加一計時器
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)
{ /**************************************************************************
此處,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回圈次數的增加而累加,
這該如何解決呢?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/252033.html
標籤:其他
