✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
一、OLED 显示屏概述
OLED(Organic Light - Emitting Diode)即有机发光二极管,0.96 寸的 OLED 显示屏具有体积小、功耗低、视角广、响应速度快等优点,在很多嵌入式系统中被广泛应用。当它与 STM32 微控制器通过 IIC(Inter - Integrated Circuit)协议进行通信时,能够实现简洁高效的显示功能。
二、IIC 协议基础
2.1 IIC 协议简介
IIC 是一种串行通信协议,由飞利浦公司开发。它使用两根线进行通信:SCL(时钟线)和 SDA(数据线)。IIC 总线上可以挂载多个设备,每个设备都有唯一的地址。在 STM32 与 0.96 寸 OLED 显示屏通信时,STM32 作为主设备,OLED 显示屏作为从设备。
2.2 IIC 通信流程
- 起始信号:主设备在 SCL 为高电平时,将 SDA 从高电平拉低,表示开始一次通信。
- 设备地址:主设备发送从设备的 7 位地址和 1 位读写位(0 表示写,1 表示读)。
- 应答信号:从设备在接收到地址后,如果地址匹配,会在第 9 个时钟周期将 SDA 拉低,表示应答。
- 数据传输:主设备和从设备之间进行数据传输,每个字节传输后都需要一个应答信号。
- 停止信号:主设备在 SCL 为高电平时,将 SDA 从低电平拉高,表示通信结束。
三、0.96 寸 OLED 显示屏硬件连接
3.1 引脚说明
0.96 寸 IIC 接口的 OLED 显示屏通常有 4 个引脚:
- VCC:电源正极,一般接 3.3V 或 5V。
- GND:电源负极,接地。
- SCL:IIC 时钟线,连接到 STM32 的 IIC 时钟引脚。
- SDA:IIC 数据线,连接到 STM32 的 IIC 数据引脚。
3.2 硬件连接示例
以 STM32F103C8T6 为例,假设使用 I2C1 接口,将 OLED 的 SCL 连接到 PB6,SDA 连接到 PB7,VCC 接 3.3V,GND 接地。
四、STM32 配置 IIC 接口
4.1 初始化 IIC 接口
以下是使用 STM32 HAL 库初始化 I2C1 接口的代码示例:
#include "stm32f1xx_hal.h"
I2C_HandleTypeDef hi2c1;
void MX_I2C1_Init(void)
{
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();
}
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(i2cHandle->Instance==I2C1)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_I2C1_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
}
4.2 向 OLED 发送数据
以下是向 OLED 发送一个字节数据的函数:
#define OLED_ADDR 0x78 // OLED 设备地址
void OLED_Write_Byte(uint8_t dat, uint8_t cmd)
{
uint8_t send_data[2];
send_data[0] = (cmd == 0)? 0x00 : 0x40;
send_data[1] = dat;
HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, send_data, 2, 100);
}
4.3 OLED 初始化
void OLED_Init(void)
{
HAL_Delay(100);
OLED_Write_Byte(0xAE, OLED_CMD); // 关闭显示
OLED_Write_Byte(0xD5, OLED_CMD); // 设置时钟分频因子
OLED_Write_Byte(0x80, OLED_CMD);
OLED_Write_Byte(0xA8, OLED_CMD); // 设置驱动路数
OLED_Write_Byte(0x3F, OLED_CMD);
OLED_Write_Byte(0xD3, OLED_CMD); // 设置显示偏移
OLED_Write_Byte(0x00, OLED_CMD);
OLED_Write_Byte(0x40, OLED_CMD); // 设置显示开始行
OLED_Write_Byte(0x8D, OLED_CMD); // 电荷泵设置
OLED_Write_Byte(0x14, OLED_CMD);
OLED_Write_Byte(0x20, OLED_CMD); // 设置内存地址模式
OLED_Write_Byte(0x02, OLED_CMD);
OLED_Write_Byte(0xA1, OLED_CMD); // 设置段重定义
OLED_Write_Byte(0xC8, OLED_CMD); // 设置 COM 扫描方向
OLED_Write_Byte(0xDA, OLED_CMD); // 设置 COM 硬件引脚配置
OLED_Write_Byte(0x12, OLED_CMD);
OLED_Write_Byte(0x81, OLED_CMD); // 对比度设置
OLED_Write_Byte(0xCF, OLED_CMD);
OLED_Write_Byte(0xD9, OLED_CMD); // 设置预充电周期
OLED_Write_Byte(0xF1, OLED_CMD);
OLED_Write_Byte(0xDB, OLED_CMD); // 设置 VCOMH 电压倍率
OLED_Write_Byte(0x40, OLED_CMD);
OLED_Write_Byte(0xA4, OLED_CMD); // 全局显示开启
OLED_Write_Byte(0xA6, OLED_CMD); // 正常显示
OLED_Write_Byte(0xAF, OLED_CMD); // 开启显示
}
五、在 OLED 上显示字符和图形
5.1 显示字符
以下是在 OLED 上显示一个字符的函数:
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size)
{
uint8_t c = 0, i = 0;
c = chr - ' ';
if (x > 128 - size / 2)
{
x = 0;
y = y + 2;
}
if (size == 16)
{
for (i = 0; i < 8; i++)
{
OLED_Set_Pos(x, y);
OLED_Write_Byte(F8X16[c * 16 + i], OLED_DATA);
OLED_Set_Pos(x, y + 1);
OLED_Write_Byte(F8X16[c * 16 + i + 8], OLED_DATA);
x++;
}
}
}
5.2 显示字符串
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t size)
{
unsigned char j = 0;
while (chr[j] != '\0')
{
OLED_ShowChar(x, y, chr[j], size);
x += size / 2;
if (x > 128 - size / 2)
{
x = 0;
y += 2;
}
j++;
}
}
5.3 显示图形
要显示图形,需要将图形数据存储在数组中,然后逐字节写入 OLED。以下是一个简单的示例:
const uint8_t gImage_logo[] = {
// 图形数据
};
void OLED_ShowPicture(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t BMP[])
{
unsigned int j = 0;
uint8_t 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++)
{
OLED_Write_Byte(BMP[j++], OLED_DATA);
}
}
}
六、主函数调用示例
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
OLED_Init();
OLED_ShowString(0, 0, "Hello, World!", 16);
while (1)
{
// 主循环
}
}
七、总结
通过以上步骤,我们可以实现 STM32 与 0.96 寸 IIC 接口 OLED 显示屏的通信,并在上面显示字符和图形。在实际应用中,可以根据需求进一步扩展功能,如显示动态图形、实现菜单界面等。同时,要注意 IIC 通信的稳定性和数据传输的准确性,确保显示效果的质量。