最简单的51单片机软件定时器的编写
最简单的51单片机软件定时器的编写
- 为什么要使用软件定时器?
- 不说废话,上代码讲解
- main.c
- soft_timer.h
- soft_timer.c
- 说明:本程序是在学习的时候编写,适当参考网上代码,如涉及到版权问题,可以联系我。
为什么要使用软件定时器?
- 定时器在我们单片机编程时必不可少,虽然现在已经有很多单片机的定时器数量功能数量十分的丰富。但是在一些环境下(例如一些系统),总不能一个任务调一个硬件定时器中断吧?那如果有几十个任务呢?
- 所以就有了软件定时器存在的必要。软件定时器的优点在于,数量可以根据用户需求而定,不需要频繁的配置,维护性较高。缺点在于时间误差较大。
但是,对于一些延时要求不是特别高的任务来说,软件定时器无疑是一个不错的选择。 - 我最近学习了一下软件定时器的实现原理,自己在51单片机上面实现了,软件定时器的主要功能(已经可以使用)。
- 初识者,只需阅读本文章,即可知道软件定时器的一个原理,紧接着可以尝试自己去编写一个软件定时器。(希望文章可以帮到你,大佬可以直接划过了,另外大家有什么意见可以在评论区下留言讨论,一个人的思维是有限的)
不说废话,上代码讲解
main.c
读者只需要关心add_soft_timer()以及soft_timer_process()函数
u16 led_cb(void)//led引脚翻转函数
{static u8 flag=0;flag=!flag;Write_GPIO_Value(GPIO2,PIN_5,flag);return 0;
}void main(void)
{GPIO_Init(); //IO口初始化Timer_Init(); //定时器初始化Uart_Init(); //串口初始化1soft_timer_init(); //软件定时器初始化SET_ALL_IRQ(IRQ_ENABLE); //打开总中断add_soft_timer(&led_cb,200,FOREVER);//添加一个200ms的软件定时器回调函数while(1){soft_timer_process();//软件定时器轮询函数 }
}
soft_timer.h
#ifndef __SOFT_TIMER_H
#define __SOFT_TIMER_H#include "user.h"
#include "timer.h"#define SOFT_TIMER_NUM 10 //定时器最大个数
/*
1)TIMER_START:记录定时器的状态(无效态、运行态、溢出态);
2)TIMER_MODE:记录定时器时的模式(单次、循环);
3)TIMER_STR:定时器的所有参数都包含在该结构体内;
4)typedef u16 (*timer_cb)(void) :为一个返回值为u16,无形参的函数指针类型,定义新名;
*/typedef u16 (*timer_cb)(void);typedef enum {INVALID=0,//无效态,表示定时器不存在RUNING, //运行态TIMEOUT, //超时态}TIMER_START;typedef enum {ONCE = 0, //单次FOREVER, //循环}TIMER_MODE;typedef struct{u16 cycle; //定时器周期 0~65535 units:100usu16 tick; //当前计数值 0~65535 units:100usTIMER_START status; //定时器状态 运行/停止/溢出TIMER_MODE mode; //定时器模式 1次/无限次timer_cb cb; //回调函数
}TIMER_STR;void soft_timer_init(void);
int add_soft_timer(timer_cb *cb,u16 cyc,TIMER_MODE mode);
void soft_timer_process(void);#endif
soft_timer.c
#include "soft_timer.h"
#include "uart.h"
#include "gpio.h"//我使用51单片机内存不够,其它芯片无需放在外部存储器
xdata TIMER_STR timer_real[SOFT_TIMER_NUM];//定义结构体数组,10个。用于存放每个定时器的参数
u16 base_timer_cnt;//计数变量//中断服务,获取时间 :计数单位1ms
void Soft_Timer_Base_Function(void) interrupt 19
{ //1ms自加1,周而复始。溢出后会重0开始继续加base_timer_cnt++;
}//初始化定时器时基设置
void soft_timer_init(void)
{memset(&timer_real,0,sizeof(timer_real)); //结构体清除,就是参数全部清0Timer3Init(); //初始化定时器
}//获取base_timer_cnt计数器的值,该值在定时器中断内不断加1
u16 get_cur_tick(void)
{return base_timer_cnt;
}//添加定时器
int add_soft_timer(timer_cb cb,u16 cyc,TIMER_MODE mode) //回调、定时周期、定时模式
{u8 i;u16 cur_tick=get_cur_tick();//获取计数值//遍历数组,查找是否存在空位,可以被插for(i=0;i<SOFT_TIMER_NUM;i++){if(INVALID==timer_real[i].status){//寻找位置插空timer_real[i].cycle = cyc;timer_real[i].tick = cur_tick+cyc;timer_real[i].cb = cb; //添加回调函数timer_real[i].mode = mode;timer_real[i].status= RUNING;//添加后进入运行态return 0;}}return -1;//没有空位置了
}//轮询处理:核心函数
void soft_timer_process(void)
{u8 i;u16 get_tick=get_cur_tick();//获取当前计数值int diff;for(i=0;i<SOFT_TIMER_NUM;i++)//数组的每一项遍历{ if(INVALID==timer_real[i].status)continue;//此定时器不存在,则结束本次循环,开始新循环if(RUNING==timer_real[i].status)//如果,定时器i,处于运行态{/*此处,我定义了一个int类型的diff变量,表示差值没有直接比较base_timer_cnt与timer_real[i].tick值的原因在于base_timer_cnt变量存在溢出的情况(就是到达65535后,接着变为0)那么此时比较大小显然是不行的。而用差值原因在于,a-b实际上是被当做a+(-b)来处理的。那么即使是存在变量溢出,最终得到的差值也是理想差值。(具体读者可以去查补码的知识)*/diff=get_tick-timer_real[i].tick;//int类型if(diff > 0)//溢出了{timer_real[i].status=TIMEOUT;//标记溢出}}if(TIMEOUT==timer_real[i].status)//如果,定时器i被标记溢出,则进行如下处理{timer_real[i].cb(); //执行回调任务(执行我们的任务)if(ONCE==timer_real[i].mode)//单次模式{memset(&timer_real[i],0,sizeof(TIMER_STR));//清除定时器i的结构体}else if(FOREVER==timer_real[i].mode)//循环模式{timer_real[i].status=RUNING;//状态跳转会运行态timer_real[i].tick=base_timer_cnt+timer_real[i].cycle;//记录下一个周期值}}}
}//定时器删除,不一定使用到
int delete_soft_timer(u8 idex)
{//判断是否存在if(INVALID==timer_real[idex].status){memset(&timer_real[idex],0,sizeof(TIMER_STR)); //结构体清除}return -1;//定时器不存在,所以无法删除
}
说明:本程序是在学习的时候编写,适当参考网上代码,如涉及到版权问题,可以联系我。
最简单的51单片机软件定时器的编写相关推荐
- 【51单片机】定时器/计数器的工作原理和结构(一)
[51单片机]定时器/计数器的工作原理和结构 回看下单片机中断系统内部结构: 分析内部中断触发: 先看图 TCON:和外部中断相比少了IT位设置触发方式 :1跳沿触发 0电平触发:此处我的理解是:就好 ...
- 51单片机学习--定时器--中断--串口通信
51单片机学习–定时器–中断–串口通信 定时器–中断–串口通信 中断分类 定时器中断 外部中断 串口中断 基本概念 对于单片机来讲, 中断是指 CPU 在处理某一事件 A 时, 发生了另一事件 B, ...
- 51单片机计算定时器初值
51单片机计算定时器初值 前言 理论分析 工作方式寄存器 TMOD GATE 门控位 C/T' 计数器模式和定时器模式选择位 M1 M0 工作方式选择位 定时器/计数器控制寄存器 TCON TCON补 ...
- 关于用51单片机内部定时器实现时钟和闹钟功能的概述
关于用51单片机内部定时器实现时钟和闹钟功能的概述 仅个人观点,欢迎大家相互学习和讨论 STC89C52单片机,内部配置了三个定时器,T0\T1\T2,其中T2定时器我们几乎不用,或者说很少用到.我们 ...
- 单片机软件定时器的使用方法
单片机软件定时器的使用方法 特别声明:文章是原创但是本文讲述的思想是在国外的开源代码中借鉴的 初学者在编写单片机程序时经常会用到延时函数,但是当系统逐步复杂以后(没有复杂到使用操作系统)延时会因为延时 ...
- (六)51单片机基础——定时器
定时器介绍:51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成. 定时器主要作用: 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作. 替代长时间的Dela ...
- 51单片机之定时器\计数器的工作原理
51单片机之定时器\计数器的工作原理 定时器/计数器的结构: 何时处于计数器方式?何时处于定时器方式? TCON和TMOD特殊功能寄存器: 定时器/计数器工作方式: 方式0:13位的定时器/计数器 方 ...
- 三菱梯形图转换c语言软件,三菱梯形图转51单片机软件使用程序超过100步又要使用软件的朋友.pdf...
三菱梯形图转51单片机软件使用程序超过100步又要使用软件的朋友 三菱梯形图转51单片机软件使用 希望这个软件 能降低你的电气控制成本. 1:运行三菱软件,选择PLC型号为FX1N,画好梯形图并保存. ...
- 51单片机用定时器0实现流水灯
51单片机用定时器0实现流水灯的代码如下,用P1口接led灯,代码如下都有注释就不具体解释了,英语不怎么好,有的地方将就一下喽,本次主要讲一下P1口怎么赋值.原先写的都是用查表来移位的,个人感觉不怎么 ...
- 51单片机内部定时器/计数器实验
51单片机内部定时器/计数器实验 一.实验内容 使用MCS-51内部定时/计数器,定时1秒钟,CPU运用定时中断方式,实现每1秒钟输出状态发生一次反转,即发光管每隔1秒钟亮一次(P1.7接LED). ...
最新文章
- Oracle数据库表导出和导入csv文件操作
- Java 基础入门随笔(1) JavaSE版——java语言三种技术架构
- go基本语法:channel未关闭遍历结束后会报错deadlock
- python使用matplotlib绘制k线图
- PHP-CGI, FastCGI, PHP-FPM的关系和区别
- 32位hex转浮点 python_python——int()、hex()、oct()、bin()、float()数值类型转换函数
- ZigBee网络架构详解
- matlab界area_Matlab的数据科学界
- java安装和环境配置
- 动态规划实战篇--斐波那契数列
- 完全卸载VS 2015各版本
- OpenCV——LBP特征
- JavaScript笔记
- 生物医学数据统计分析-回归分析
- 计算机桌面壁纸被锁定,Win10桌面壁纸被锁定无法修改咋办? win10官网
- Windows7 64位安装EPLAN P8 2.6教程
- win8计算机休眠的区别,win8系统的休眠和睡眠有什么区别?如何用?
- opencv切割视频:把长视频切割成固定时间的短视频
- EasyExcel 固定(冻结)单元格
- win10+ubuntu双系统之三步彻底删除ubuntu系统
热门文章
- Prophet(预言者)facebook时序预测----论文总结以及调参思路
- (爱斯维尔期刊:遇到问题已解决) 使用elsarticle-harv的style引文格式时报错 mand\Nat@force@numbers{}\NAT@force@numbers
- TCGA数据库ensembl id 转为 gene Symbol,提取出需要的RNA种类表达谱列表信息
- 分享-IE游览器升级工具
- C语言 AES算法 加密解密
- 一些服务器常见漏洞的修复方法
- 扑克牌游戏“快算24”算法
- Kruise Rollout:灵活可插拔的渐进式发布框架
- mysql横切竖切_MySQL常用操作 - cheney-f的个人空间 - OSCHINA - 中文开源技术交流社区...
- 利用pandas进行数据分析