【STM32】软件I2C控制频率

这篇具有很好参考价值的文章主要介绍了【STM32】软件I2C控制频率。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在上一篇文章中,我们已经介绍了整个软件I2C的实现原理,但是也遗留了一个问题,那就是I2C速率的控制,其实就是控制SCL信号的频率。

微秒级延时

在上篇文章中,我们使用了SysTick进行延时,具体如下:

    typedef enum
    {
        Standard_Mode = 100 * 1000,
        Fast_Mode = 400 * 1000,
        Fast_Mode_Plus = 1000 * 1000,
    } I2C_SW_Speed_Mode_e; //i2c速率 unit Hz

static void i2c_delay(I2C_SW_Speed_Mode_e speed_mode)
{
    uint32_t temp;
    SysTick->LOAD = SystemCoreClock / 8 / (speed_mode * 2);
    SysTick->VAL = 0X00; //
    SysTick->CTRL = 0X01; //
    do
    {
        temp = SysTick->CTRL; //
    }
    while((temp & 0x01) && (!(temp & (1 << 16)))); //
    SysTick->CTRL = 0x00; //
    SysTick->VAL = 0X00; //
}

关于SysTick延时的原理,可以参考这篇文章

HAL库下的systick 底层配置 HAL_Delay实现原理 微秒级延时(非中断)以及一些重写延时的小坑 关于HAL_Delay的使用问题_hal_inctick配置__zs_dawn的博客-CSDN博客

STM32入门:Systick(嘀嗒定时器)学习_我是混子我怕谁的博客-CSDN博客

在这里就说明一下Load的值怎么来的。

首先,Systick使用的是系统时钟的8分频,例如系统时钟为400MHz,8分频后为50MHz。

那么1/50000000秒即1/50微秒产生一个周期的振动。

所以,需要计数50次才会产生1微秒的时钟。也就是计数1次产生0.02微秒,精度就是0.02us。

延时验证

那么这个延时准确吗?我们怎么验证呢?网上一般都会有两种方式:

  • 使用示波器观察(电平翻转延时)
  • keil中使用st-link单步调试

在这里,我推荐使用keil中使用st-link单步调试的方案,至于为什么,我们下文再做解释。

首先,我们重写了一个函数

void delay_us(uint32_t delay)
{
    uint32_t temp;
    SysTick->LOAD = SystemCoreClock / 8 / 1000000 * delay;
    SysTick->VAL = 0X00; //
    SysTick->CTRL = 0X01; //
    do
    {
        temp = SysTick->CTRL; //
    }
    while((temp & 0x01) && (!(temp & (1 << 16)))); //
    SysTick->CTRL = 0x00; //
    SysTick->VAL = 0X00; //
}

【STM32】软件I2C控制频率

【STM32】软件I2C控制频率

Core Clock中配置mcu的主时钟频率,本人使用的H7 mcu,在时钟树中配置的主频为400MHz。然后打开Trace Enable。

然后打断点调试(注意,如果有些行不能打断点,可能需要调整代码编译优化等级)。

【STM32】软件I2C控制频率

记录两个端点的时刻,然后相减就是delay_us(1);语句运行的耗时。

0.02621103s - 0.02620955s = 0.00000148s = 1.48us
0.02623537s - 0.02623389s = 0.00000148s = 1.48us
0.02620512s - 0.02620364s = 0.00000148s = 1.48us

实测了3次,平均耗时为1.48us。那么与实际值还是有一定偏差呢,对于这个现象个人觉得是正常的,因为delay_us函数中除了延时代码,还有其它代码也有需要耗时的。那是不是其他耗时就是1.48us-1.00us=0.48us呢?

当我们delay_us(2);时,测试结果如下;

0.02617987s - 0.02617736s = 0.00000251s = 2.51us
0.02619555s - 0.02619303s = 0.00000252s = 2.52us
0.02618346s - 0.02618095s = 0.00000251s = 2.51us

好像也不是固定的。。。。所以除了一个固定计数延时,还有一个不固定的其他代码耗时。但是如果只关注微秒级别的值,那么0.xxus确实可以忽略不计。

但是如果是对于1MHz的时钟频率,半周期为0.50us,那这个代码本身运行耗时是没有办法忽略不计的。这也是为什么配置时钟频率越高的时候,实际偏差越大。

高频率时钟延时

上文说到,1MHz频率的时钟,半周期为0.50us,而我们1us计数的偏差都有0.48us,所以我们使用微秒级别的延时是远远不够的。那么不能直接使用上文的delay_us函数。

又由于其他代码自身有延时,所以我们的实际计数时间得减去一个偏置值,这个偏置值是一个经验值,和编译优化等级强相关。

#define CODE_BASE_DELAY_US  (0.40f)
#define I2C_SPEED_HZ_TO_DELAY_TIME_US(speed) (1000000.0/(speed*2)-CODE_BASE_DELAY_US)

    typedef enum
    {
        Standard_Mode = 100 * 1000,
        Fast_Mode = 400 * 1000,
        Fast_Mode_Plus = 1000 * 1000,
    } I2C_SW_Speed_Mode_e; //i2c速率 unit Hz

static void i2c_delay(I2C_SW_Speed_Mode_e speed_mode)
{
    float delay = I2C_SPEED_HZ_TO_DELAY_TIME_US(speed_mode);
	
    uint32_t temp;
    SysTick->LOAD = SystemCoreClock / 8 / 1000000 * delay;
    SysTick->VAL = 0X00; //
    SysTick->CTRL = 0X01; //
    do
    {
        temp = SysTick->CTRL; //
    }
    while((temp & 0x01) && (!(temp & (1 << 16)))); //
    SysTick->CTRL = 0x00; //
    SysTick->VAL = 0X00; //
    //printf("delay %0.3f us\r\n",delay);
}

结果

本人的编译优化等级选择的是-Ofast,然后#define CODE_BASE_DELAY_US (0.40f)

最终测得波形比较准确。
【STM32】软件I2C控制频率
【STM32】软件I2C控制频率

总结

1、当制作一个延时函数的时候(无论什么方式),当延时足够小的时候,我们就很有必要考虑这个延时函数内部代码本身运行的耗时。
2、很多地方计算SysTick->LOAD的时候会最终减1,这个应该是参考了HAL库函数里的写法。但是如果是上文中的mcu,1个计数就是0.02us,可根据实际情况决定是否减1。文章来源地址https://www.toymoban.com/news/detail-504099.html

到了这里,关于【STM32】软件I2C控制频率的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【stm32】软件I2C读写MPU6050

    概况 首先建立通信层的.c和.h模块 在通信层里写好I2C底层的GPIO初始化 以及6个时序基本单元 起始、终值、发送一个字节、接收一个字节、发送应答、接收应答 写好I2C通信层之后,再建立MPU6050的.c和.h模块 基于I2C通信的模块,来实现指定地址读、指定地址写 再实现写寄存器对

    2024年04月26日
    浏览(50)
  • 【STM32学习】——I2C通信协议&MPU6050姿态传感器&软件I2C读写MPU6050

    ​   目录 前言 一、I2C通信协议 1.简介 2.硬件电路设计 3.I2C时序(软件)

    2024年02月16日
    浏览(52)
  • 【STM32】STM32学习笔记-软件I2C读写MPU6050(33)

    I2C(Inter-Integrated Circuit)总线 是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信,在小数据量场合使用,传输距离短,任意时刻只能有一个主机等特性。 串行的 8 位双向数据传输位速率在标准模式下可

    2024年01月21日
    浏览(62)
  • STM32软件模拟I2C从机的实现方法

    在使用I2C通信时,一般会用到软件模拟I2C。目前网络上能搜索到的软件模拟I2C一般都是模拟I2C主机,很少有模拟I2C从机的例程。由于I2C主机在进行数据收发时,有明确的可预见性,也就是主机明确知道什么时候要进行数据的收发操作,而且I2C的同步时钟信号也是由主机产生的

    2024年02月01日
    浏览(59)
  • STM32 硬件IIC 控制OLED I2C卡死问题

    #更新通知:2023-09-06 STM32L151 固件库 使用I2C 太难了,又宕机了,建议不要在固件库版本上尝试硬件IIC 了,一般人真用不了,直接使用软件模拟的,或者不要使用固件库了,用HAL 库吧,据说HAL 库没这么多问题,不死心的我还是死心了,等有空再研究吧 3.1 I2C模式,我这里选的

    2024年02月09日
    浏览(44)
  • 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日
    浏览(47)
  • 第五章 stm32 cubemx 软件I2C实验以及EEPROM的使用理论及实验过程

    本章将讲解stm32通讯协议中的IIC协议,利用cubeMX完成软件和硬件IIC的实现,并结合实验数据,给人更为深刻的体验。 我们结合IIC的具体协议和逻辑分析仪得到的具体实验数据理解IIC协议。 I2C通讯协议是由Phiilps公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要

    2024年01月21日
    浏览(48)
  • 【STM32 CubeMX】I2C层次结构、I2C协议

    在STM32 CubeMX环境中,I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,广泛应用于连接各种外设和传感器。理解I2C的层次结构、协议和硬件结构对于STM32微控制器的开发至关重要。通过STM32 CubeMX提供的图形化配置工具,我们能够更轻松地理解和配置I2C通信,同时深入了解

    2024年02月22日
    浏览(76)
  • STM32---I2C

    目录                                       一.I2C协议 1.什么是I2C协议?  2.物理层特性                                     二.协议层 1.I2C读写过程 2.I2C外设 3.I2C外设通讯过程              三.I2C库函数                       四.EEPROM 写操作: 读操作:      

    2024年02月16日
    浏览(43)
  • STM32 I2C

    目录 I2C通信  软件I2C读写MPU6050 I2C通信外设 硬件I2C读写MPU6050 I2C通信 R/W:0写1读 十轴:3轴加速度,3轴角速度,3轴磁场强度和一个气压强度  软件I2C读写MPU6050 MyI2C.c MPU6050.c MPU6050_Reg.h(寄存器) main.c I2C通信外设 GPIO口需要配置为复用开漏输出模式。复用:就是GPIO的状态是交由

    2024年02月19日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包