按計劃,今天實現一個計數的功能,即按六個數碼管進行計數累加顯示,當右邊一位值超過9時,則進一位,如此類推。
最開始時想採用取餘的方式,一看一共有6個數碼管,最大可達999999,當到達這個值後清零從新開始計數。用uint16一共能到達65536,因爲用這個類型的變量不行,於是試了一個unsigned long,這個自然可以表示的數很大。於是按我思路編寫了一下代碼,滿以爲用取餘的方法,依次取出每一位再將其對應至數碼客中進行顯示即可,沒想到調了半天不行,後面發現這裏面的unsigned long是按16進制進行表示的,當我用到取餘時,其會將超過9的數,比如a,b,c等這些當成一位,比如對10取餘的話,則會取出a,b,c這樣的來,這樣的話,我的數碼管的進位表示就不是10進制的了,反而變成了16進制計數了,這自然不是我想要的。沒有辦法,自然只能放棄這種方法了,可能是我的單片機技術還不深入的原因,對一些細節不清楚,以爲只是編寫一個程序,沒想到以失敗告終。
於是只能用一般的方法,定義6個變量,以分別對應6個數碼管,當右邊一位超過9時,則在前面的一位加1,如此累加。滿以爲這下應該沒有問題了,可是卻很遺憾,數碼管顯示非常混亂,思考了半天,不得要領。想來可能是對單片機還不能安全掌握的緣故,因此只有暫時放棄,等後面再回過頭來再想想爲什麼會出現這樣的問題。
源代碼附上,等後面來解釋錯誤原因,以及如何進行改進。
#include <reg52.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
typedef unsigned long uint32;
uint8number[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
sbit ENLED = P1^4;
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
main()
{
uint8counter,j;
uint8num6,num5,num4,num3,num2,num1;
ENLED= 0; ADDR3=1;
ADDR0=0;ADDR1=0;ADDR2=0;
TMOD= 0X01;
TH0=0X4C;//設置計數器0的初始值,相應的有TH1,TL1。
TL0=0X00;
TR0=1;//計數器一開始計時
counter=0; //counter聲明時默認值爲0,不過此處明確賦初始值爲0會更明白些
j=0;
while(1)
{
if(TF0==1)//表示完成一次溢出
{
TF0=0; //由於本次未響應中斷,則要採用軟件清0的方式進行
TH0=0X4C;
TL0=0X00;
counter++;
}
if(counter ==20)//表示完成了20次溢出,花費時間就是一秒。
{
counter=0;
if(num1==9)
{
num1=0;
num2++;
}else
{
num1++;
}
if(num2==9)
{
num2=0;
num3++;
}else
{
num2++;
}
if(num3==9)
{
num3=0;
num4++;
}else
{
num3++;
}
if(num4==9)
{
num4=0;
num5++;
}else
{
num4++;
}
if(num2==9)
{
num2=0;
num3++;
}else
{
num1++;
}
if(num5==9)
{
num5=0;
num6++; if(num6==9&&num5==9&&num4==9&&num3==9&&num2==9&&num1==9)
{
num1=num2=num3=num4=num5=num6=0;
}
}else
{
num5++;
}
}
switch(j++)
{
case0:ADDR0=0;ADDR1=0;ADDR2=0;P0=number[num1];break;
case1:ADDR0=1;ADDR1=0;ADDR2=0;P0=number[num2];break;
case2:ADDR0=0;ADDR1=1;ADDR2=0;P0=number[num3];break;
case3:ADDR0=1;ADDR1=1;ADDR2=0;P0=number[num4];break;
case4:ADDR0=0;ADDR1=0;ADDR2=1;P0=number[num5];break;
case5:ADDR0=1;ADDR1=0;ADDR2=1;P0=number[num6];j=0;break;
default:break;
}
}
}