C51实现定时器0高效率获取开机的微秒数及实现多任务执行无阻塞延时
2023-12-21 04:05:22
类似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
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!