一、I2C程序层次

1.1 设备间的通信方式

  • UART(异步 全双工)& 1.1.2 I2C(同步 半双工)
UART串口 I2C 协议
在这里插入图片描述 在这里插入图片描述

1.2 硬件原理图

// OLED实物图 教程见
https://blog.csdn.net/Super_Fisher_man/article/details/135613284?spm=1001.2014.3001.5501
OLED实物图 OLED原理图
在这里插入图片描述 在这里插入图片描述

1.3 硬件框图和软件层次

硬件框图
在这里插入图片描述
软件层次
在这里插入图片描述


二、I2C 协议

2.1 硬件连接(一主多从)

I2C在硬件上的接发
在这里插入图片描述

2.2 数据传输 类比

I2C 数据传输类比图
在这里插入图片描述

2.3 IIC 传输数据的格式

IIC 传输数据的格式
在这里插入图片描述
  • IIC 像快递系统,只负责把包裹送到指定设备;包裹里面装的是什么、怎么解释,由具体芯片的数据手册决定。

  • 拿OLED为例:S + Dev + w + 显存地址 + data0 + data1 ...

    2.4 IIC 总线的信号类型

I2C 总线的信号类型
在这里插入图片描述
芯片手册上的图
在这里插入图片描述
  • IIC 总线的 SDA 和 SCL 通常采用开漏输出结构(Open-Drain)。设备只能主动拉低总线,不能主动输出高电平;当需要输出高电平时,设备释放总线,由上拉电阻将信号线拉高。这样可以避免多个设备同时驱动总线时产生电平冲突。详情: 【STM32】HAL库的本质 及 芯片内部GPIO模块细节
输出 0 (驱动) 输出 1 (释放)
GPIO 主动拉低 SDA/SCL GPIO 变成高阻态,由上拉电阻拉高(由外部电路决定)
  • 主从设备,任意一方 觉得要等一等,表示我这边还没准备好,都可以把 SCL (时钟)拉低;任意一方拉低,结果都是 0;

三、IIC HAL 编程

IIC_读写
在这里插入图片描述

3.1 STM32CubeMX 配置

  • I2C1 ==> Parameter Settings ==> GPIO Settings

3.2 查询方式

3.2.1 Master 模式函数
// Master 模式函数
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
uint8_t *pData, uint16_t Size, uint32_t Timeout);

参数 说明
I2C_HandleTypeDef *hi2c 使用哪个 I2C 控制器
uint16_t DevAddress 设备地址,需要把 7 位地址左移 1 位
uint8_t *pData 数据 buffer
uint16_t Size 数据个数
uint32_t Timeout 超时时间,单位是 Tick,一般是 1ms
返回值 HAL_OK:成功HAL_ERROR:错误HAL_BUSY:总线忙HAL_TIMEOUT:超时
3.2.2 MEM 模式函数
// MEM 模式函数 
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t
MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t
MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
参数 说明
I2C_HandleTypeDef *hi2c 使用哪个 I2C 控制器
uint16_t DevAddress 设备地址,需要把 7 位地址左移 1 位
uint16_t MemAddress 存储地址, 即 I2C 设备上的寄存器地址或存储地址
uint16_t MemAddSize 存储地址的大小,有 2 种取值: I2C_MEMADD_SIZE_8BIT:存储地址为 1 字节,就是 MemAddress 的低字节I2C_MEMADD_SIZE_16BIT:存储地址为 2 字节,先发送 MemAddress 的高字节,再发送低字节
uint8_t *pData 数据 buffer
uint16_t Size 数据个数
uint32_t Timeout 超时时间,单位是 Tick,一般是 1ms
返回值 HAL_OK:成功HAL_ERROR:错误HAL_BUSY:总线忙HAL_TIMEOUT:超时

3.3 中断方式

3.3.1 Master 模式函数
// Master 模式函数
HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
uint8_t *pData, uint16_t Size);

/* 主设备发送完成回调函数 */
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c);
/* 主设备接收完成回调函数 */
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c);
/* 出错回调函数 */
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
参数 说明
I2C_HandleTypeDef *hi2c 使用哪个 I2C 控制器
uint16_t DevAddress 设备地址,需要把 7 位地址左移 1 位
uint8_t *pData 数据 buffer
uint16_t Size 数据个数
返回值 HAL_OK:成功HAL_BUSY:总线忙
3.3.2 MEM 模式函数
// MEM 模式函数
HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,
uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t
MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);

/* MEM模式发送完成回调函数 */
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c);
/* MEM模式接收完成回调函数 */
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c);
/* 出错回调函数 */
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
参数 说明
I2C_HandleTypeDef *hi2c 使用哪个 I2C 控制器
uint16_t DevAddress 设备地址,需要把 7 位地址左移 1 位
uint16_t MemAddress 存储地址, 即 I2C 设备上的寄存器地址或存储地址
uint16_t MemAddSize 存储地址的大小,有 2 种取值: I2C_MEMADD_SIZE_8BIT:存储地址为 1 字节,就是 MemAddress 的低字节I2C_MEMADD_SIZE_16BIT:存储地址为 2 字节,先发送 MemAddress 的高字节,再发送低字节
uint8_t *pData 数据 buffer
uint16_t Size 数据个数
返回值 HAL_OK:成功HAL_BUSY:总线忙
3.3.3 DMA 模式
  • 将中断模式中的IT改为DMA 即可;

四、OLED 操作原理

4.1 SOC控制OLED原理框架

SOC控制OLED原理框架
在这里插入图片描述
4.1.1 如何分辨 cmd /data?
分辨 cmd / data
在这里插入图片描述
4.1.2 显存和像素的关系
像素点_显存(GDDRAM)大小 显存和像素的关系
在这里插入图片描述 在这里插入图片描述
  • 写显存: ① 设置 Page n (n=0~7) ② 设置 列 m (m= 0~127) ③ 写入 1 byte 的数据

  • 一定要一个个设置吗?

4.2 自动设置行列 ==> 地址模式

页地址模式
在这里插入图片描述
行地址 模式
在这里插入图片描述
列地址模式
在这里插入图片描述

五、在OLED上显示汉字

5.1 取模软件使用

//软件地址
通过网盘分享的文件:PCtoLCD2002.zip
链接: https://pan.baidu.com/s/1eORhBJW78vXzYZH6XJcWew?pwd=wjyf 提取码: wjyf
取模软件_PCtoLCD2022完美版
在这里插入图片描述
(0)(1)  // 16*16 + 16*16

{0x20,0x20,0x20,0xFF,0x20,0x20,0x00,0xF8,0x88,0x88,0xFF,0x88,0x88,0xF8,0x00,0x00},
{0x10,0x30,0x10,0x0F,0x08,0x08,0x00,0x1F,0x08,0x08,0xFF,0x08,0x08,0x1F,0x00,0x00},/*"坤",0*/

{0x20,0x20,0x20,0xFF,0x20,0x20,0x00,0xF8,0x88,0x88,0xFF,0x88,0x88,0xF8,0x00,0x00},
{0x10,0x30,0x10,0x0F,0x08,0x08,0x00,0x1F,0x08,0x08,0xFF,0x08,0x08,0x1F,0x00,0x00},/*"坤",1*/

5.2 完整程序

通过网盘分享的文件:i2c_chinese.7z
链接: https://pan.baidu.com/s/1hktCwfMTZ80wHkBal4235Q?pwd=ny43 提取码: ny43

5.3 部分程序


void OLED_PrintChinese(uint8_t x, uint8_t y)
{   
	extern uint8_t g_chinese_fonts[5][32];

	uint8_t page = y;
	uint8_t col  = x*8;
	
	if (y > 7 || x > 15)
			return;
	
	int i;
	for (i = 0; i < sizeof(g_chinese_fonts)/sizeof(g_chinese_fonts[0]); i++)
	{
		/* 设置位置: page,col */
    OLED_SetPosition(page, col);

		/* 发送16字节数据(汉字的上半部) */
    OLED_WriteNBytes((uint8_t*)&g_chinese_fonts[i][0], 16);

		/* 设置位置: page+1,col */
    OLED_SetPosition(page+1, col);
		
		/* 发送16字节数据(汉字的下半部) */
    OLED_WriteNBytes((uint8_t*)&g_chinese_fonts[i][16], 16);

		/* 更新下一个字符的位置:page不变,col+=16 */	
		col += 16;
	}
}
// chinese_font.c
#include <stdint.h>

/* 16*16, 32byte */
uint8_t g_chinese_fonts[2][32] = {
	{0x20,0x20,0x20,0xFF,0x20,0x20,0x00,0xF8,0x88,0x88,0xFF,0x88,0x88,0xF8,0x00,0x00, 
   0x10,0x30,0x10,0x0F,0x08,0x08,0x00,0x1F,0x08,0x08,0xFF,0x08,0x08,0x1F,0x00,0x00},/*"坤",0*/

	{0x20,0x20,0x20,0xFF,0x20,0x20,0x00,0xF8,0x88,0x88,0xFF,0x88,0x88,0xF8,0x00,0x00,
	 0x10,0x30,0x10,0x0F,0x08,0x08,0x00,0x1F,0x08,0x08,0xFF,0x08,0x08,0x1F,0x00,0x00},/*"坤",1*/
};

5.4 OLED显示 结果

显示结果
在这里插入图片描述

欢迎大家一起交流讨论!

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐