32G8K64 实现32位系统us计时和软件定时器
stc里没有32位的定时器获取系统us的定时太麻烦了, 还要安全取值才行, 要不然会出现时间回退,使用定时器0来进行系统us计时, 系统运行在40Mhz,8位预分频器设置0x27, 自动重装载值为0, 溢出时间为65536us,
然后再设置一个变量来记录溢出次数, 这样就可以实时获取系统的us计时了
受javascript定时器的启发, 可以实现这种软件定时器跟js的语法一样
//========================================================================
// ---------------------- 类javascript定时器开始-------------------------
//========================================================================
#define JSTimeSize 10 // 初始化定时的个数, 数量越多, 运行效率越低, 够用就好
unsigned long globeTime = 0; // 定时器0溢出次数
unsigned long system_us = 0; // 系统微秒计时
unsigned long tempGlobeTime = 0; // 临时存储globeTime
unsigned char tempTH0 = 0; // 临时存储TH0
unsigned char tempTL0 = 0; // 临时存储TL0
struct JSTimeStruct
{
unsigned long id; // 定时器id,用来取消定时器, id>0x80000000是setTimeout的id, id<0x80000000是setInterval的id
unsigned long startTime;// 开始执行的时间, 单位us
unsigned long periodTime; // 延时的时间 或者 间隔执行的时间, 单位us
void (*callback)(); // 回调函数
};
struct JSTimeStruct JSTime_arr;
// 获取系统微秒计时
unsigned long micros()
{
// 系统微秒计时, 保持严格单调递增, 禁止出现时间倒退, 32位溢出时间为71分钟
// globeTime*65536+(TH0-0)*256+(TL0-0)
do
{
// 如果在读取过程中发生溢出,重新读取
tempTH0 = TH0;
tempTL0 = TL0;
tempGlobeTime = globeTime;
} while (tempTH0 != TH0 || tempTL0 != TL0 || tempGlobeTime != globeTime);
// 计算当前时间
system_us = (tempGlobeTime << 16) + (tempTH0 << 8 | tempTL0);
return system_us;
}
// 定时器0中断
void T_IRQ0(void) interrupt 1 using 1
{
globeTime++; // 定时器0溢出次数
}
// 定时器0初始化
void Timer0_Init(void) // 65536微秒@40.000MHz
{
TM0PS = 0x27; // 设置定时器时钟预分频
AUXR |= 0x80; // 定时器时钟1T模式
TMOD &= 0xF0; // 设置定时器模式
TL0 = 0x00; // 设置定时初始值
TH0 = 0x00; // 设置定时初始值
TF0 = 0; // 清除TF0标志
TR0 = 1; // 定时器0开始计时
ET0 = 1; // 打开定时器0中断
IPH |= 0x02;// 设置定时器0的中断的优先级为高
IP |= 0x02; // 设置定时器0的中断的优先级为高
}
// 定时器初始化函数
void JSTime_init()
{
unsigned char i = 0;
for (i = 0; i < JSTimeSize; i++)
{
JSTime_arr.callback = 0;
JSTime_arr.periodTime = 0;
JSTime_arr.startTime = 0;
JSTime_arr.id = 0;
}
Timer0_Init();
}
unsigned long JSTime_createTimeId = 0x80000000; // `setTimeout`的id
unsigned long JSTime_createIntervalTimeId = 1;// `setInterval`的id
// loop循环中不断刷新定时器, JSTime_refresh中的局部变量变成全局变量
unsigned long JSTime_cacheId = 0; // 缓存id
unsigned long JSTime_currentTime = 0;
unsigned char JSTime_i = 0;
unsigned char JSTime_isFree = 0;
void JSTime_refresh()
{
JSTime_currentTime = micros();
for (JSTime_i = 0; JSTime_i < JSTimeSize; JSTime_i++)
{
if (JSTime_arr.id != 0)
{
if (JSTime_currentTime - JSTime_arr.startTime >=
JSTime_arr.periodTime)
{
JSTime_cacheId = JSTime_arr.id;
if (JSTime_cacheId >= 0x80000000)
{
// setTimeout 执行完毕就销毁
JSTime_isFree = 1;
}
else
{
JSTime_isFree = 0;
// setInteval 不断进行
JSTime_arr.startTime = JSTime_currentTime;
}
if (JSTime_arr.callback)
{
JSTime_arr.callback();
JSTime_currentTime = micros();
}
// 防止在回调函数里调用了 clearTime 而引发bug
if (JSTime_isFree == 1 && JSTime_arr.id == JSTime_cacheId)
{
// setTimeout 执行完毕就销毁
JSTime_arr.id = 0;
}
}
}
}
}
// 延时执行, delayTime单位为us
unsigned long setTimeout_us(void (*callback)(), uint32 delayTime)
{
unsigned char i = 0;
for (i = 0; i < JSTimeSize; i++)
{
// 找出失效的 结构体
if (JSTime_arr.id == 0)
{
JSTime_arr.callback = callback;
JSTime_arr.periodTime = delayTime;
JSTime_arr.startTime = micros();
if (JSTime_createTimeId > 0xfffffff0)
{
JSTime_createTimeId = 0x80000000;
}
JSTime_createTimeId++;
JSTime_arr.id = JSTime_createTimeId;
return JSTime_createTimeId;
}
}
return 0;
}
// 延时执行, delayTime单位为ms
unsigned long setTimeout(void (*callback)(), uint32 delayTime)
{
return setTimeout_us(callback, delayTime * 1000);
}
// 间隔时间执行, intervalTime单位为us
unsigned long setInterval_us(void (*callback)(), uint32 intervalTime)
{
unsigned char i = 0;
for (i = 0; i < JSTimeSize; i++)
{
// 找出失效的 结构体
if (JSTime_arr.id == 0)
{
JSTime_arr.startTime = micros();
JSTime_arr.callback = callback;
JSTime_arr.periodTime = intervalTime;
if (JSTime_createIntervalTimeId > 0x7ffffff0)
{
JSTime_createIntervalTimeId = 1;
}
JSTime_createIntervalTimeId++;
JSTime_arr.id = JSTime_createIntervalTimeId;
return JSTime_createIntervalTimeId;
}
}
return 0;
}
// 间隔时间执行, intervalTime单位为ms
unsigned long setInterval(void (*callback)(), uint32 intervalTime)
{
return setInterval_us(callback, intervalTime * 1000);
}
// 停止软件定时器计时
void clearTime(unsigned long timeId)
{
unsigned char i = 0;
for (i = 0; i < JSTimeSize; i++)
{
if (timeId == JSTime_arr.id)
{
JSTime_arr.id = 0;
}
}
}
// 停止所有软件定时器计时
void clearAllTime()
{
unsigned char i = 0;
for (i = 0; i < JSTimeSize; i++)
{
JSTime_arr.id = 0;
}
}
//========================================================================
// ---------------------- 类javascript定时器结束-------------------------
//========================================================================
使用方法:
unsigned long timeId = 0;
void task1()
{
// todo
}
void task2()
{
// todo
}
void task3()
{
// todo
}
void task4()
{
// 允许嵌套调用
setTimeout(task2, 1000); // 1秒后执行一次task2
setTimeout(task3, 2000); // 2秒后执行一次task3
}
void task5()
{
// 先清除定时器
// 再设置定时器, 用于防抖延时执行
clearTime(timeId);
timeId = setInterval(task1, 500); // 每隔1秒执行一次task1
}
void setup()
{
//1: 初始化JSTime
JSTime_init();
//2: 设置定时器
timeId = setInterval(task1, 1000); // 每隔1秒执行一次task1
setTimeout(task2, 2000); // 2秒后执行一次task2
setTimeout(task3, 3000); // 3秒后执行一次task3
setTimeout(task4, 4000); // 4秒后执行一次task4
setTimeout(task5, 5000); // 5秒后执行一次task5
}
void main(void)
{
setup();
while (1)
{
// 3: 刷新JSTime
JSTime_refresh();
}
}
页:
[1]