【STM32】软件I2C控制频率

news2024/10/6 10:37:47

在上一篇文章中,我们已经介绍了整个软件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; //
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dQr8E86k-1687864519727)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20230627114808333.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u34unSy4-1687864519728)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20230627114814233.png)]

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JZWhqYLr-1687864519729)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20230627142100990.png)]

记录两个端点的时刻,然后相减就是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)

最终测得波形比较准确。
在这里插入图片描述
在这里插入图片描述

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/704567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分析生态系统服务社会价值问题

生态系统服务是人类从自然界中获得的直接或间接惠益&#xff0c;可分为供给服务、文化服务、调节服务和支持服务4类&#xff0c;对提升人类福祉具有重大意义&#xff0c;且被视为连接社会与生态系统的桥梁。自从启动千年生态系统评估项目&#xff08;Millennium Ecosystem Asse…

飞致云开源社区月度动态报告(2023年6月)

自2023年6月起&#xff0c;中国领先的开源软件公司FIT2CLOUD飞致云将以月度为单位发布《飞致云开源社区月度动态报告》&#xff0c;旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况&#xff0c;以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源大…

准备项目管理软考前,这份备考经验你不得不看

早上好&#xff0c;我是老原。 5月的全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试 &#xff08;简称软考&#xff09;的考试即将开始&#xff0c;不知道大家都准备的如何&#xff1f; 虽然5月考试的报名时间已经过了&#xff0c;但还是有新一波粉丝朋友…

解决微信后台禁用url问题

解决微信后台禁用url问题 由于目前用的平台&#xff0c;域名都没有在微信授权&#xff0c;所以被微信给禁用了&#xff0c;我们现在用一个接口可以绑定域名的平台转发一下&#xff0c;演示选择使用vscode工具&#xff0c;其它有终端的工具亦可。 1. 安装vercel 全局安装verce…

虹科分享|如何防范MOVEit transfer漏洞|高级威胁防御

美国网络安全和基础设施安全局(CISA)承认&#xff0c;它正在向几个联邦机构提供支持&#xff0c;这些机构在Progress(前身为IpSwitch)MOVEit传输解决方案中暴露出漏洞后被攻破。根据CISA发布的一份警报和网络安全公告&#xff0c;CL0P勒索软件团伙一直在积极利用漏洞进行数据外…

SpringBoot + Druid监控 MySQL,慢SQL快速定位,真好用!

我们都使用过连接池&#xff0c;比如C3P0&#xff0c;DBCP&#xff0c;hikari&#xff0c; Druid&#xff0c;虽然HikariCP的速度稍快&#xff0c;但Druid能够提供强大的监控和扩展功能&#xff0c;也是阿里巴巴的开源项目。 Druid是阿里巴巴开发的号称为监控而生的数据库连接…

环肽抑制剂:244082-19-7,CTTHWGFTLC, CYCLIC,属于基质金属蛋白酶 MMP-2 和 MMP-9

文章编辑来自于&#xff1a;陕西新研博美生物科技有限公司MISS.wu​ CTTHWGFTLC, CYCLIC | CAS&#xff1a;244082-19-7| 纯度&#xff1a;95% 结构式&#xff1a; 试剂参数信息&#xff1a; CAS&#xff1a;244082-19-7 外观&#xff08;Appearance&#xff09;&#xff1…

fastadmin框架select下拉框该怎么写(接口数据)

先让大家看一下最终效果&#xff1a; 来上代码&#xff1a; <select id"c-education" data-rule"required" class"form-control selectpicker" name"row[education]">{foreach name"education" item"vo"}&…

【Linux | Shell命令】bash shell 进程、磁盘、文件处理命令

目录 &#x1f384;一、概述&#x1f384;二、进程相关命令✨2.1 ps 命令 —— 查看进程✨2.2 top 命令 —— 实时监测进程✨2.3 kill、pkill 命令 —— 结束进程 &#x1f384;三、磁盘相关命令✨3.1 mount、umount 命令 —— 挂载、卸载命令✨3.2 df 命令 —— 查看磁盘空间✨…

DCompute链下计算外包:只EVM就足够了么?

1. 引言 当前的以太坊L2扩容方案主要有&#xff1a; Optimistic RollupzkRollup&#xff1a;如Polygon zkEVM、Scroll等 这些L2方案仍是基于EVM的。 但游戏、链上订单簿、Web3社交、机器学习、基因组建模等高性能应用是compute-heavy的&#xff0c;对于L2 EVM来说仍是昂贵的…

深入理解 Golang: Goroutine 协程

进程用来分配内存空间&#xff0c;是操作系统分配资源的最小单位&#xff1b;线程用来分配 CPU 时间&#xff0c;多个线程共享内存空间&#xff0c;是操作系统或 CPU 调度的最小单位&#xff1b;协程用来精细利用线程。协程就是将一段程序的运行状态打包&#xff0c;可以在线程…

idea连接MYSQL报错汇总

idea连接MYSQL报错汇总 【The last packet sent successfully to the server was 0 milliseconds ago.The driver has not received any packets from the server.】 原因&#xff1a;mysql57 运行在非默认端口号 解决&#xff1a; 1.测试本地连接mysqsl57 打开C:\ProgramDa…

管理类联考——数学——技巧篇——公式——函数、方程与不等式

集合 A 有 n 个元素&#xff0c;则集合 A 的子集个数为 2 n 2^n 2n个&#xff0c;真子集个数为 2 n − 1 2^n-1 2n−1个&#xff0c;非空子集个数为 2 n − 1 2^n-1 2n−1个&#xff0c;非空真子集个数为 2 n − 2 2^n-2 2n−2个。抛物线 y a x 2 b x c yax^2bxc yax2bxc与轴…

ST STM32H723ZGTx - NUCLEO-H723ZG DMAMUX_RequestGen例程重现/消化/改进

文章目录 ST STM32H723ZGTx - NUCLEO-H723ZG DMAMUX_RequestGen例程重现/消化/改进概述笔记问题的难点为了确定程序流程, 加入ITM将CubeMX升级到最新将CubeMX说明书翻一下CubeMX配置芯片功能实验工程主要代码.sct文件main.c中断实现文件 stm32h7xx_it.c.ioc补充END ST STM32H72…

探索网络通信核心技术,手写TCPIP用户态协议栈,让性能飙升起来!

一、DPDK简介 DPDK&#xff08;Data Plane Development Kit&#xff09;是一个开源的数据平面开发工具包&#xff0c;它提供了一组C语言库和驱动程序&#xff0c;用于快速开发高性能的数据平面应用程序。DPDK使用用户空间的方式来实现网络数据包处理&#xff0c;从而避免了传统…

海气相互作用 - 全球水循环过程及其量级

全球水循环过程及其量级 单位&#xff1a;Sv106m3/s&#xff0c;大气/陆地/海洋(103 km3)径流1.3 Sv≈台湾暖流1.1 Sv≈白令海峡0.9-1.1 Sv 从涡度平衡的角度说明为什么大洋强化发生在西边界而非东边界 有且只有在大洋西边界强化&#xff0c;才可以使得摩擦力产生一个正的涡…

【线程池】Java线程池的内部类Worker详解

目录 一、简介 二、Worker类对象的类图 三、Worker类对象的解释 4.2 Worker继承自AQS有何意义&#xff1f; 四、Worker的主要代码 4.1 运行worker 4.2 worker和ThreadPool的关系 五、Worker源码分析 5.1 Worker实现接口Runnable&#xff0c;执行run方法 5.2 核心方法…

Mysql主从原理

1.为什么要主从&#xff1f; 什么东西都有丢失或损坏的可能&#xff0c;所以备份是一个重要的手段。 2.备份机制&#xff1f; 对于主从库的分工: "主写从读" 中继日志文件我的理解是一个大的临时区&#xff0c;主库推送过来的数据不用同步进行到从库&#xff0c;这…

零基础学会Python编程——数据也分类:常见数据类型

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 ​编辑 前言 学习目标 一.常见数据类型 1.数字类型 &#xff08;1&#xff09…

Can’t connect to MySQL server on ‘localhost’ (10061)

标题:Can’t connect to MySQL server on ‘localhost’ (10061) 一种情况是&#xff0c;mysql服务没有开启&#xff0c; 解决方式&#xff1a;以管理员身份进入cmd&#xff0c;然后输入net start mysql&#xff0c;注意这里的mysql&#xff0c;指的是你的mysql服务的名称&am…