加一计时器——每隔1s六位数码管显示数字加1,直至999999,之后归零,重新开始。
作者:互联网
加一计时器
每隔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)
{ /**************************************************************************
此处,n=50000,num_set=20,时间间隔是:50000*1us*20=100ms=1s;
若要调整时间间隔,需要调整n和num_set,如:
(1)当n=50000,num_set=2时,时间间隔是:50000*1us*2=100ms=0.1s;
(2)当n=5000 ,num_set=2时,时间间隔是:5000 *1us*2=10ms=0.01s,
此时,同时需要将“if(num==num_set)”改为“if(num>=num_set)”,
否则数码管显示数字会出错!
【出现错误的原因可能是:程序运行到此处时,中断服务响应次数已经超过预设值,
这当然会对数码管显示值的精度造成影响!而且这种误差还会随着时间累加。
这一点是此代码的缺陷。】
同时,也要合理地调整延时函数的参数,以保证显示效果稳定。
如果延时时间不合理,就会造成显示时能够看出明显的闪烁。
***************************************************************************/
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循环次数的增加而累加。
这该如何解决呢?
标签:dula,wela,加一,set,P0,1s,999999,num,disnum 来源: https://blog.csdn.net/qq_46541463/article/details/113044793