互动
最近评论
stonewu
static uint32_t next_tick = 0; 原: if(HAL_GetTick() >= next_tick) { next_tick = HAL_GetTick() + 100; HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); }//未处理边界条件,溢出导致逻辑非预期。 改动: if(HAL_GetTick()-next_tick <= UINT32_MAX/2 ) { next_tick = HAL_GetTick() + 100; HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } ***代码分析:以上代码的作用是每隔一段时间翻转IO口。其巧妙之处,在于利用减法配合溢出将原本因为溢出而需要 考虑的【边界判断省去】了。 ***通用处理: static uint32_t next_tick = 0; #define INTERVAL 100 if(HAL_GetTick()-next_tick <= (UINT32_MAX+1-INTERVAL) ) { next_tick = HAL_GetTick() + INTERVAL; HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } ***【边界判断省去】原理分析: 原式HAL_GetTick()≥next_tick, 移项变形得到HAL_GetTick()-next_tick≥0, *当HAL_GetTick()等于或者略大于next_tick的时候上式无问题,但是当next_tick增加, *HAL_GetTick()小于next_tick时,由于均是uint32_t,不等式左边的值应是恒≥0的,就比原式错得更多了(原式好歹是边界条件时出错,这直接一开始就出错了),但是仔细观察,next_tick+100后大于HAL_GetTick(),那么HAL_GetTick()-next_tick的值是大于2^32-100的, *那么只需要继续变形为HAL_GetTick()-next_tick<=(2^32-100)是不是就可以了呢? 以上不考虑边界条件,考虑边界条件,则分为两种情况: ①next_tick先溢出, next_tick变得很小,而HAL_GetTick()很大,HAL_GetTick()-next_tick则是一个比较大的值,记其值最小情况为UPLIMIT,为了排除此情况,HAL_GetTick()-next_tick应该<或者≤UPLIMIT。 ②HAL_GetTick()、next_tick均溢出, 此情况就同不考虑边界条件时的分析,HAL_GetTick()-next_tick<=(2^32-100)就可以了。 那么最后,HAL_GetTick()-next_tick是应该<还是≤ UINT32_MAX/2,UPLIMIT,(2^32-100)呢?或者说UPLIMIT应该是多少呢? UINT32_MAX/2是怎么来的,不做考究,当INTERVAL的值大于UINT32_MAX/2则HAL_GetTick()-next_tick <= UINT32_MAX/2 会出错; 当INTERVAL取值100,HAL_GetTick()-next_tick应该和(2^32-100)做比较, 即UPLIMIT应取值(2^32-INTERVAL),<或者≤就自己思考吧。 ***温馨提示or思考:以上代码中两次HAL_GetTick()的值可能是不一样的,也就是翻转IO的周期可能不是简单的INTERVAL*2;还有当INTERVAL取值特别大时,代码可能失效,例如HAL_GetTick()-next_tick<=0或者 <=1时,由于时序问题,调用HAL_GetTick()的时机可能很难满足式子成立。 记HAL_GetTick()为A,记next_tick为B,记INTERVAL为c, 当A=A0=B0>=2^32-c时,B1=B0+c-2^32, B=B1、A>A0→A-B=A-B1=A-(B0+c-2^32)>A0-(B0+c-2^32)=2^32-c; 当A=A2=B2<2^32-c时,B3=B2+c, B=B3、B3>A>A2→[A-B]=[A-B3]=[A-(B2+c)]=A-(B2+c)+2^32>A2-(B2+c)+2^32=2^32-c;
标签
寻找感兴趣的领域
Halo
1
网盘
1
单片机
1
OpenResty
2
ecs
1
端口转发
1
tableview
1
rtthread
1
font
1
1Panel
4
iar
1
efsm
1
vscode
2
版本控制
3
git
6
IAP
2
MDK
1
proxy
1
version
1
自启
1
lvgl
4
rt-thread
1
C语言
2
docker
1
软件
1
UI
1
fifo
1
lvm
4
sspi
1
文章
十一月 2024
3
篇
十月 2024
4
篇
九月 2024
6
篇
八月 2024
5
篇
七月 2024
3
篇
六月 2024
2
篇
五月 2024
5
篇
四月 2024
15
篇
三月 2024
15
篇
二月 2024
13
篇
微信
支付宝
功能
显示模式
关于
gitea
gitbook
网盘
标签
Halo
1
网盘
1
单片机
1
OpenResty
2
ecs
1
端口转发
1
tableview
1
rtthread
1
font
1
1Panel
4
iar
1
efsm
1
vscode
2
版本控制
3
git
6
IAP
2
MDK
1
proxy
1
version
1
自启
1
lvgl
4
rt-thread
1
C语言
2
docker
1
软件
1
UI
1
fifo
1
lvm
4
sspi
1
播放音乐
蒙蒙plus个人博客
文章归档
首页
关于
gitea
gitbook
网盘
tb店铺
二次元入口
火数云
登录
0
文章
72
2024
2024-09-27
模块的功耗管理
•
2024-09-27
模块的状态管理
•
2024-09-27
调试-嵌入式开发必备技能
•
2024-09-14
cherry-pick挑拣提交
•
2024-09-09
Git 约定式提交(Conventional Commits)
•
2024-09-05
电脑单网口双IP实现方式
•
1
你好啊!我是
蒙蒙plus的个人博客
了解更多
最近发布
结构体赋值操作
2024-11-23 11:22:33
rtthread启动流程
2024-11-03 15:32:45
第一个工程-rtthread开发指南
2024-11-03 15:31:02
RT-Thread仓库目录介绍
2024-10-30 01:39:16
最新评论
static uint32_t next_tick = 0; 原: if(HAL_GetTick() >= next_tick) { next_tick = HAL_GetTick() + 100; HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); }//未处理边界条件,溢出导致逻辑非预期。 改动: if(HAL_GetTick()-next_tick <= UINT32_MAX/2 ) { next_tick = HAL_GetTick() + 100; HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } ***代码分析:以上代码的作用是每隔一段时间翻转IO口。其巧妙之处,在于利用减法配合溢出将原本因为溢出而需要 考虑的【边界判断省去】了。 ***通用处理: static uint32_t next_tick = 0; #define INTERVAL 100 if(HAL_GetTick()-next_tick <= (UINT32_MAX+1-INTERVAL) ) { next_tick = HAL_GetTick() + INTERVAL; HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); } ***【边界判断省去】原理分析: 原式HAL_GetTick()≥next_tick, 移项变形得到HAL_GetTick()-next_tick≥0, *当HAL_GetTick()等于或者略大于next_tick的时候上式无问题,但是当next_tick增加, *HAL_GetTick()小于next_tick时,由于均是uint32_t,不等式左边的值应是恒≥0的,就比原式错得更多了(原式好歹是边界条件时出错,这直接一开始就出错了),但是仔细观察,next_tick+100后大于HAL_GetTick(),那么HAL_GetTick()-next_tick的值是大于2^32-100的, *那么只需要继续变形为HAL_GetTick()-next_tick<=(2^32-100)是不是就可以了呢? 以上不考虑边界条件,考虑边界条件,则分为两种情况: ①next_tick先溢出, next_tick变得很小,而HAL_GetTick()很大,HAL_GetTick()-next_tick则是一个比较大的值,记其值最小情况为UPLIMIT,为了排除此情况,HAL_GetTick()-next_tick应该<或者≤UPLIMIT。 ②HAL_GetTick()、next_tick均溢出, 此情况就同不考虑边界条件时的分析,HAL_GetTick()-next_tick<=(2^32-100)就可以了。 那么最后,HAL_GetTick()-next_tick是应该<还是≤ UINT32_MAX/2,UPLIMIT,(2^32-100)呢?或者说UPLIMIT应该是多少呢? UINT32_MAX/2是怎么来的,不做考究,当INTERVAL的值大于UINT32_MAX/2则HAL_GetTick()-next_tick <= UINT32_MAX/2 会出错; 当INTERVAL取值100,HAL_GetTick()-next_tick应该和(2^32-100)做比较, 即UPLIMIT应取值(2^32-INTERVAL),<或者≤就自己思考吧。 ***温馨提示or思考:以上代码中两次HAL_GetTick()的值可能是不一样的,也就是翻转IO的周期可能不是简单的INTERVAL*2;还有当INTERVAL取值特别大时,代码可能失效,例如HAL_GetTick()-next_tick<=0或者 <=1时,由于时序问题,调用HAL_GetTick()的时机可能很难满足式子成立。 记HAL_GetTick()为A,记next_tick为B,记INTERVAL为c, 当A=A0=B0>=2^32-c时,B1=B0+c-2^32, B=B1、A>A0→A-B=A-B1=A-(B0+c-2^32)>A0-(B0+c-2^32)=2^32-c; 当A=A2=B2<2^32-c时,B3=B2+c, B=B3、B3>A>A2→[A-B]=[A-B3]=[A-(B2+c)]=A-(B2+c)+2^32>A2-(B2+c)+2^32=2^32-c;
文档阅读者 /
Halo
1
网盘
1
单片机
1
OpenResty
2
ecs
1
端口转发
1
tableview
1
rtthread
1
font
1
1Panel
4
iar
1
efsm
1
vscode
2
版本控制
3
git
6
IAP
2
MDK
1
proxy
1
version
1
自启
1
lvgl
4
rt-thread
1
C语言
2
docker
1
软件
1
UI
1
fifo
1
lvm
4
sspi
1
文章数 :
72
访问量 :
5466
建站天数 :
2024-02-20
广告
繁
复制选中文本
粘贴文本
引用到评论
新窗口打开
复制链接地址
复制此图片
下载此图片
新窗口打开图片
站内搜索
百度搜索
播放音乐
切换到上一首
切换到下一首
查看所有歌曲
复制歌名
随便逛逛
博客分类
文章标签
复制地址
关闭热评
深色模式
轉為繁體