互动
最近评论
文档阅读者
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;
文章72
2024
openharmony笔记
openharmony笔记
WebDAV
WebDAV
在SDRAM中运行
在SDRAM中运行
IAP升级
IAP升级
SPI协议
SPI协议
华大HC32 flash擦除未生效的解决方法
华大HC32 flash擦除未生效的解决方法
代码格式化对齐功能
代码格式化对齐功能
滴答时间溢出问题
滴答时间溢出问题
lvm lv使用手册
lvm lv使用手册
lvm vg操作手册
lvm vg操作手册
你好啊!我是
蒙蒙plus的个人博客
最近发布
结构体赋值操作
结构体赋值操作
rtthread启动流程
rtthread启动流程
RT-Thread仓库目录介绍
RT-Thread仓库目录介绍
最新评论
头像
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;
文档阅读者 /
广告
引用到评论