chengxg 发表于 2025-2-28 15:51:33

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]
查看完整版本: 32G8K64 实现32位系统us计时和软件定时器