加一计时器
2021-01-23,51单片机学习笔记
每隔1s六位数码管显示数字加1,直至999999,之后归零,重新开始。
代码:
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define ulint unsigned long int
sbit dula=P2^6;
sbit wela=P2^7;
uint num,num_set,n;//中断计次num,中断次数预设,中断服务初始化参数n
ulint disnum;
//欲显示的数字,因其最大值为999999,已经超过uint的范围(0~65535),这里采用ulint
uchar code table_du[]={
0x3f,0x06,0x5b,0x4f,0x66,0x6d,
0x7d,0x07,0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};//六位共阴极8段数码管段显编码
void display(ulint);//展示数字 声明
void delayms(uint); //延时函数 声明
void main()
{
n=50000;
num_set=20;
EA=1;
ET0=1;
TMOD=0x01;
TH0=(65536-n)/256;
TL0=(65536-n)%256;
TR0=1;
while(1)
{
if(num==num_set)//每间隔1s(=2*50ms),更新一次disnum
{
num=0;
if(disnum==1000000)//溢出回零
{
disnum=0;
}
disnum++;
}
display(disnum);//显示当前数字
}
}
//中断服务程序
void time0() interrupt 1
{
TH0=(65536-n)/256;
TL0=(65536-n)%256;
num++;//记录中断次数
//晶振f=12MHz,震荡周期=1/12um,机器周期=1us
//n=50000时,单次中断服务耗时50ms(=50000*1us)
}
void display(ulint disnum)
{
uint ms;//延时函数参数
ms=1;
if(disnum>=100000)//当欲显示数字大于 该位显示的最小值 时才点亮
{
P0=table_du[disnum/100000];//取十万位
dula=1;
dula=0;//段显锁存
P0=0xfe;//11 11 1110 (对应LED1(第一位数码管);LED1~6自左到右分布)
//位显编码(六位共阴极8段数码管,由P0口低六位控制,低电平时相应位点亮)
wela=1;
wela=0;//位显锁存
delayms(ms);
}
if(disnum>=10000)
{
P0=table_du[disnum%100000/10000];//取万位
dula=1;
dula=0;
P0=0xfd;//11 11 1101 (对应LED2)
wela=1;
wela=0;
delayms(ms);
}
if(disnum>=1000)
{
P0=table_du[disnum%100000%10000/1000];//取千位
dula=1;
dula=0;
P0=0xfb;//11 11 1011 (对应LED3)
wela=1;
wela=0;
delayms(ms);
}
if(disnum>=100)
{
P0=table_du[disnum%100000%10000%1000/100];//取百位
dula=1;
dula=0;
P0=0xf7;//11 11 0111 (对应LED4)
wela=1;
wela=0;
delayms(ms);
}
if(disnum>=10)
{
P0=table_du[disnum%100000%10000%1000%100/10];//取十位
dula=1;
dula=0;
P0=0xef;//11 10 1111 (对应LED5)
wela=1;
wela=0;
delayms(ms);
}
if(disnum>=0)
{
P0=table_du[disnum%100000%10000%1000%100%10];//取个位
dula=1;
dula=0;
P0=0xdf;//11 01 1111 (对应LED6)
wela=1;
wela=0;
delayms(ms);
}
}
void delayms(uint ms) //延时函数,ms=100时,延时约为100ms
{
uchar k;
while(ms--)
{
for(k = 0; k < 90; k++);
}
}
思考:
当间隔时间小到0.01s时,程序运行到if(num==num_set){...}
位置时,中断服务响应次数已经超过预设值,则不满足条件“num==num_set”,就无法执行后续语句,导致显示数值一直停留在某个数值。这时,将判断条件改为“num>=num_set”,就可以避免上述情况发生,但是,实际中断次数已经大于预设值,也造成了计时器的误差。这种误差会随着while循环次数的增加而累加。
这该如何解决呢?