这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【Let'sdo第1期-DIY功率检测与控制系统】2、过程贴:驱动OLED屏

共3条 1/1 1 跳转至

【Let'sdo第1期-DIY功率检测与控制系统】2、过程贴:驱动OLED屏

工程师
2025-05-20 20:56:02     打赏

《Let'sdo第1期-DIY功率检测与控制系统》

目标:实现驱动OLED屏

1、连线图

1.png

2、I2C配置

2.png

static void MX_I2C1_Init(void)
{

  /* USER CODE BEGIN I2C1_Init 0 */

  /* USER CODE END I2C1_Init 0 */

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 400000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN I2C1_Init 2 */

  /* USER CODE END I2C1_Init 2 */

}

3.png

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hi2c->Instance==I2C1)
  {
    /* USER CODE BEGIN I2C1_MspInit 0 */

    /* USER CODE END I2C1_MspInit 0 */

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**I2C1 GPIO Configuration
    PB8     ------> I2C1_SCL
    PB9     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* Peripheral clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
    /* I2C1 interrupt Init */
    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
    HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
    /* USER CODE BEGIN I2C1_MspInit 1 */

    /* USER CODE END I2C1_MspInit 1 */

  }

}


3、OLED驱动

// 发送命令


void OLED_WriteCommand(uint8_t cmd) {
    uint8_t buf[2] = {0x00, cmd};
    HAL_I2C_Master_Transmit(hi2c_oled, OLED_I2C_ADDRESS, buf, 2, 10);
}

// 发送数据


void OLED_WriteData(uint8_t data) {
    uint8_t buf[2] = {0x40, data};
    HAL_I2C_Master_Transmit(hi2c_oled, OLED_I2C_ADDRESS, buf, 2, 10);
}

和本次活动提供的代码的接口:


void OLED_WR_Byte(uint8_t dat,uint8_t mode)
{
if(mode==0){
OLED_WriteCommand(dat);
}
else
{
OLED_WriteData(dat);
}
}

// 初始化OLED


void OLED_Init(I2C_HandleTypeDef *hi2c) {
    hi2c_oled = hi2c;
    
    HAL_Delay(100);
    OLED_WriteCommand(0xAE); // 关闭显示
    
    OLED_WriteCommand(0xD5); // 设置显示时钟分频比/振荡器频率
    OLED_WriteCommand(0x80);
    
    OLED_WriteCommand(0xA8); // 设置多路复用率
    OLED_WriteCommand(0x3F);
    
    OLED_WriteCommand(0xD3); // 设置显示偏移
    OLED_WriteCommand(0x00);
    
    OLED_WriteCommand(0x40); // 设置显示开始行
    
    OLED_WriteCommand(0x8D); // 电荷泵设置
    OLED_WriteCommand(0x14);
    
    OLED_WriteCommand(0x20); // 设置内存地址模式
    OLED_WriteCommand(0x00); // 水平地址模式
    
    OLED_WriteCommand(0xA1); // 段重映射
    OLED_WriteCommand(0xC8); // 输出扫描方向
    
    OLED_WriteCommand(0xDA); // 设置COM引脚硬件配置
    OLED_WriteCommand(0x12);
    
    OLED_WriteCommand(0x81); // 设置对比度控制
    OLED_WriteCommand(0xCF);
    
    OLED_WriteCommand(0xD9); // 设置预充电周期
    OLED_WriteCommand(0xF1);
    
    OLED_WriteCommand(0xDB); // 设置VCOMH取消选择级别
    OLED_WriteCommand(0x40);
    
    OLED_WriteCommand(0xA4); // 设置整个显示开启/关闭
    OLED_WriteCommand(0xA6); // 设置正常/反向显示
    
    OLED_WriteCommand(0xAF); // 开启显示
    
    OLED_Clear();
    OLED_SetCursor(0, 0);
}

显示单个ascii字符

//inv:是否反显


void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t size1,uint8_t inv)
{
uint8_t i,m,temp,size2,chr1;
uint8_t y0=y;
size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
chr1=chr-' ';  //计算偏移后的值
for(i=0;i<size2;i++)
{
if(size1==12)
        {temp=asc2_1206[chr1][i];} //调用1206字体
else if(size1==16)
        {temp=asc2_1608[chr1][i];} //调用1608字体
else if(size1==24)
        {temp=asc2_2412[chr1][i];} //调用2412字体
else return;
for(m=0;m<8;m++)           //写入数据
{
if(temp&0x80){if(inv)OLED_DrawPoint(x,y);else OLED_ClearPoint(x,y);}
else {if(inv) OLED_ClearPoint(x,y);else OLED_DrawPoint(x,y);}
temp<<=1;
y++;
if((y-y0)==size1)
{
y=y0;
x++;
break;
          }
}
  }
}

显示ascii字符串

//inv:是否反显


void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t size1,uint8_t inv)
{
while((*chr>=' ')&&(*chr<='~'))//判断是不是非法字符!
{
OLED_ShowChar(x,y,*chr,size1,inv);
x+=size1/2;
if(x>128-size1)  //换行
{
x=0;
y+=2;
    }
chr++;
  }
}

动画效果:屏幕整体左移:


void OLED_ScrollDisplay(uint8_t step)
{
uint8_t i,n;
for(i=step;i<144;i++)   //实现左移
{
for(n=0;n<8;n++)
{
OLED_GRAM[i-step][n]=OLED_GRAM[i][n];
}
}
OLED_Refresh();
HAL_Delay(50);
}

显示汉字字符串:

//显示汉字

//x,y:起点坐标

//num:汉字对应的序号

//取模方式 列行式

void OLED_ShowChineseString16(uint8_t x,uint8_t y,unsigned char *cn,uint8_t inv)
{
uint8_t i,m,n=0,temp,num;
uint8_t x0=x,y0=y;
while (*cn != '\0')
{
for (i=0; i<(sizeof(Hzk1) / sizeof(Hzk1[0])); i++)
{
if((Hzk1[i].Index[0]==*cn)&&(Hzk1[i].Index[1]==*(cn+1)))
{
num=i;
break;
}
}
for(i=0;i<32;i++)
{
temp=Hzk1[num].Msk[i];
for(m=0;m<8;m++)
{
if(temp&0x01){if(inv) OLED_DrawPoint(x,y); else OLED_ClearPoint(x,y);}
else {if(inv) OLED_ClearPoint(x,y); else OLED_DrawPoint(x,y);}
temp>>=1;
y++;
}
if(i==15){x=x0;}else {x++;}
if(i>15){y=y0+8;}else {y=y0;}
 }
cn+=2;//下一个汉字偏移
y=y0;//纵坐标恢复初始值
x0+=16;//横坐标初始值加16
x=x0;//横坐标=初始值
}
}

其中Hzk1修改为:

struct Cn16CharTypeDef                   // 汉字字模数据结构
{
	unsigned char  Index[2];            // 汉字内码索引,一个汉字占两个字节	
	unsigned char   Msk[32];            // 点阵码数据(32*29/8) 
};

const struct Cn16CharTypeDef Hzk1[]={

"功",{0x08,0x08,0x08,0xF8,0x08,0x08,0x08,0x10,0x10,0xFF,0x10,0x10,0x10,0xF0,0x00,0x00,
0x10,0x30,0x10,0x1F,0x08,0x88,0x48,0x30,0x0E,0x01,0x40,0x80,0x40,0x3F,0x00,0x00},/*"功",0*/

"率",{0x00,0x14,0xA4,0x44,0x24,0x34,0xAD,0x66,0x24,0x94,0x04,0x44,0xA4,0x14,0x00,0x00,
0x08,0x09,0x08,0x08,0x09,0x09,0x09,0xFD,0x09,0x09,0x0B,0x08,0x08,0x09,0x08,0x00},/*"率",1*/

"监",{0x00,0x00,0x7E,0x00,0x00,0xFF,0x00,0x40,0x30,0x0F,0x04,0x14,0x64,0x04,0x00,0x00,
0x40,0x40,0x7E,0x42,0x42,0x7E,0x42,0x42,0x42,0x7E,0x42,0x42,0x7E,0x40,0x40,0x00},/*"监",2*/

"测",{0x10,0x60,0x02,0x8C,0x00,0xFE,0x02,0xF2,0x02,0xFE,0x00,0xF8,0x00,0xFF,0x00,0x00,
0x04,0x04,0x7E,0x01,0x80,0x47,0x30,0x0F,0x10,0x27,0x00,0x47,0x80,0x7F,0x00,0x00},/*"测",3*/

"与",{0x00,0x00,0xE0,0x9F,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x08,0x00,0x00,
0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x48,0x80,0x40,0x3F,0x00,0x00,0x00},/*"与",4*/

"控",{0x10,0x10,0x10,0xFF,0x90,0x20,0x98,0x48,0x28,0x09,0x0E,0x28,0x48,0xA8,0x18,0x00,
0x02,0x42,0x81,0x7F,0x00,0x40,0x40,0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x40,0x00},/*"控",5*/

"制",{0x40,0x50,0x4E,0x48,0x48,0xFF,0x48,0x48,0x48,0x40,0xF8,0x00,0x00,0xFF,0x00,0x00,
0x00,0x00,0x3E,0x02,0x02,0xFF,0x12,0x22,0x1E,0x00,0x0F,0x40,0x80,0x7F,0x00,0x00},/*"制",6*/

"电",{0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00,
0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00},/*"电",7*/
"流",{0x10,0x60,0x02,0x8C,0x00,0x44,0x64,0x54,0x4D,0x46,0x44,0x54,0x64,0xC4,0x04,0x00,
0x04,0x04,0x7E,0x01,0x80,0x40,0x3E,0x00,0x00,0xFE,0x00,0x00,0x7E,0x80,0xE0,0x00},/*"流",8*/

"压",{0x00,0x00,0xFE,0x02,0x82,0x82,0x82,0x82,0xFA,0x82,0x82,0x82,0x82,0x82,0x02,0x00,
0x80,0x60,0x1F,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x44,0x58,0x40,0x40,0x00},/*"压",10*/

"阈",{0x00,0xF8,0x01,0x22,0xA0,0xA2,0xA2,0x22,0xFE,0x22,0xAA,0x32,0x02,0xFE,0x00,0x00,
0x00,0xFF,0x00,0x10,0x13,0x0A,0x4B,0x20,0x17,0x0C,0x13,0x38,0x80,0xFF,0x00,0x00},/*"阈",13*/

"值",{0x00,0x80,0x60,0xF8,0x07,0x04,0xE4,0xA4,0xA4,0xBF,0xA4,0xA4,0xE4,0x04,0x00,0x00,
0x01,0x00,0x00,0xFF,0x40,0x40,0x7F,0x4A,0x4A,0x4A,0x4A,0x4A,0x7F,0x40,0x40,0x00},/*"值",14*/

"过",{0x40,0x40,0x42,0xCC,0x00,0x08,0x48,0x88,0x08,0x08,0x08,0xFF,0x08,0x08,0x08,0x00,
0x00,0x40,0x20,0x1F,0x20,0x40,0x40,0x41,0x40,0x48,0x50,0x4F,0x40,0x40,0x40,0x00},/*"过",15*/

"状",{0x00,0x08,0x30,0x00,0xFF,0x20,0x20,0x20,0x20,0xFF,0x20,0x20,0x22,0x2C,0x20,0x00,
0x04,0x04,0x02,0x01,0xFF,0x80,0x40,0x30,0x0E,0x01,0x06,0x18,0x20,0x40,0x80,0x00},/*"状",17*/

"态",{0x00,0x04,0x84,0x84,0x44,0x24,0x54,0x8F,0x14,0x24,0x44,0x84,0x84,0x04,0x00,0x00,
0x41,0x39,0x00,0x00,0x3C,0x40,0x40,0x42,0x4C,0x40,0x40,0x70,0x04,0x09,0x31,0x00},/*"态",18*/

"正",{0x00,0x02,0x02,0xC2,0x02,0x02,0x02,0xFE,0x82,0x82,0x82,0x82,0x82,0x02,0x00,0x00,
0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00},/*"正",19*/

"常",{0x20,0x18,0x08,0xEA,0xAC,0xA8,0xA8,0xAF,0xA8,0xA8,0xAC,0xEA,0x08,0x28,0x18,0x00,
0x00,0x00,0x3E,0x02,0x02,0x02,0x02,0xFF,0x02,0x02,0x12,0x22,0x1E,0x00,0x00,0x00},/*"常",20*/

"异",{0x00,0x00,0x7E,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x9E,0x80,0xE0,0x00,0x00,
0x08,0x88,0x48,0x28,0x1E,0x08,0x08,0x08,0x08,0x08,0xFE,0x08,0x08,0x08,0x08,0x00},/*"异",21*/

"得",{0x00,0x10,0x88,0xC4,0x33,0x00,0xBE,0xAA,0xAA,0xAA,0xAA,0xAA,0xBE,0x80,0x00,0x00,
0x02,0x01,0x00,0xFF,0x00,0x02,0x0A,0x12,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x00},/*"得",23*/

"捷",{0x10,0x10,0xFF,0x10,0x90,0x44,0x54,0x54,0x54,0xFF,0x54,0x54,0xF4,0x44,0x44,0x00,
0x42,0x82,0x7F,0x01,0x80,0x60,0x1D,0x21,0x41,0x7F,0x49,0x49,0x49,0x48,0x40,0x00},/*"捷",24*/

"子",{0x80,0x82,0x82,0x82,0x82,0x82,0x82,0xE2,0xA2,0x92,0x8A,0x86,0x82,0x80,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"子",26*/

};

画图像:

//配置写入数据的起始位置
void OLED_WR_BP(uint8_t x,uint8_t y)
{
	OLED_WR_Byte(0xb0+y,OLED_CMD);//设置行起始地址
	OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
	OLED_WR_Byte((x&0x0f),OLED_CMD);
}
//x0,y0:起点坐标
//x1,y1:终点坐标
//BMP[]:要写入的图片数组
void OLED_ShowPicture(uint8_t x0,uint8_t y0,uint8_t x1,uint8_t y1,uint8_t BMP[])
{
	uint32_t j=0;
	uint8_t x=0,y=0;
	if(y%8==0)y=0;
	else y+=1;
	for(y=y0/8;y<y1/8;y++)
	 {
		 OLED_WR_BP(x0,y);
		 for(x=x0;x<x1;x++)
		 {
			 OLED_WR_Byte(BMP[j],OLED_DATA);
			 j++;
     }
	 }
}

复制bmp到OLED_GRAM缓存:

void OLED_Copy_Bmp(uint8_t x0,uint8_t y0,uint8_t width,uint8_t height,const uint8_t BMP[],uint8_t bmp_x0,uint8_t bmp_y0)
{
uint8_t i,j;
for (i=0;i<height/8;i++)
for (j=0;j<width;j++)
{
OLED_GRAM[j+x0][i+y0/8]=BMP[i*128+j+bmp_x0+bmp_y0/8*128];
}
}

main.c

	OLED_Clear();
	OLED_Copy_Bmp(0,0,128,16,bmp1,0,0);
	OLED_Refresh();
	HAL_Delay(500);
	OLED_Copy_Bmp(0,16,128,16,bmp1,0,16);
	OLED_Refresh();
	HAL_Delay(500);
	OLED_Copy_Bmp(0,32,128,16,bmp1,0,32);
	OLED_Refresh();
	HAL_Delay(500);
	OLED_Copy_Bmp(0,48,128,16,bmp1,0,48);
	OLED_Refresh();
	HAL_Delay(500);
        while (1)
        {
	
		if(count<128/4)
		{
			OLED_ScrollDisplay(4);
			count++;
		}else
		{
		
			OLED_ShowChineseString16(0,0,"电流电压阈值",(count)%4);
			OLED_ShowString(0,16,"I2C OLED Demo",16,(count+3)%4);
			
			OLED_ShowChineseString16(0,32,"得捷电子",(count+2)%4);
			OLED_ShowChineseString16(0,48,"功率监测与控制",(count+1)%4);
			OLED_Refresh();
			
			HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
			HAL_Delay(1000);
			count++;
		}
	}

tutieshi_480x270_12s.gif





关键词: Let'sdo第1期-DIY功率检测与控制系统    

专家
2025-05-21 10:38:57     打赏
2楼

谢谢楼主分享


菜鸟
2025-05-23 19:39:22     打赏
3楼

这些代码加在哪里啊老哥,看不懂了


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]