STM32 HAL库驱动0.96寸OLED屏幕
STM32 HAL库驱动0.96寸OLED屏幕
项目概述
本项目使用STM32 HAL库为0.96寸OLED屏幕编写驱动程序。OLED屏幕通过I2C接口与STM32单片机通信,实现文本、数字和图形的显示功能。
项目仓库地址:STM32_Sensor_Drives
硬件连接
OLED屏幕通过I2C接口与STM32连接:
- SCL连接到PB8
- SDA连接到PB9
关键代码
1. I2C初始化
void MX_I2C1_Init(void){ hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; 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(); }}
2. I2C引脚配置
void HAL_I2C_MspInit(I2C_HandleTypeDef *i2cHandle){ GPIO_InitTypeDef GPIO_InitStruct = {0}; if (i2cHandle->Instance == I2C1) { __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.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); __HAL_AFIO_REMAP_I2C1_ENABLE(); /* I2C1 clock enable */ __HAL_RCC_I2C1_CLK_ENABLE(); }}
3. OLED基本通信函数
// 向OLED发送命令void Write_IIC_Command(uint8_t cmd){ HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x00, I2C_MEMADD_SIZE_8BIT, &cmd, 1, 100);}// 向OLED发送数据void Write_IIC_Data(uint8_t data){ HAL_I2C_Mem_Write(&hi2c1, 0x78, 0x40, I2C_MEMADD_SIZE_8BIT, &data, 1, 100);}
4. OLED显示控制函数
// 设置显示坐标void OLED_Set_Pos(unsigned char x, unsigned char y){ Write_IIC_Command(0xb0 + y); Write_IIC_Command(((x & 0xf0) >> 4) | 0x10); Write_IIC_Command((x & 0x0f));}// 开启OLED显示void OLED_Display_On(void){ Write_IIC_Command(0X8D); // SET DCDC命令 Write_IIC_Command(0X14); // DCDC ON Write_IIC_Command(0XAF); // DISPLAY ON}// 关闭OLED显示void OLED_Display_Off(void){ Write_IIC_Command(0X8D); // SET DCDC命令 Write_IIC_Command(0X10); // DCDC OFF Write_IIC_Command(0XAE); // DISPLAY OFF}// 清屏函数void OLED_Clear(void){ uint8_t i, n; for (i = 0; i < 8; i++) { Write_IIC_Command(0xb0 + i); // 设置页地址(0~7) Write_IIC_Command(0x00); // 设置显示位置—列低地址 Write_IIC_Command(0x10); // 设置显示位置—列高地址 for (n = 0; n < 128; n++) Write_IIC_Data(0); }}// 全屏点亮void OLED_On(void){ uint8_t i, n; for (i = 0; i < 8; i++) { Write_IIC_Command(0xb0 + i); // 设置页地址(0~7) Write_IIC_Command(0x00); // 设置显示位置—列低地址 Write_IIC_Command(0x10); // 设置显示位置—列高地址 for (n = 0; n < 128; n++) Write_IIC_Data(1); }}
5. 字符显示函数
// 在指定位置显示一个字符void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t Char_Size){ unsigned char c = 0, i = 0; c = chr - \' \'; // 得到偏移后的值 if (x > Max_Column - 1) { x = 0; y = y + 2; } if (Char_Size == 16) { OLED_Set_Pos(x, y); for (i = 0; i < 8; i++) Write_IIC_Data(F8X16[c * 16 + i]); OLED_Set_Pos(x, y + 1); for (i = 0; i < 8; i++) Write_IIC_Data(F8X16[c * 16 + i + 8]); } else { OLED_Set_Pos(x, y); for (i = 0; i < 6; i++) Write_IIC_Data(F6x8[c][i]); }}// 显示字符串void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t Char_Size){ unsigned char j = 0; while (chr[j] != \'\\0\') { OLED_ShowChar(x, y, chr[j], Char_Size); x += 8; j++; }}// 显示数字void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size2){ uint8_t t, temp; uint8_t enshow = 0; for (t = 0; t < len; t++) { temp = (num / oled_pow(10, len - t - 1)) % 10; if (enshow == 0 && t < (len - 1)) { if (temp == 0) { OLED_ShowChar(x + (size2 / 2) * t, y, \' \', size2); continue; } else enshow = 1; } OLED_ShowChar(x + (size2 / 2) * t, y, temp + \'0\', size2); }}// m^n函数uint32_t oled_pow(uint8_t m, uint8_t n){ uint32_t result = 1; while (n--) result *= m; return result;}
6. 中文显示和图片显示
// 显示中文void OLED_ShowCHinese(uint8_t x, uint8_t y, uint8_t no){ uint8_t t, adder = 0; OLED_Set_Pos(x, y); for (t = 0; t < 16; t++) { Write_IIC_Data(Hzk[no][t]); adder += 1; } OLED_Set_Pos(x, y + 1); for (t = 0; t < 16; t++) { Write_IIC_Data(Hzk[no][t + 16]); adder += 1; }}// 显示BMP图片void OLED_DrawBMP(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char BMP[]){ unsigned int j = 0; unsigned char x, y; if (y1 % 8 == 0) y = y1 / 8; else y = y1 / 8 + 1; for (y = y0; y < y1; y++) { OLED_Set_Pos(x0, y); for (x = x0; x < x1; x++) { Write_IIC_Data(BMP[j++]); } }}
7. OLED初始化函数
void OLED_start(void){ Write_IIC_Command(0xAE); // 关闭显示 Write_IIC_Command(0xD5); // 设置时钟分频因子,震荡频率 Write_IIC_Command(0x80); // [3:0],分频因子;[7:4],震荡频率 Write_IIC_Command(0xA8); // 设置驱动路数 Write_IIC_Command(0x3F); // 默认0X3F(1/64) Write_IIC_Command(0xD3); // 设置显示偏移 Write_IIC_Command(0x00); // 默认为0 Write_IIC_Command(0x40); // 设置显示开始行 [5:0],行数. Write_IIC_Command(0x8D); // 电荷泵设置 Write_IIC_Command(0x14); // bit2,开启/关闭 Write_IIC_Command(0x20); // 设置内存地址模式 Write_IIC_Command(0x02); // [1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; Write_IIC_Command(0xA1); // 段重定义设置,bit0:0,0->0;1,0->127; Write_IIC_Command(0xC8); // 设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 Write_IIC_Command(0xDA); // 设置COM硬件引脚配置 Write_IIC_Command(0x12); // [5:4]配置 Write_IIC_Command(0x81); // 对比度设置 Write_IIC_Command(0xEF); // 1~255;默认0X7F (亮度设置,越大越亮) Write_IIC_Command(0xD9); // 设置预充电周期 Write_IIC_Command(0xf1); // [3:0],PHASE 1;[7:4],PHASE 2; Write_IIC_Command(0xDB); // 设置VCOMH 电压倍率 Write_IIC_Command(0x30); // [6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc; Write_IIC_Command(0xA4); // 全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) Write_IIC_Command(0xA6); // 设置显示方式;bit0:1,反相显示;0,正常显示 Write_IIC_Command(0xAF); // 开启显示 OLED_Clear();}
8. 主函数中的使用示例
int main(void){ /* 省略初始化代码 */ /* 初始化外设 */ MX_GPIO_Init(); MX_USART2_UART_Init(); MX_I2C1_Init(); /* 初始化OLED */ OLED_start(); /* 无限循环 */ printf(\"System will start while\\n\"); OLED_Clear(); OLED_ShowString(0, 0, (uint8_t*)\"Init success\", 16); OLED_ShowString(0, 2, (uint8_t*)\"Init success\", 12); while (1) { HAL_Delay(200); }}
字体数据
项目中包含了两种字体数据:
- 6x8点阵字体(F6x8):适用于小字体显示
- 8x16点阵字体(F8X16):适用于大字体显示
- 中文字库(Hzk):用于显示中文字符
注意事项
- OLED的I2C地址为0x78(写操作)
- 显示区域为128x64像素
- 使用前需要先调用OLED_start()初始化OLED
- 清屏函数OLED_Clear()可以清除屏幕上的所有内容
常用函数总结
参考资料
- STM32 HAL库文档
- 0.96寸OLED屏幕数据手册
- 项目仓库