STC32 定时器0做滴答,设计millis(),micros(),delay_ms()函数
本帖最后由 熊仔 于 2023-7-21 12:10 编辑用过arduino的人都知道,millis()是获取系统运行时间单位ms;micros()是获取系统运行时间单位us。
当然delay_ms()看名字就知道了,毫秒延时函数。这个根据micros()获取系统us时间,延时挺准的。
delay_us(),微秒延时函数,自适应系统时钟。
while(t--) 翻译汇编需要6T时钟,所以时钟最好选6的倍数:12,24,30,36,42,48,54
注意:delay_ms() 不能在中断中使用。
#include "config.h"
/*
2023-07-13 修复定时器读取计数值不准的问题。
*/
uint32_t volatile edata timer0_millis = 0;
//定时器0初始化
void Timer0_Init(void) //1毫秒
{
TM0PS = MAIN_Fosc / 1000000 - 1; //分频,定时器1M时钟
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = (uint8_t)(65536 - 1000); //设置定时初始值
TH0 = (uint8_t)((65536 - 1000) / 256); //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //开启中断
}
//定时器溢出中断
void Timer0_Isr(void) interrupt 1
{
timer0_millis++;
P20 = ~P20;
}
//获取系统运行时间单位ms
uint32_t millis()
{
return timer0_millis;
}
//获取系统运行时间单位us
uint32_t micros()
{
uint32_t ms, us;
uint8_t th, tl, tf;
F0 = EA;
EA = 0;
/*
动态读取运行中的计数值
一种可避免读错的方法是:先读 THx,后读TLx,将两次读得的THx 进行比较,
若两次读得的值相等,则可确定读的值是正确的,否则重复上述过程,
重复读得的值一般不会再错。
*/
do
{
th = TH0;
tl = TL0;
}
while(th != TH0);
tf = TF0;
ms = timer0_millis;
EA = F0;
if(tf)
{
ms++;
us = ms * 1000;
}
else
{
us = ms * 1000 + th * 256 + tl - 64536;
}
return us;
}
//毫秒延时函数
void delay_ms(uint32_t ms)
{
uint32_t start, current;
start = micros();
while (ms > 0)
{
current = micros();
if (( current - start) >= 1000)
{
ms--;
start += 1000;
}
}
}
//while(t--) 翻译汇编需要6T时钟,所以时钟最好选6的倍数:12,24,30,36,42,48,54
#define US_6T(MAIN_Fosc/6000000UL)
void delay_us(uint16_t us)
{
uint32_t t;
t =us * US_6T; //3T
t -= 2; //1T
while(t--); //6T*t
//最后退出只需要1T,所以-2T
//RET 3T参数 1T lcall 3T
}
//由于micros()需要时间,导致不是很准
/*
void delay_us(uint32_t us)
{
uint32_t end,current;
end = micros()+us;
#if(MAIN_Fosc>=40000000UL)
end--;
#endif
#if(MAIN_Fosc<40000000UL)
end-=2;
#endif
do{
current = micros();
}while (current < end) ;
}
*/
这个代码调试了很久,才弄对。
调试过程中,遇到2个难题:
1,动态读取运行中的计数值,读不准的问题。请教了STC技术才解决。
2,必须读取溢出标志位,溢出的时候tl不是马上重载的,这个要注意,计算的时候去掉th和tl的数值。
版主,我这也遇到这样同样的问题了,一个定时器中断里自增的一个值,之后读出来的值有时候反而小于一开始读出来的值,请问你是怎么解决的呢 aa520520 发表于 2024-9-10 16:18
版主,我这也遇到这样同样的问题了,一个定时器中断里自增的一个值,之后读出来的值有时候反而小于一开始读 ...
你要在程序里写上,如果后读入的值小于前读入的值,后面的值要加上进制,这样,后面的值就会永远大于前面的值了。问题就是,变量是循环的,int型到了65535,再来一次就变成0了。我的办法就是在中断中看看次数到了30000吗,到了30000就清零,这样如果后面读到的数小于前面的数,直接加30000,总数也没有超过int的范围。 liuzonggong 发表于 2024-9-10 17:10
你要在程序里写上,如果后读入的值小于前读入的值,后面的值要加上进制,这样,后面的值就会永远大于前面 ...
读的时候需要关闭中断
页:
[1]