欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

程序员文章站 2024-02-21 21:01:28
...

本文开发环境:

  • MCU型号:STM32F103ZET6
  • IDE环境: MDK 5.27
  • 代码生成工具:STM32CubeMx 5.4.0
  • HAL库版本:STM32Cube_FW_F1_V1.8.0

本文内容:

  1. STM32CubeMx 配置主从I2C(IIC)
  2. 示例工程

一、简介

I2C 是一种双线协议,由一根时钟线和一根数据线组成,由于时序简单,应用广泛,ST 硬件 I2C 网传不够稳定,通常也用软件来模拟,不过由于软件模拟需要占用CPU的资源,所以在一些情况下,硬件I2C是更好的选择。本文示例了 I2C 的主从通信,由于 STM32F103ZE 拥有2个硬件I2C,所以只需要一个单片机即可模拟双机的通信。

二、使用 STM32CubeMx 配置 I2C

使用 STM32CubeMx(以下简称 Mx) 可以非常方便的配置硬件I2C,一般有以下几个步骤:

  • 选择目标单片机
  • 选择系统时钟源,配置系统时钟树
  • 打开调试 IO 口
  • 配置 I2C:选择速度,配置地址等
  • 生成指定 IDE 的工程

三、硬件I2C的配置

  1. 创建一个新的工程:
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置
  2. 选择目标单片机(STM32F103ZET6):
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置
  3. 选址时钟源:
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

一般单片机的最小系统板,都有外部晶振,这里可根据实际需求来配置。

  1. 配置系统时钟树:
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

  2. 打开调试:
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

  3. 配置 I2C 主机:
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

由于本文目的是把 I2C 配置为主机,所以其实只有2个选项需要配置,这里保持默认,即使用 标准模式,频率100KHz。

  1. 配置 I2C 从机:
    1. 基本配置:
      STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置2.打开中断:STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

从机需要配置作为从机时的地址,I2C需要地址,这样就可以实现一对多的通信。地址有2种,7位和10位,本文选择默认的7位。另外,从机需要打开中断,以便使用中断来接收数据。

  1. 配置工程的基本信息
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置
  2. 生成工程
    至此已经完成了所有工程的配置,点击 GENERATE CODE 即可生成工程:
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

三、外部上拉

需要注意的是,I2C标准中定义了IO口为开漏模式,所以需要上拉电阻,在进行编程测试之前,请保证 I2C 有外部上拉是电阻,本文上拉电阻为 4.7K:
STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

四、编程

1. 准备

环境已经准备完成以后,就可以编程来测试代码,Mx 默认是使用 HAL 库来初始化外设,所以可以调用 HAL 的 API 函数来测试 I2C 的通信功能。

本文示例选用以下 2个数组和3 个函数来测试:

//接收和发送数组
static uint8_t I2C_recvBuf[10] = {0};
static uint8_t I2C_sendBuf[10] = {0,1,2,3,4,5,6,7,8,9};
//HAL 接口函数
HAL_I2C_Master_Transmit();             //主机堵塞发送
HAL_I2C_Slave_Receive_IT();            //从机中断接收
HAL_I2C_SlaveRxCpltCallback();         //接收完成回调函数

2. 程序实现

具体程序如下所示:

// #1.定义数组
static uint8_t I2C_recvBuf[10] = {0};
static uint8_t I2C_sendBuf[10] = {0,1,2,3,4,5,6,7,8,9};
int main(void)
{
  ......
  // #2.使能从机中断接收
  HAL_I2C_Slave_Receive_IT(&hi2c2/*接收的I2C*/,I2C_recvBuf/*存放数据的地址*/,sizeof(I2C_recvBuf)/*接收数据的个数*/);
  while (1)
  {
     ......
     // #3.主机发送数据
     HAL_I2C_Master_Transmit(&hi2c1/*发送的I2C*/, (20<<1)|0x00/*地址*/, I2C_sendBuf/*发送数据的地址*/, sizeof(I2C_sendBuf/*发送的字节*/), 1000/*等待的时间*/); 
  }
}

/* 从机接收回调函数 */
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
    /* 再次打开 I2C 中断接收 */
	HAL_I2C_Slave_Receive_IT(&hi2c2,I2C_recvBuf,sizeof(I2C_recvBuf));
}

需要注意,在I2C2完成一次接收一次,会关闭中断,并调用回调函数HAL_I2C_SlaveRxCpltCallback() 所以,可以在回调函数中写入数据处理的语句,但是需要运行HAL_I2C_Slave_Receive_IT()来开启接收中断。

3. 验证

将 I2C1 和 I2C2 连接起来,也就是连接主机和从机:

  • PB6 --> PB10
  • PB7 --> PB11

该程序有多种验证的方法:

  1. 在回调函数中,打印 I2C_recvBuf 的值,查看是否和发送的一致。这需要额外添加打印的代码
  2. 使用硬件仿真,通过变量观察窗口查看 I2C_recvBuf 的值,这需要ST-LINK或J-Link调试器
  3. 使用 逻辑分析仪/示波器 直接进行时序的分析,这需要一个逻辑分析仪示波器

本文使用 硬件仿真 的方式:

  1. 运行程序仿真后,将I2C_recvBuf 添加到 Watch1 观察串口中:
    STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

2 . 观察Watch1中,I2C_recvBuf [] 的值:
STM32F1x HAL库学习笔记(9)硬件 I2C(IIC)主从机的配置

五、注意事项

  • I2C 总线必须外部上拉
  • HAL 库在完成一个中断接收后,会关闭中断,所以需要在回调函数中再次打开
  • 一些 MCU 在调用主机发送时,可能会一直返回数值2,即对于错误:HAL_BUSY,若排除上拉电路问题,可能是遇到 I2C 死锁现象,在官方勘误文件已经做出了应对的方法,详见: 【InterFace】STM32 I2C 死锁问题

六、附件

百度云连接
STM32F103ZE HW_I2C MDK_Project
提取码:5ugn