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 ConfigurationPB8 ------> I2C1_SCLPB9 ------> 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 ONWrite_IIC_Command(0XAF); // DISPLAY ON
}// 關閉OLED顯示
void OLED_Display_Off(void)
{Write_IIC_Command(0X8D); // SET DCDC命令Write_IIC_Command(0X10); // DCDC OFFWrite_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;}elseenshow = 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;elsey = 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); // 默認為0Write_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()可以清除屏幕上的所有內容
常用函數總結
函數名 | 功能描述 |
---|---|
OLED_start() | 初始化OLED |
OLED_Clear() | 清屏 |
OLED_Display_On() | 開啟顯示 |
OLED_Display_Off() | 關閉顯示 |
OLED_ShowChar() | 顯示單個字符 |
OLED_ShowString() | 顯示字符串 |
OLED_ShowNum() | 顯示數字 |
OLED_ShowCHinese() | 顯示中文 |
OLED_DrawBMP() | 顯示BMP圖片 |
參考資料
- STM32 HAL庫文檔
- 0.96寸OLED屏幕數據手冊
- 項目倉庫