打印
[经验分享]

51单片机定时器封装

[复制链接]
1138|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-11-25 11:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
简介
介绍:仿javascript的setInterval(callback,delay)实现封装的定时器函数。

文件:timer.c和timer.h

API
定时器初始化
void timer_init(unsigned char timers);

// 单独初始化定时器1
timer_init(TIMER1);
// 同时初始化定时器0和1
timer_init(TIMER0|TIMER1);
添加定时调用事件
char timer_add_event(unsigned char timer_id, void (*callback)(void), unsigned short ms);


// 初始化定时器id,未绑定事件时为-1
char timer   = -1;
// 在定时器0 添加 函数事件callback,每 500ms 调用一次,不会立即调用。
timer = timer_add_event(0, callback, 500);

// 外部函数定义格式示例
void callback(){
    // 执行代码
}
删除定时调用事件
char timer_remove_event(unsigned char timer_id, char id);


// 初始化定时器id,未绑定事件时为-1
char timer   = -1;

// 在定时器0 添加 函数事件callback,每 500ms 调用一次,不会立即调用。
timer = timer_add_event(0, callback, 500);

// 删除timer绑定的函数事件,返回值:-1
timer = timer_remove_event(0,timer);
LED示例
key开关控制led闪烁

#include <REG52.H>
#include "timer.h"
sbit led = P2^0; // led灯
sbit key = P3^1; // 独立按键
void delay_ms(unsigned int ms){
    unsigned int i,j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 110; j++);
}
void led_change(){
    led = ~led;
}
void main()
{
    char timer = -1;
    timer_init(TIMER0); // 定时器0初始化
    while(1){
        if (key == 0)
        {
            delay_ms(10);
            if (key == 0)
            {
                if(timer==-1){ // 如果定时器未绑定事件,则添加事件
                    timer = timer_add_event(0, led_change, 500); // 添加定时器事件
                }else{
                    timer = timer_remove_event(0,timer); // 移除定时器事件
                }
                while (key == 0);
            }
        }

    }
}

注意
如果出现此代码所在文件触发的“ADDRESS SPACE OVERFLOW”,减少EVENT_MAX或TIMER_MAX。测试数据:普中51测试两种模式切换代码,timer_events最大能够定义5个Timer_Event_Type,问题疑似内存不足(不确定)。

函数文件
timer.h
/*
* @Author: VB9331 vb9331@qq.com
* @Date: 2024-11-20 00:00:00
* @LastEditors: VB9331 vb9331@qq.com
* @LastEditTime: 2024-11-20 00:55:27
* @Description: 定时器封装
* Copyright (c) 2024 by VB9331 , All Rights Reserved.
*/
#ifndef __TIMER_H__
#define __TIMER_H__

#define NULL ((void *)0)
enum {
    TIMER0 = 1,
    TIMER1
};

void timer_init(unsigned char timers);
char timer_add_event(unsigned char timer_id, void (*callback)(void), unsigned short ms);
char timer_remove_event(unsigned char timer_id, char id);

#endif

timer.c
/*
* @Author: VB9331 vb9331@qq.com
* @Date: 2024-11-20 00:00:00
* @LastEditors: VB9331 vb9331@qq.com
* @LastEditTime: 2024-11-20 00:55:27
* @Description: 定时器封装
* Copyright (c) 2024 by VB9331 , All Rights Reserved.
*/
#include <REG52.H>
#include "timer.h"

#define TIMER_MAX 2 // 定时器最大数量
#define EVENT_MAX 2 // 每个定时器能存储的最大事件数量

typedef struct _Timer_Event_Type {
    unsigned char enabled;                // 是否绑定
    unsigned short delay;                // 延时时间
    void (*fun)(void);                        // 回调函数
    unsigned short begin_time;        // 记录开始时间,用于计算已绑定时间
} Timer_Event_Type;

Timer_Event_Type timer_events[TIMER_MAX][EVENT_MAX];

char cur_id_max[TIMER_MAX];

unsigned short action_time[2] = {0, 0}; // 定时器已启动时间

void timer_init(unsigned char timers)
{
    TMOD &= ((0xF00 >> (timers & TIMER0)) | (0xF00 >> (timers & TIMER1))) & 0xFF;

    EA = 1; // 打开总中断
    if (timers & TIMER0) {
        TMOD |= 0x01;
        TH0 = 0XFC;
        TL0 = 0X18;
        TF0 = 0; // interrupt sign
        ET0 = 1; // 打开定时器0中断允许
        TR0 = 1; // 打开定时器
        PT0 = 0; // priority level
    }
    if (timers & TIMER1) {
        TMOD |= 0x10;
        TH1 = 0XFC;
        TL1 = 0X18;
        TF1 = 0; // interrupt sign
        ET1 = 1; // 打开定时器1中断允许
        TR1 = 1; // 打开定时器
        PT1 = 1; // priority level
    }
}

// add timer event
char timer_add_event(unsigned char timer_id, void (*callback)(void), unsigned short ms)
{
    unsigned char i;
    char id;
    Timer_Event_Type new_event;

    // catch_begin
    // 非法值直接退出
    if (callback == NULL) {
        return -1;
    }
    // 负数和0延时调为1ms
    ms <= 0 ? ms = 1 : 0;
    // catch_end

    // find available id
    for (i = 0; i <= cur_id_max[timer_id] && timer_events[timer_id].enabled; i++);
    id = i;
    if (id >= EVENT_MAX) { // catch
        return -1;
    }
    if (id > cur_id_max[timer_id]) {
        cur_id_max[timer_id] = id;
    }

    new_event.enabled          = 1;
    new_event.delay            = ms;
    new_event.fun              = callback;
    new_event.begin_time       = action_time[timer_id]; // +1 防止立即触发
    timer_events[timer_id][id] = new_event;
    return id;
}

char timer_remove_event(unsigned char timer_id, char id)
{
    if (id < 0 || id > cur_id_max[timer_id]) { // catch
        return id;
    }
    timer_events[timer_id][id].enabled    = 0;
    timer_events[timer_id][id].delay      = 0;
    timer_events[timer_id][id].fun        = NULL;
    timer_events[timer_id][id].begin_time = 0;
    if (id == cur_id_max[timer_id]) {
        cur_id_max[timer_id]--;
    }
    return -1;
}

void time0_handler(void) interrupt 1 // 定时器0中断函数
{

    const unsigned char timer_id = 0; // 定时器id

    unsigned char i;
    TH0 = (65536 - 1000) / 256; // 1ms 中断一次
    TL0 = (65536 - 1000) % 256;
    action_time[0]++; // 定时器0已启动时间+1,放在函数前端防止立即触发

    for (i = 0; i <= cur_id_max[timer_id]; i++) {
        if (timer_events[timer_id].enabled == 0) {
            continue;
        }
        if (((action_time[0] - timer_events[timer_id].begin_time) % timer_events[timer_id].delay) == 0) {
            timer_events[timer_id].fun(); // TODO: Whether to add arguments about the timer object to this function.
        }
    }
}

void time1_handler() interrupt 3 // 定时器1中断函数
{
    const unsigned char timer_id = 1;

    unsigned char i;
    TH1 = (65536 - 1000) / 256;
    TL1 = (65536 - 1000) % 256;
    action_time[1]++;

    for (i = 0; i <= cur_id_max[timer_id]; i++) {
        if (timer_events[timer_id].enabled == 0) {
            continue;
        }

        if (((action_time[1] - timer_events[timer_id].begin_time) % timer_events[timer_id].delay) == 0) {
            timer_events[timer_id].fun(); // TODO: Whether to add arguments about the timer object to this function.
        }
    }
}

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_47019630/article/details/143898493

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2028

主题

15904

帖子

14

粉丝