概述
原理
我们都知道单片机有定时器,但我们使用到多个需要定时的任务的时候,往往是在定时器中断中,加入定时时间以及标志,至少需要三个部分
- :用来计时的cnt
- :表示计时上限的定时时间
- :定时完成标志
传统写法如下:
void Timer1Handle() interrupt 3
{
if(timecnt < time)
timecnt++
else
{
timecnt = 0;
timecntOK = 1;
}
}
void process()
{
if(timecntOK)
{
timecntOK = 0;
//you process code
}
}
这种写法,运用到了定时器的特性,但是每创建一个定时器就需要3个变量,并且在写程序的时候,创建变量不是很方便。
于是经过一番思考,我想到了另外一个方法,使用一个timecnt,然后需要创建的定时器都和这个timecnt来进行对比从而进行定时。
首先贴上代码和效果(这个是在蓝桥杯板子上实验的,因此有些部分是板子上的,不用理会),我再解释
#include "STC15F2K60S2.h"
#include "stdio.h"
typedef unsigned char uchar;
typedef unsigned int uint;
#define OFF 1
#define ON 0
sbit BP = P0^6; sbit RL = P0^4;
#define BP(x) BP = x; P2 = P2 & 0x1f | 5 << 5; P2 = P2 & 0x1f
#define RL(x) RL = x; P2 = P2 & 0x1f | 5 << 5; P2 = P2 & 0x1f
//define
enum{LED = 4, EXT, SEL, CODE};
//time
#define ntime sizeof(Inc_time)/sizeof(Inc_time[0])
enum{T1, T2, T3, T4};
uint code Inc_time[] = {500, 1000, 1500, 2000};
uint time[ntime];
uint timecnt = 0;
//display
uchar digSel = 0;
uchar code CA[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99,
0x92, 0x82, 0xf8, 0x80, 0x90};
uchar Buffer[] = {1, 2, 3, 4, 5, 6, 7, 8};
sbit t1 = P1^0; sbit t2 = P1^7; sbit t3 = P1^2; sbit t4 = P1^3;
//key
sbit K1=P3^0; sbit K2=P3^1; sbit K3=P4^2; sbit K4=P3^3;
enum{KS_GT, KS_AS, KS_WD}keyState = KS_GT;
uchar keyCnt = 0, tempKey = 0, key = 0;
void Timer1Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x9A; //设置定时初值
TH1 = 0xA9; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
EA = 1;
}
void UartInit(void) //9600bps@11.0592MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = 0xE0; //设定定时初值
T2H = 0xFE; //设定定时初值
AUXR |= 0x10; //启动定时器2
ES = 0;
}
void SL(char da, char num)
{
P0 = da;
P2 = P2 & 0x1f | num << 5; P2 = P2 & 0x1f;
}
uchar GetKey()
{
if(K1 == 0) return 1;
else if (K2 == 0) return 2;
else if (K3 == 0) return 3;
else if (K4 == 0) return 4;
else return 0;
}
void Init(void)
{
uchar i = 0;
BP(ON);RL(ON);
SL(0xff, LED);
for(;i < ntime; i++)
{
time[i] = Inc_time[i];
}
}
void Timer1Handle() interrupt 3
{
SL(0xff, CODE);
SL(1 << digSel, SEL);
SL(CA[Buffer[digSel]], CODE);
digSel = (digSel +1)%8;
switch(keyState)
{
case KS_GT:
keyState = KS_AS;
keyCnt = 10;
tempKey = GetKey();
break;
case KS_AS:
if(keyCnt-- != 0);
else if(tempKey == GetKey())
{
if(tempKey != key)
{
key = tempKey;
keyState = KS_WD;
}
else
{
keyState = KS_GT;
}
}
else
keyState = KS_GT;
break;
}
{
uchar i;
for(i = 0;i < ntime; i++)
{
if((timecnt == 65535) || (timecnt == time[i]))
time[i] += Inc_time[i];
}
timecnt++;
}
}
void test1()
{
static uint Stime = 500;
if(Stime != time[T1])
{
Stime = time[T1];
TI = 1;
printf("t1rn");
t1 = ~t1;
}
}
void test2()
{
static uint Stime = 1000;
if(Stime != time[T2])
{
Stime = time[T2];
TI = 1;
printf("t2rn");
t2 = ~t2;
}
}
void test3()
{
static uint Stime = 1500;
if(Stime != time[T3])
{
Stime = time[T3];
TI = 1;
printf("t3rn");
t3 = ~t3;
}
}
void test4()
{
static uint Stime = 2000;
if(Stime != time[T4])
{
Stime = time[T4];
TI = 1;
printf("t4rn");
t4 = ~t4;
}
}
void main()
{
Init();
UartInit();
Timer1Init();
while(1)
{
test1();
test2();
test3();
test4();
}
}
效果
初始化部分
//time
#define ntime sizeof(Inc_time)/sizeof(Inc_time[0])
enum{T1, T2, T3, T4};
uint code Inc_time[] = {500, 1000, 1500, 2000};
uint time[ntime];
uint timecnt = 0;
//为了方便创建定时任务所增加改动的步骤减少,因此这里写一个赋值初始化函数
void Init(void)
{
uchar i = 0;
for(;i < ntime; i++)
{
time[i] = Inc_time[i];
}
}
定时器部分
void Timer1Handle() interrupt 3
{
uchar i;
for(i = 0;i < ntime; i++)
{
if((timecnt == 65535) || (timecnt == time[i]))
time[i] += Inc_time[i];
}
timecnt++;
}
流程图
也就是说有一个定时器在走,而且不会停,但是它有一个特点就是到了65535就会归0
这个时候有一个数组,里面装的都是定时的时间,然后每次定时器计数+1的时候,都会和这个数组里面的一一判断,当相同的时候,说明它定时的时间到达。并且当前数组元素的值要+它定时的值,以下次到达定时的时间。
因为65535归0的特性。如果当一个定时到达65535的时候,所有在数组中的元素都应该+它定时的值,这样才能保证每个定时任务的定时是完整的!
如果不理解,可以在纸上画一遍流程就知道为什么到达65535要将所有的数据都+它定时的值了
最后
以上就是凶狠茉莉为你收集整理的单片机定时任务的写法(单定时器多定时用法)(蓝桥杯单片机)原理的全部内容,希望文章能够帮你解决单片机定时任务的写法(单定时器多定时用法)(蓝桥杯单片机)原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复