《Let'sdo第1期-DIY功率检测与控制系统》
目标:实现驱动OLED屏
1、连线图

2、I2C配置

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 */
}
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++;
}
}
我要赚赏金
