本文代码使用 HAL 库。
OLED 屏幕是一种高对比度、高亮度、低功耗、灵活可弯曲的显示技术。在电子产品中,OLED 屏幕通常用于显示各种文本、图标、图像等内容。本篇文章将介绍 使用 I2C 接口 在 OLED 屏幕上显示字符,汉字。
我使用的 OLED 分辨率是 128x64。这里我使用 STM32 上的 2 个接口模拟 I2C 的功能。
模拟I2C:
通常是指在没有硬件I2C接口的情况下,使用单片机的GPIO模拟实现I2C通信协议。I2C通信协议是一种串行通信协议,通常用于连接微控制器、传感器、存储器等设备,其具有简单、高效、灵活等优点。在一些低成本的单片机上,由于没有硬件I2C接口,因此需要使用模拟I2C来实现I2C通信。
OLED 上有4个接口,分别是
OLED 屏幕的 点阵是指 OLED 屏幕上的像素数,通常用水平像素数和垂直像素数来描述。不的OLED 屏幕尺寸和型号的点阵大小不同。
点阵显示规则:(页面式列式)
OLED页面式列式 的显示规则是指 OLED点阵屏幕上的像素点是按照页面和列的方式进行排列的。通常来说,OLED点阵屏幕被分成多个页面,每个页面包含若干列像素点,每列像素点又包含若干行像素点。
在使用 OLED 点阵屏幕时,我们需要按照页面和列的方式来控制像素点的显示。通常来说,我们需要先选择要显示的页面,然后再选择要显示的列,最后通过设置像素点的亮度来点亮屏幕显示效果
。
如下图:以128x64 的OLED点阵屏幕为例,这种屏幕通常被分成了 8个页面,每个页面包含128列 像素点,每列像素点包含8行像素点。(蓝色部分是 PAGE0, 紫色的部分是 PAGE7。)
OLED 显示时,当在某一页的某列显示,如果该页的该列显示完毕,则在 该列的下一列显示。若是该页都显示完毕,则 在下一页显示。
写数据
时的设备地址 :0x78
读数据
时的设备地址 :0x79
控制字节:
1.用于表明紧跟着的下一个字节数据是命令数据还是写入GRAM 的数据;
2. Co 位表示紧跟着的数据是会仅有数据字节还是会包含控制字节,默认为0;
3. DC# 位为 1 表示紧跟着的字节数据为写入 GRAM的数据,为 0 则表示是一个 命令数据,
这一位和硬件的 DC# 引脚无关;
所以:当控制自字节为 0x00 ,表明后面写入的是 命令;当控制自字节为 0x40 ,表明后面写入的是数据。
void OLED_WriteCmd(uint8_t cmd)
{
I2C_Start(); //I2C启动
I2C_WriteByte(0x78); //发送写地址
I2C_WriteByte(0x00); //发送 控制字节
I2C_WriteByte(cmd); //发送命令
I2C_Stop(); //I2C停止
}
void OLED_WriteData(uint8_t data)
{
I2C_Start(); //I2C启动
I2C_WriteByte(0x78); //发送写地址
I2C_WriteByte(0x40); //发送 控制字节
I2C_WriteByte(data); //发送数据
I2C_Stop(); //I2C停止
}
void OLED_WriteNBytes(uint8_t *buf, uint16_t length)
{
uint16_t i = 0;
if(buf == NULL) return;
I2C_Start();
I2C_WriteByte(OLED_WRITE_ADDR);
I2C_WriteByte(0x40);
for(i=0; i<length; i++)
{
I2C_WriteByte(buf[i]);
}
I2C_Stop();
}
/* 设置 页 ,列 */
void OLED_SetPosition(int page,int col)
{
OLED_SetPageAddr_PAGE(page);
OLED_SetColAddr_PAGE(col);
}
/* 清屏 */
void OLED_Clear()
{
uint8_t buf[128] = {0}; /* 表示128列 */
for(int i=0;i<8;i++) /* 从0~7页 */
{
OLED_SetPosition(i,0);
OLED_WriteNBytes(buf,128); /* 将数据全部设为0 */
}
}
英文字符的长宽是 8x16
, 这意味着使用一页只能显示一个字符的上面一半。所以需要使用 2 页来显示一个字符
。/* 显示 a */
uint8_t buff[] = {0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x19,0x24,0x24,0x12,0x3F,0x20,0x00};/*"a",0*/
OLED_SetPosition(0,0); /*在 0页 0 列显示*/
OLED_WriteNBytes((uint8_t*)&buff[0], 8); /* 显示上半部分 */
OLED_SetPosition (1,0); /* 页加 1 */
OLED_WriteNBytes((uint8_t*)&buff[8], 8); /* 显示下半部分 */
显示字符,字符串的 原理都一样,只不过显示字符串要 逐个显示每个字符,大家可以自己试试。