STM32 I2C 总线通信实战|从原理到 OLED 屏数据收发(超详细)---STM32 HAL库专栏

🎬 渡水无言个人主页渡水无言

专栏传送门 : 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》

专栏传送门 : 《freertos专栏》 《STM32 HAL库专栏

⭐️流水不争先,争的是滔滔不绝

📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生

| 省级优秀毕业生获得者 | csdn新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生

在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连

目录

前言

[一、I2C 总线核心基础知识](#一、I2C 总线核心基础知识)

1.1、总线组成与硬件规则

[二、I2C 总线通信时序过程](#二、I2C 总线通信时序过程)

2.1、总体流程

2.2、起始位

[2.3、 寻址阶段](#2.3、 寻址阶段)

2.4、数据传输阶段

2.5、停止位

2.6、全过程总结

2.7、波特率

[三、CubeMX 配置 I2C+OLED 屏通信](#三、CubeMX 配置 I2C+OLED 屏通信)

3.1、OLED简介

3.1.1、实物及原理图

[3.2、CubeMX 完整配置步骤](#3.2、CubeMX 完整配置步骤)

3.2.1、创建新工程及选择芯片型号

[3.2.2、选择SYS 外设的核心配置及设置引脚模式](#3.2.2、选择SYS 外设的核心配置及设置引脚模式)

3.2.3、pc13引脚参数设置

3.2.4、设置I2C接口

3.2.5项目管理与生成

3.3、代码编写

[3.3.1、查找OLED屏的I2C 地址(查找手册)](#3.3.1、查找OLED屏的I2C 地址(查找手册))

[3.3.2、OLED 屏控制指令(核心)](#3.3.2、OLED 屏控制指令(核心))

[3.3.3、 I2C 核心 API(CubeMX 生成)](#3.3.3、 I2C 核心 API(CubeMX 生成))

[写数据 API:HAL_I2C_Master_Transmit(向从机写数据)](#写数据 API:HAL_I2C_Master_Transmit(向从机写数据))

[读数据 API:HAL_I2C_Master_Receive(从从机读数据)](#读数据 API:HAL_I2C_Master_Receive(从从机读数据))

3.3.4、keil最终程序

总结


前言

本此博客基于 STM32F103 系列单片机,从 I2C 总线核心原理(开漏输出、线与逻辑、通信时序)讲起,使用 CubeMX 配置 I2C、实现 OLED 屏数据收发,并联动控制板载 LED。


一、I2C 总线核心基础知识

串口只能实现 "一对一" 通信,一个串口可以让单片机跟一个外部设备相连,所以通过串口USART1、USART2、USART3,我们的单片机可以跟三个外部设备相连,如下图所示:

1.1、总线组成与硬件规则

但如果想要连接更多的设备,就要使用总线了,比如本期博客我们要讲的I2C总线。

而 I2C 总线是多设备互联的核心方案 ------ 仅需 SCL(时钟线)、SDA(数据线)两根线,就能让一个主机挂载多个从机,是传感器、显示屏等外设的主流通信方式。如下图所示:

I2C总线由SCL、SDA组成。

SCL负责传输高低变化的方波信号,每个时钟周期传输一位,所以时钟的频率越高,传输的速率越快。

SDA负责传输数据,高电压表示1,低电压表示0;

主机和从机各有SCL、SDA引脚,两种引脚各自与I2C总线的SCL、SDA引脚相连;

SCL、SDA各连接一个阻值4.7k的上拉电阻;

主/从机的SCL、SDA引脚都使用开漏输出开漏输出如下图所示:

疑问:为什么I2C所有的引脚都要配置开漏输出?为什么要配置两个上拉电阻呢?

答案:这其实是为了实现逻辑线与。

当主机、从机均配置高阻抗时,总线由于配置了上拉电阻,所以显示高电压;

只要有一个"机"配置的低电压,那么Vdd的电流就会直接通往此"机",从而总线显示低电压

二、I2C 总线通信时序过程

2.1、总体流程

I2C 通信由主机全程主导,完整时序分为 4 个核心阶段,流程图直观拆解全过程:

2.2、起始位

过程如下图所示:

  • 触发条件:主机控制SCL 保持高电平 ,SDA 产生下降沿(高→低);
  • 作用:告诉所有从机 "通信开始,准备接收地址"。

2.3、 寻址阶段

  • 主机动作:通过 SCL 控制时钟节奏,SDA 依次发送7 位从机地址 (图中比如是0x78)+ 1 位读写方向位(0 = 写,1 = 读);

  • 从机动作:所有从机对比自身地址,匹配成功的从机在第 9 个时钟周期向 SDA 发送1 位应答位(ACK)(低电平 = 应答成功);

  • 核心:每台 I2C 设备都有唯一地址,主机通过寻址确定 "和谁通信"。

注意:寻址阶段 NAK 的原因

地址填错,要寻址的从机不存在
要寻址从机正忙,来得及回复 ACK
从机故障

2.4、数据传输阶段

写数据:主机在 SCL 时钟同步下,通过 SDA 逐位发送有效数据,从机每接收 1 字节后回复 1 位应答位;

读数据:读写方向位为 "读" 时,从机在 SCL 时钟同步下发送数据,主机接收后回复应答位;

关键:无论读写,SCL 始终由主机控制,仅 SDA 的收发方互换。

2.5、停止位

触发条件:主机控制SCL 保持高电平,SDA 产生上升沿(低→高);

作用:告诉所有从机 "本次通信结束"。

2.6、全过程总结

2.7、波特率

波特率越大,数据传输越快,但是越不稳定,f103单片机只支持前两钟模式:

注意:通常使用2:1的模式。

三、CubeMX 配置 I2C+OLED 屏通信

3.1、OLED简介

OLED显示屏:性能优异的新型显示屏,具有功耗低、相应速度快、宽视角、轻薄柔韧等特点

0.96寸OLED模块:小巧玲珑、占用接口少、简单易用,是电子设计中非常常见的显示屏模块。

供电:3~5.5V,通信协议:I2C/SPI,分辨率:128*64

3.1.1、实物及原理图

实物图如下图所示:

原理图如下:

VCC - 电源 +

GND - 接地

SCL - I2C 接口的串行时钟线

SDA - I2C 接口的串行数据线

3.2、CubeMX 完整配置步骤

CubeMX新建项目------选型号------选调试接口------配置PC13引脚(板载LED,跟前几次操作相同)------设置I2C接口

1.打开STM32CubeMX,新建工程,选择芯片

2.设置芯片的调试接口(如果忘记这个步骤,芯片的调试接口将被锁死,程序烧录不进去)

3.2.1、创建新工程及选择芯片型号

首先点击File --->点击New project

选中STM32F103C8T6,再点击start project

3.2.2、选择SYS 外设的核心配置及设置引脚模式

在SYS Mode and Configuration栏中,按如下配置:

调试模式(Debug):选定了Serial Wire(SW 模式)。

这是 STM32 最常用的调试接口模式,仅需占用SWDIO和SWCLK两个引脚。

时基源(Timebase Source):选定了SysTick。

这表示将系统滴答定时器作为 HAL 库的时基来源,用于实现HAL_Delay()等延时函数,是 STM32 工程的标准配置。

并在右侧芯片图中点击PC13设置为GPIO_Output"

PA9引脚设置为GPIO_input"

3.2.3、pc13引脚参数设置

点击GPIO选中对应的引脚,即可设置参数,设置为开漏模式,初值为高电平,这样led默认为熄灭。

3.2.4、设置I2C接口

在connectivity里可以看到,单片机有两个I2C接口I2C1和I2C2,任选一个即可

I2C有三种模式:

I2C为标准I2C接口(一般使用这个)

下边两行为系统管理总线(不常用)

选完第一种,可以看到底下出现了各种参数

当STM32当作主机时,设置Master Features(主机参数,更常用),如下图所示:

速度等级其实也就是波特率等级,决定着下面比特率参数的范围。

我们的OLED显示器支持快速模式,所以点击快速模式,并出现新的参数:

占空比只要没特殊要求一般就选择2:1。

可以看到软件已经自动帮我们分配了I2C的引脚:

继续点击GPIO的I2C,可以看到CubeMX已经自动将GPIO模式设置成立复用输出开漏模式。保持默认就好。

3.2.5项目管理与生成

给项目取名、设置位置、选择开发的工具链,再点击GENERATE CODE生成

3.3、代码编写

接线图如下:

注意:市面多数 OLED 屏均自带上拉电阻,接线仅需 SCL/SDA + 正负极(所以可不接电阻)

3.3.1、查找OLED屏的I2C 地址(查找手册)

可知地址为:0x78

3.3.2、OLED 屏控制指令(核心)

通过 I2C 向 OLED 屏发送特定指令,可实现屏幕初始化、显示控制等功能,手册核心指令示例:

复制代码
// 示例:OLED屏初始化指令数组(需根据手册调整)
uint8_t oled_cmd[] = {
    0x00, // 指令起始位
    0xAE, // 关闭显示
    0xD5, // 设置显示时钟分频比/振荡器频率
    0x80, // 分频比设置
    0xA8, // 设置多路复用率
    0x3F, // 多路复用率值
    0xa5  //全白
    // ... 其他初始化指令
    0xAF  // 开启显示
};

3.3.3、 I2C 核心 API(CubeMX 生成)

CubeMX 为 I2C1 生成句柄hi2c1,核心通信接口:

写数据 API:HAL_I2C_Master_Transmit(向从机写数据)
复制代码
HAL_StatusTypeDef HAL_I2C_Master_Transmit(
    I2C_HandleTypeDef *hi2c,    // I2C句柄指针,实战填&hi2c1(CubeMX生成)
    uint16_t DevAddress,        // 从机地址,实战填OLED屏地址0x78
    uint8_t *pData,             // 要发送的数据缓冲区(指令/数据数组)
    uint16_t Size,              // 发送数据长度,以字节为单位
    uint32_t Timeout            // 超时时间(ms),HAL_MAX_DELAY表示无限等待
);
参数 / 返回值 实战说明 图片标注对应项
*hi2c 固定传入&hi2c1,指定使用 I2C1 接口通信 黄色标注:&hi2c1
DevAddress OLED 屏写地址固定为0x78,不可修改 黄色标注:0x78
*pData 传入指令数组(如oled_init_cmd)或数据数组 图片标注:要发送的数据
Size 传入数组长度(如sizeof(oled_init_cmd) 图片标注:要发送数据的数量
Timeout 调试阶段可用HAL_MAX_DELAY(无限等待),量产建议设 100~500ms 黄色标注:HAL_MAX_DELAY
返回值 HAL_OK:发送成功;HAL_ERROR:发送出错;HAL_BUSY:I2C 接口忙;HAL_TIMEOUT:发送超时 图片标注:成功 / 失败返回结果
读数据 API:HAL_I2C_Master_Receive(从从机读数据)
复制代码
HAL_StatusTypeDef HAL_I2C_Master_Receive(
    I2C_HandleTypeDef *hi2c,    // I2C句柄指针,实战填&hi2c1
    uint16_t DevAddress,        // 从机读地址
    uint8_t *pData,             // 接收数据缓冲区(存储读取的状态字/数据)
    uint16_t Size,              // 接收数据长度,以字节为单位
    uint32_t Timeout            // 超时时间(ms),建议设100ms以上
);
参数 / 返回值 实战说明
*hi2c 同写数据 API,固定传入&hi2c1
DevAddress OLED 屏读地址为ox78
*pData 传入单字节数组(如uint8_t status[1]),存储读取的状态字
Size 读取状态字时填 1,读取多字节数据时填对应长度
Timeout 建议设 100ms,避免因通信异常导致程序阻塞
返回值 HAL_I2C_Master_Transmit一致,通过返回值判断读取是否成功

打开keli可以发现CubeMX已经为I2C1生成了一个句柄:

3.3.4、keil最终程序

现在使用第一个接口将命令发送出去,在最开始,我们需要生成一个数组,存放命令:

此外,我们还想将板载指示灯当作OLED屏指示灯来使用,当屏幕开启时,点亮这颗LED,查询手册可知屏幕有一个状态字可表示屏幕的开启或关闭。如下图所示:


总结

使用 CubeMX 配置 I2C、实现 OLED 屏数据收发,并联动控制板载 LED。

相关推荐
Hello_Embed2 小时前
LVGL 入门(四):大小坐标与盒子模型
前端·笔记·stm32·单片机·嵌入式
風清掦2 小时前
【江科大STM32学习笔记-08】DMA直接存储器存取
笔记·stm32·单片机·嵌入式硬件·学习
17(无规则自律)2 小时前
嵌入式 Linux 启动:设备树的加载、传递和解析全流程分析
linux·stm32·嵌入式硬件·unix
爱倒腾的老唐2 小时前
05、STM32 开发基础知识
stm32·单片机·嵌入式硬件
香水5只用六神3 小时前
【RTOS快速入门】05_动态_静态创建任务(2)
c语言·stm32·单片机·嵌入式硬件·freertos·rtos·嵌入式软件
香水5只用六神3 小时前
【RTOS快速入门】06_任务状态理论讲解(1)
c语言·stm32·单片机·嵌入式硬件·freertos·rtos·嵌入式软件
啊哈的哲学路途4 小时前
【esp-idf 指令】
linux·stm32
freemote4 小时前
单极性霍尔开关OH3144/OH44E
stm32·单片机·霍尔传感器·oh3144/oh44e·单极性霍尔开关
kaikaile199516 小时前
农业物联网基于STM32的LoRa无线通信系统设计与实现
stm32·嵌入式硬件·物联网