锦鈓 发表于 2026-1-19 11:03
和我的设想几乎一致了。问题是目前定时器不支持读计数值吧,都是靠溢出中断,作处理 ...
有些定时器可以读,但只能按8位来读,效率低还要飞读,效率更低
楼主以为“定时器不支持读计数值”?
可以读的吧,不管定时器是否启动都能读。
定时器启动后它就一直累加计数,不需要中断的。
lcwswust 发表于 2026-1-19 11:42
楼主以为“定时器不支持读计数值”?
可以读的吧,不管定时器是否启动都能读。
定时器启动后它就一直累加计 ...
我不知道怎么读,请问一下怎么读寄存器的计数值呢?
我理解的定时器是,初始化时,设置一个初值,然后每个时钟周期+1,满0xFFFF就会溢出,产生中断标志,可以处理中断函数。
例如:
20MHz主频,定时器1T模式,1us的时间可以计数20次,要精确得到1us的定时中断,
计数值初值要设置65516,计数20次到65536溢出,产生中断。
如果按照你的说法,可以读这个计数值,那就很方便了。
我用24MHz主频,12T模式,就是2MHz,1us计数2次,16位,可以计时32768us,约32ms。
如果要使用1ms的时基,我只需要读计数值T,处理一下即可。
初步构思一下逻辑,如下:
主函数中:
u16 lastT;
if( (T - lastT) >= 1000 )
{
lastT = T;
// 任务处理
...
}
溢出中断处理:
lastT=0;
这样的话,就是32ms产生一次中断,比1ms产生一次中断的效率,不说快了32倍,至少10倍有了吧。
同理,1us的时基大致也可以这么处理,1000改成1,并且也是32ms产生一次中断,比1us中断一次效率不知道高了多少倍呢。
任务处理需要耗时多久,1us任务定时是否准确等等问题暂不讨论,这些跟主频相关的。
仔细看了手册,确实有一句话提到可以读计数值。之前都误以为读写的是RL寄存器的值,实际值不可读写。
锦鈓 发表于 2026-1-19 13:20
我不知道怎么读,请问一下怎么读寄存器的计数值呢?
我理解的定时器是,初始化时,设置一个初值,然后每 ...
比如是24MHz时钟,定时器T0工作于12T模式,相当于0.5us计数加1,使其工作于模式1(16位不自动重装),不开定时中断,
那么,TH0、TL0计数达到0xFFFF再加1就自动溢出变成0,不需要中断去处理。
比如你想计算一个函数的耗时,那么就可以这样操作,以下为伪代码:
init();//初始化T0,工作于模式1(16位不自动重装),不开定时中断
......
u16 t0,t1,t;
t0=((u16)TH0<<8)|TL0;//读取16位计数值,实际使用得考虑临界情况
fun();//调用函数,最长耗时不超过32ms
t1=((u16)TH0<<8)|TL0;//读取16位计数值,实际使用得考虑临界情况
t=(t1-t0)/2;//得到时间差,即为耗时,并转为1us单位。
另外,以STC8H为例,定时器2、3、4是可以设置8位分频的,就能较为方便的让计数值按1us加1。
对于速度较慢的低端单片机,搞1us的时基不是不行,而是没啥必要,你读取、比较判断到执行跳转会占用1us中的较多部分,那还能干啥其他事了
锦鈓 发表于 2026-1-19 11:03
和我的设想几乎一致了。问题是目前定时器不支持读计数值吧,都是靠溢出中断,作处理 ...
1us的溢出中断?那不是一直在中断中么
xxxevery 发表于 2026-1-20 09:04
对于速度较慢的低端单片机,搞1us的时基不是不行,而是没啥必要,你读取、比较判断到执行跳转会占用1us中的 ...
顶楼不是说了对于未来的高速单片机而言吗?
patch1582 发表于 2026-1-20 09:07
1us的溢出中断?那不是一直在中断中么
所以我最开始提出这个建议的目的就是为了解决这个问题的啊
xxxevery 发表于 2026-1-20 09:04
对于速度较慢的低端单片机,搞1us的时基不是不行,而是没啥必要,你读取、比较判断到执行跳转会占用1us中的 ...
你先看看13楼的分析,使用读取的方案就是阻塞式,读取的耗时就跟主频相关了,主频越高读取越快。又不是实时操作系统,而且不采用中断的方式,不会打断主程序运行,1us的任务执行的准不准就另当别论了,具体情况还要实验才知晓。主要是为了突破ms级,有100us/10us级可选。