STM32设置为I2C从机模式(HAL库版本)

这篇具有很好参考价值的文章主要介绍了STM32设置为I2C从机模式(HAL库版本)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32设置为I2C从机模式(HAL库版本)

前言

我之前出过一篇关于STM32设置为I2C从机的博客,现在应粉丝要求,出一篇HAL库版本的I2C从机编程。
基于官方库版本的可以看下我之前发的文章:STM32设置为I2C从机模式

1 硬件连接

测试芯片:STM32F103RCT6
测试方法:用一个USB转I2C的工具接到STM32的I2C引脚上,通过上位机工具进行读写操作。如果没有这个工具,也可以用另外一组I2C作为主机或者其他设备测试通讯,同时也可以借助示波器或者逻辑分析仪来辅助调试。
硬件连接:
STM32这边使用硬件I2C1(PB6、PB7),并外接上拉电阻。
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

本次测试中使用的USB转I2C的工具如下图所示:
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

2 软件编程

2.1 步骤分解

1、初始化I2C配置
注:除了最后的HAL_I2C_EnableListen_IT()函数,其他代码都可以用STM32CubeMX自动生成
参考代码:

static void MX_I2C1_Init(void)
{
  hi2c1.Instance = I2C1;                                // 配置I2C1                   
  hi2c1.Init.ClockSpeed = 100000;                       // 时钟频率:100k                            
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;               // 占空比:1/2                                    
  hi2c1.Init.OwnAddress1 = 0x80;                        // 本机地址:0x80(若作为从设备则是从机地址)                           
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;  // 地址模式:7位                                                 
  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)    // I2C1初始化                                                  
  {                                                      
    Error_Handler();                                                      
  }                                                      
  HAL_I2C_EnableListen_IT(&hi2c1);       // 使能I2C1的侦听中断  
}

2、初始化I2C引脚和中断
参考代码:
注:这个代码可以用STM32CubeMX自动生成

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(hi2c->Instance==I2C1)
  {
    // 配置GPIO
    __HAL_RCC_GPIOB_CLK_ENABLE();   
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // 配置I2C中断
    /* Peripheral clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
    /* I2C1 interrupt Init */
    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);  // 事件中断(必须有)
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
    HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 0);  // 错误中断(非必须)
    HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
  }
}

3、配置I2C中断服务函数
参考代码:
注:这个代码可以用STM32CubeMX自动生成

// I2C1事件中断服务函数(必须有)
void I2C1_EV_IRQHandler(void)
{
  HAL_I2C_EV_IRQHandler(&hi2c1);
}

// I2C1错误中断服务函数(非必须)
void I2C1_ER_IRQHandler(void)
{
  HAL_I2C_ER_IRQHandler(&hi2c1);
}

4、配置I2C从机回调处理函数
参考代码:

static uint8_t ram[256];             // 模拟I2C从机数据寄存器(主机读写的数据都放在这块内存)
uint8_t offset;                      // 从机寄存器当前偏移地址
static uint8_t first_byte_state = 1; // 是否收到第1个字节,也就是偏移地址(0:已收到,1:没有收到)

// 侦听完成回调函数(完成一次完整的i2c通信以后会进入该函数)
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
  // 完成一次通信,清除状态
  first_byte_state = 1;
  offset = 0;
  HAL_I2C_EnableListen_IT(hi2c); // slave is ready again
}

// I2C设备地址回调函数(地址匹配上以后会进入该函数)
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
  if(TransferDirection == I2C_DIRECTION_TRANSMIT) 
  {// 主机发送,从机接收
    if(first_byte_state) 
    {// 准备接收第1个字节数据
      HAL_I2C_Slave_Seq_Receive_IT(hi2c, &offset, 1, I2C_NEXT_FRAME);  // 每次第1个数据均为偏移地址
    } 
  } 
  else 
  {// 主机接收,从机发送
    HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &ram[offset], 1, I2C_NEXT_FRAME);  // 打开中断并把ram[]里面对应的数据发送给主机
  }
}

// I2C数据接收回调函数(在I2C完成一次接收时会关闭中断并调用该函数,因此在处理完成后需要手动重新打开中断)
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
  if(first_byte_state) 
  {// 收到的第1个字节数据(偏移地址)
    first_byte_state = 0;
  } 
  else 
  {// 收到的第N个字节数据
    offset++;  // 每收到一个数据,偏移+1
  }
  // 打开I2C中断接收,下一个收到的数据将存放到ram[offset]
  HAL_I2C_Slave_Seq_Receive_IT(hi2c, &ram[offset], sizeof(ram), I2C_NEXT_FRAME);  // 接收数据存到ram[]里面对应的位置
}

// I2C数据发送回调函数(在I2C完成一次发送后会关闭中断并调用该函数,因此在处理完成后需要手动重新打开中断)
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
  offset++;  // 每发送一个数据,偏移+1
  HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &ram[offset], sizeof(ram), I2C_NEXT_FRAME);  // 打开中断并把ram[]里面对应的数据发送给主机
}

2.2 测试用例

1、测试方法
使用USB转I2C的工具接入到MCU的I2C上面,然后使用上位机工具进行读写操作,最后通过串口把I2C通讯过程中的几个重要节点打印出来,验证结果是否正确。

2、测试程序
其实和上面讲解的代码是一样的,只是初始化时先把ram[]赋初值。
参考测试代码:

#include "stm32f1xx_hal.h"

static uint8_t ram[256];             // 模拟I2C从机数据寄存器(主机读写的数据都放在这块内存)
uint8_t offset;                      // 从机寄存器当前偏移地址
static uint8_t first_byte_state = 1; // 是否收到第1个字节,也就是偏移地址(0:已收到,1:没有收到)

// 侦听完成回调函数(完成一次完整的i2c通信以后会进入该函数)
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
  // 完成一次通信,清除状态
  first_byte_state = 1;
  offset = 0;
  HAL_I2C_EnableListen_IT(hi2c); // slave is ready again
}

// I2C设备地址回调函数(地址匹配上以后会进入该函数)
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
  if(TransferDirection == I2C_DIRECTION_TRANSMIT) 
  {// 主机发送,从机接收
    if(first_byte_state) 
    {// 准备接收第1个字节数据
      HAL_I2C_Slave_Seq_Receive_IT(hi2c, &offset, 1, I2C_NEXT_FRAME);  // 每次第1个数据均为偏移地址
    } 
  } 
  else 
  {// 主机接收,从机发送
    HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &ram[offset], 1, I2C_NEXT_FRAME);  // 打开中断并把ram[]里面对应的数据发送给主机
  }
}

// I2C数据接收回调函数(在I2C完成一次接收时会关闭中断并调用该函数,因此在处理完成后需要手动重新打开中断)
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
  if(first_byte_state) 
  {// 收到的第1个字节数据(偏移地址)
    first_byte_state = 0;
  } 
  else 
  {// 收到的第N个字节数据
    offset++;  // 每收到一个数据,偏移+1
  }
  // 打开I2C中断接收,下一个收到的数据将存放到ram[offset]
  HAL_I2C_Slave_Seq_Receive_IT(hi2c, &ram[offset], sizeof(ram), I2C_NEXT_FRAME);  // 接收数据存到ram[]里面对应的位置
}

// I2C数据发送回调函数(在I2C完成一次发送后会关闭中断并调用该函数,因此在处理完成后需要手动重新打开中断)
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
  offset++;  // 每发送一个数据,偏移+1
  HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &ram[offset], sizeof(ram), I2C_NEXT_FRAME);  // 打开中断并把ram[]里面对应的数据发送给主机
}

// 测试用例:初始化把ram设置为从0到255的数
void i2c_test(void)
{
  for (uint16_t i = 0; i < 256; i++)
  {
    ram[i] = i;
  }
}

3 运行测试

3.1 I2C连续写入

通过上位机工具写入:
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

通过逻辑分析仪抓取波形:
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

3.2 I2C连续读取

通过上位机工具连续读取256字节:
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

通过逻辑分析仪抓取波形:
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

3.3 I2C单次读写测试

通过上位机工具读取原值,再写入新值,最后再读取新值:
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

通过逻辑分析仪抓取波形:
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机

4 总结

通过上位机工具的测试以及逻辑分析仪的解析,STM32的硬件I2C从机通信正常且稳定,读写速度测试了100k和400k,没有发现问题,至此测试完成。
好了,关于STM32如何设置从机模式就介绍到这里,如果你们有什么问题,欢迎评论区留言。

需要完整源码工程的同学可以自行下载:源码下载地址

如果这篇文章能够帮到你,就…懂的。
STM32设置为I2C从机模式(HAL库版本),单片机相关,经验分享,stm32,单片机,I2C,I2C从机文章来源地址https://www.toymoban.com/news/detail-663713.html

到了这里,关于STM32设置为I2C从机模式(HAL库版本)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32 HAL库函数学习 I2C篇

    本篇内容讲述STM32的硬件IIC功能。硬件IIC的使用在F1系列上可能会有问题。本次使用的测试平台是H7,用于AT24C02芯片的读写正常,暂不清楚在其他芯片上使用是否正常。 1、HAL_StatusTypeDef HAL_I2C_Init (I2C_HandleTypeDef * hi2c) I2C初始化函数,使用CubeMx生成。需要选中I2C硬件指定的IO口。

    2023年04月08日
    浏览(15)
  • STM32 HAL FreeRTOS 硬件I2C 使用

    因为某个项目想要颜色识别,去识别球的颜色,但是又不想多来个摄像头,所以想尝试一下颜色传感器的方案。但是经过尝试,HAL库生成的 FreeRTOS 硬件 I2C 读写一直在报错。 刚好手头上有九轴陀螺仪的例程代码。最后用FreeRTOS 硬件 I2C 读取数据。 这里提到了阻塞式 HAL 函数(

    2024年02月20日
    浏览(22)
  • STM32 HAL库 STM32CubeMX -- I2C(IIC)

    I2C 通讯协议(Inter - Integrated Circuit) 也就是IIC; 由Phiilps 公司开发的,它引脚少,硬件实现简单,可扩展性强,不需要USART、CAN 等通讯协议的外部收发设备。 I2C协议分为物理层和协议层。 物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物理媒体的传输

    2023年04月16日
    浏览(20)
  • STM32基于CubeMX与HAL库的I2C应用

    1.1 物理层         I2C协议和摩托罗拉公司的SPI协议一样,是一种通讯协议。串行外围设备接口,是一种高速全双工的通信总线,是由 Phiilps 公司开发的。由于它引脚少,硬件实现简单,可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内

    2024年02月21日
    浏览(27)
  • STM32之I2C总线知识和HAL库函数

    一、 I2C总线知识 I2C总线物理拓扑结构 I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来 产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接

    2024年02月21日
    浏览(19)
  • 【STM32CubeMX+HAL库】I2C详解+读写EEPROM

    在之前的标准库中,STM32的硬件IIC非常复杂,更重要的是它并不稳定,所以都不推荐使用。但是在我们的HAL库中,对硬件IIC做了全新的优化,使得之前软件IIC几百行代码,在HAL库中,只需要寥寥几行就可以完成 那么这篇文章将带你去感受下它的优异之处。 通过本篇博客您将

    2024年02月03日
    浏览(24)
  • STM32 HAL库硬I2C的TOF050C模块

    最近在倒腾毕业设计,需要用到TOF050C,但是现有的案例都是软IIC,并且还是基于STM32F103的,笔者用的STM32F767,没有GPIO-CRH寄存器。问题来了,如果我每次都要去看寄存器手册属实费时间,这不干脆直接用硬IIC? 于是乎,打开了TOF050C手册,硬啃! 这手册好在它有工作流程图,

    2024年02月14日
    浏览(23)
  • Clion开发STM32之HAL库I2C封装(基础库)

    引用参考: Clion开发STM32之HAL库GPIO宏定义封装(最新版)

    2024年02月13日
    浏览(21)
  • 01_STM32软件+硬件I2C读取MPU6050(HAL库)

    目录 1、I2C简介 2、I2C时序单元 2.1 起始条件 2.2 终止条件 2.3 发送一个字节 2.4 接收一个字节 2.5 发送应答 2.6 接收应答 3、I2C完整时序 3.1 指定地址写一个字节 3.2 当前地址读一个字节 3.2 指定地址读一个字节 4、简单软件I2C代码(HAL) 4.1 软件I2C 4.2 软件I2C读MPU6050寄存器 5、ST

    2024年04月17日
    浏览(21)
  • 【STM32】I2C练习,HAL库读取MPU6050角度陀螺仪

    MPU-6000(6050)为全球首例整合性6轴运动处理组件,相较于多组件方案,免除了组合陀螺仪与加速器时间轴之差的问题,减少了大量的封装空间。当连接到三轴磁强计时,MPU-60X0提供完整的9轴运动融合输出到其主I2C或SPI端口(SPI仅在MPU-6000上可用)。 寄存器地址 寄存器内容 0X3B

    2024年02月16日
    浏览(20)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包