C51实现定时器0高效率获取开机的微秒数及实现多任务执行无阻塞延时

发布时间:2023年12月21日

类似arduino里的micros()函数, 可以获取开机到现在的微秒数,? 不能1us中断一次吧, 这样效率太低, 直接获取定时器0的 TH0 和 TL0的值及溢出次数来计时就比较好

这里我用的芯片的是stc32g, 主频为24M, 设置定时器初始为?TH0,?TL0的值为0, 最大计时为?32768 us, 计时器每计时一次所用的时间为0.5us,?再次添加一个溢出中断函数来记录溢出了多少次

uint32 globeTime = 0;

void T_IRQ0(void) interrupt 1 using 1 { globeTime++; }

void Timer0_Init(void) // 32768微秒@24.000MHz
{
? AUXR &= 0x7F; // 定时器时钟12T模式
? TMOD &= 0xF0; // 设置定时器模式
? TL0 = 0x00; ? // 设置定时初始值
? TH0 = 0x00; ? // 设置定时初始值
? TF0 = 0; ? ? ?// 清除TF0标志
? TR0 = 1; ? ? ?// 定时器0开始计时
? ET0 = 1; ? ? ?// 打开定时器0中断
}
uint32 micros() {
  // 系统微秒计时
  return (globeTime << 15) + ((TH0 << 8 | TL0) >> 1);
}

则此时获取开机到现在的运行时间计算为,

(globeTime*65536+(TH0-0)*256+(TL0-0))/2,?

c51计算乘除法比较慢, 为计算效率高采用位操作简化为, 此时需要满足条件为主频为24M, 定时器初始为0
(globeTime << 15) + ((TH0 << 8 | TL0) >> 1)

既然有了能够直接获取开机到现在的时间, 那么利用这个就能实现类似javascript的setTimeout和setInterval, 实现分时多任务执行的效果

JSTime.h

uint32 globeTime = 0;

void T_IRQ0(void) interrupt 1 using 1 { globeTime++; }

void Timer0_Init(void) // 32768微秒@24.000MHz
{
? AUXR &= 0x7F; // 定时器时钟12T模式
? TMOD &= 0xF0; // 设置定时器模式
? TL0 = 0x00; ? // 设置定时初始值
? TH0 = 0x00; ? // 设置定时初始值
? TF0 = 0; ? ? ?// 清除TF0标志
? TR0 = 1; ? ? ?// 定时器0开始计时
? ET0 = 1; ? ? ?// 打开定时器0中断
}
uint32 micros() {
  // 系统微秒计时
  return (globeTime << 15) + ((TH0 << 8 | TL0) >> 1);
}

#define JSTimeSize 20 //初始化定时的个数
struct JSTimeStruct {
  uint32 id; //定时器id,用来取消定时器
  uint32 startTime; // 开始执行的时间
  uint32 periodTime; // 延时的时间 或者 间隔执行的时间
  void (*callback)(); // 回调函数
};
struct JSTimeStruct xdata JSTime_arr[JSTimeSize];
uint32 JSTime_createTimeId = 0x80000000; // 0x80000000 之后的id为setTimeout
uint32 JSTime_createIntervalTimeId = 1;

// 定时器初始化函数
void JSTime_init() {
  uint8 i = 0;
  for (i = 0; i < JSTimeSize; i++) {
    JSTime_arr[i].callback = 0;
    JSTime_arr[i].periodTime = 0;
    JSTime_arr[i].startTime = 0;
    JSTime_arr[i].id = 0;
  }
  Timer0_Init();
}

// loop循环中不断刷新
void JSTime_refresh() {
  uint8 i = 0;
  uint32 cacheId = 0;
  uint8 isFree = 0;
  uint32 currentTime = micros();
  for (i = 0; i < JSTimeSize; i++) {
    if (JSTime_arr[i].id != 0) {
      if (currentTime - JSTime_arr[i].startTime >= JSTime_arr[i].periodTime) {
        cacheId = JSTime_arr[i].id;
        if (cacheId >= 0x80000000) {
          // setTimeout 执行完毕就销毁
          isFree = 1;
        } else {
          isFree = 0;
          // setInteval 不断进行
          JSTime_arr[i].startTime = micros();
        }
        if (JSTime_arr[i].callback) {
          JSTime_arr[i].callback();
          currentTime = micros();
        }
        // 防止在回调函数里调用了 clearTime 而引发bug
        if (isFree && JSTime_arr[i].id == cacheId) {
          // setTimeout 执行完毕就销毁
          JSTime_arr[i].id = 0;
        }
      }
    }
  }
}

// 延时执行, delayTime单位为ms
uint32 setTimeout(void (*callback)(), float delayTime) {
  int8 i = 0;
  for (i = 0; i < JSTimeSize; i++) {
    // 找出失效的 结构体
    if (JSTime_arr[i].id == 0) {
      JSTime_arr[i].callback = callback;
      JSTime_arr[i].periodTime = delayTime * 1000;
      JSTime_arr[i].startTime = micros();
      if (JSTime_createTimeId > 0xfffffff0) {
        JSTime_createTimeId = 0x80000000;
      }
      JSTime_createTimeId++;
      JSTime_arr[i].id = JSTime_createTimeId;
      return JSTime_createTimeId;
    }
  }
  return 0;
}

// 间隔时间执行, intervalTime单位为ms
uint32 setInterval(void (*callback)(), float intervalTime) {
  int8 i = 0;
  for (i = 0; i < JSTimeSize; i++) {
    // 找出失效的 结构体
    if (JSTime_arr[i].id == 0) {
      JSTime_arr[i].startTime = micros();
      JSTime_arr[i].callback = callback;
      JSTime_arr[i].periodTime = intervalTime * 1000;
      if (JSTime_createIntervalTimeId > 0x7ffffff0) {
        JSTime_createIntervalTimeId = 1;
      }
      JSTime_createIntervalTimeId++;
      JSTime_arr[i].id = JSTime_createIntervalTimeId;
      return JSTime_createIntervalTimeId;
    }
  }
  return 0;
}

// 停止计时
void clearTime(uint32 timeId) {
  uint8 i = 0;
  if (timeId == 0) {
    for (i = 0; i < JSTimeSize; i++) {
      JSTime_arr[i].id = 0;
    }
  } else {
    for (i = 0; i < JSTimeSize; i++) {
      if (timeId == JSTime_arr[i].id) {
        JSTime_arr[i].id = 0;
      }
    }
  }
}

这个是基于天问block开发工具的代码

demo

#define IRC_24M
#define PLL_NO
#define boolean uint8
#define true 1
#define false 0
#define HIGH 1
#define LOW 0

#include <STC32G.h>
#include <stdio.h>
uint32 sys_clk = 24000000; // 设置PWM、定时器、串口、EEPROM频率参数
#include "lib/rcclock.h"
#include "lib/UART.h"
#include "lib/ADC.h"
#include "lib/delay.h"
#include "myLib/JSTime.h"

#define LED_PIN P2_1
#define LED2_PIN P2_0

void mytask1()
{
  LED_PIN = !LED_PIN;
}

void mytask2()
{
  LED2_PIN = !LED2_PIN;
}

void setup()
{
  rcclock_set_irc(1);
  P2M1 &= ~0x01;
  P2M0 |= 0x01; // 推挽输出
  P2M1 &= ~0x02;
  P2M0 |= 0x02; // 推挽输出
  P2M1 &= ~0x04;
  P2M0 |= 0x04; // 推挽输出
  P2M1 &= ~0x08;
  P2M0 |= 0x08; // 推挽输出
  P3M1 |= 0x04;
  P3M0 &= ~0x04;                                                 // P3.2 高阻输入
  uart_init(UART_1, UART1_RX_P30, UART1_TX_P31, 1000000, TIM_1); // 初始化串口
  ET0 = 1; // 控制定时器中断
  EA = 1;
  JSTime_init(); // JSTime初始化
  
  setInterval(mytask1, 1000); // 添加任务1
  setInterval(mytask2, 200); // 添加任务2
}

void ispDowbload()
{
  if (P3_2 == LOW)
  {
    if (P3_2 == LOW)
    {
      IAP_CONTR = 0x60; // 进入ISP下载
    }
  }
}

void loop()
{
  JSTime_refresh();
  ispDowbload();
}

void main(void)
{
  setup();
  while (1)
  {
    loop();
  }
}

文章来源:https://blog.csdn.net/cxgasd/article/details/135078268
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。