8位单片机尽量不要使用%mod取模
结论:因为会耗费大量时间除几十次
也少用int 16位变量,能用就用char 8位
今天在调板子的时候,发现定时器卡住了,特别慢,排查后是我用了这一行常用代码来把125us定时器计时1秒
i=(i+1)%8000;每次暂停都在这个函数,定时器的时序也乱了
原因:
原因是因为大部分8位单片机没有硬件除法器
取模mod只能靠二进制恢复除法,多次除法或长除法实现
一次需要50-100条指令,相当于几十us,在定时器里是灾难级的
解决方法:
- 用
if (i > 8000) i = 0;代替,规避了多次除法的操作,只需要对比一下 - 用
i = i % 8,2的次方倍,编译器能直接优化成移位操作
以及少用int,多用char
因为8位单片机一次处理数据一般8位,意味着16位的运算要拆成2次,3次的预算
性能对比:
(AI估算,实际会快一点)
| 操作 | 数据类型 | 典型周期数 | 时间@16MHz | 相对耗时 |
|---|---|---|---|---|
i % 8(2的幂) | char 8位 | 1 | 0.25μs | 🟢 极快 |
i % 3 | char 8位 | 286 | 71.5μs | 🔴 极慢 |
j % 8(2的幂) | int 16位 | 3 | 0.75μs | 🟢 极快 |
j % 3 | int 16位 | 286 | 71.5μs | 🔴 极慢 |
j % 8000 | int 16位 | 571 | 142.75μs | 🔴 极慢 |
if(++j>=8000)j=0 | int 16位 | 5 | 1.25μs | 🟢 极快 |
算法源码:
这是单片机官方的底层mod源码,可以学习参考一下
unsignedint__lwmod(unsignedintdivisor,unsignedintdividend){unsignedcharcounter;if(divisor!=0){counter=1;while((divisor&0x8000)==0){divisor<<=1;counter++;}do{if(divisor<=dividend)dividend-=divisor;divisor>>=1;}while(--counter!=0);}returndividend;}