這是樓主學習單片機時做的,很適合新手學習定時器和外部中斷時做參考。 左側為單片機最小系統,左上按鍵為復位鍵,右側P3口為兩個外部中斷,INT0為開始/暫停按鍵(用定時器控制),INT1為模式切換按鍵。
流水燈沒有用循環函數寫,其與定時器結合,可以用外部中斷INT0實時控制。
keil所有文件和proteus仿真都已上傳,程序注釋標的很清楚,適合新手學習。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
)5O%M(R34T9Z{6{(XNN7O8L.png (11.12 KB, 下載次數: 26)
下載附件
正向秒表
2018-11-30 18:27 上傳
}9U5L[H}99AAT3UCYOR85R1.png (11.04 KB, 下載次數: 33)
下載附件
逆向秒表
2018-11-30 18:27 上傳
QZ4Z6I0]IP%YJ[DC0R03$XR.png (5.79 KB, 下載次數: 36)
下載附件
實時可控流水燈
2018-11-30 18:28 上傳
7IF9}D2YRDGEU`Y6SK@O(8T.png (10.9 KB, 下載次數: 29)
下載附件
proteus仿真
2018-11-30 18:27 上傳
單片機正逆向秒表流水燈源程序如下:
- #include<reg51.h>
- #include"main.h"
- #include"delay.h"
- #define uchar unsigned char
- #define uint unsigned int
- unsigned long int g_unDisNum; //用于計數,從00000到99999
- unsigned long int g_unDisNum1; //用于計數,從99999到00000
- uchar i,K,m,g_ucNum;
- uint c=0;
- uchar code table[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; //流水燈顯示模式一
- uchar code table1[]={0x55,0xAA}; //流水燈顯示模式二
- uchar code table2[]={0x00,0xFF}; //流水燈顯示模式三
- uchar code DIS_CODE[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共陰極數碼管顯示代碼
- void disp_numu(unsigned long int num1) //數碼管顯示函數,顯示5位數字
- {
- uchar sep_num1=0;
- uchar ten_num1=0;
- uchar hund_num1=0;
- uchar thou_num1=0;
- uchar tent_num1=0;
-
- sep_num1=num1%10; //數碼管的個十百千萬位
- ten_num1=(num1%100)/10;
- hund_num1=(num1%1000)/100;
- thou_num1=(num1%10000)/1000;
- tent_num1=(num1%100000)/10000;
-
- P2=0xFE; //通過掃描的方式顯示
- P0=DIS_CODE[tent_num1];
- delay_ms(1);
- P2=0xFD;
- P0=DIS_CODE[thou_num1];
- delay_ms(1);
- P2=0xFB;
- P0=DIS_CODE[hund_num1];
- delay_ms(1);
- P2=0xF7;
- P0=DIS_CODE[ten_num1];
- delay_ms(1);
- P2=0xEF;
- P0=DIS_CODE[sep_num1];
- }
- void modea() //正序按秒從00000遞增至99999
- {
- if(g_ucNum>=200) //g_ucNum增至200正好1秒,將g_ucNum清零,g_unDisNum增1
- {
- g_ucNum=0;
- g_unDisNum++;
- }
- disp_numu(g_unDisNum);
- P1=0x00;
- }
- void modeb() //倒序按秒從99999遞減至00000
- {
- if(g_ucNum>=200) //g_ucNum增至200正好1秒,將g_ucNum清零,g_unDisNum1減1
- {
- g_ucNum=0;
- g_unDisNum1--;
- }
- disp_numu(g_unDisNum1);
- P1=0x00;
- }
- void mode1() //正序流水燈,為了實時暫停、開始流水燈,mode1mode2mode3mode4均采用定時器中斷的方式控制
- {
- P1=table[i%8];
- if(g_ucNum>=20)
- {
- g_ucNum=0;
- i++;
- }
- P2=0xFF; //清除右側數碼管余輝
-
- }
- void mode2() //倒序流水燈
- {
- P1=table[i%8];
- if(g_ucNum>=20)
- {
- g_ucNum=0;
- i--;
- }
- }
- void mode3() //混合亮滅流水燈
- {
- P1=table1[i%2];
- if(g_ucNum>=20)
- {
- g_ucNum=0;
- i++;
- }
- }
- void mode4() //全亮全滅流水燈
- {
- P1=table2[i%2];
- if(g_ucNum>=20)
- {
- g_ucNum=0;
- i++;
- }
- }
- void mode5() //初始狀態 數碼管88888二極管1111 1111
- { uchar m;
- for(m=0;m<10;m++)
- {
- P2=0xFE;
- P0=0x7F;
- delay_ms(2);
- P2=0xFD;
- P0=0x7F;
- delay_ms(2);
- P2=0xFB;
- P0=0x7F;
- delay_ms(2);
- P2=0xF7;
- P0=0x7F;
- delay_ms(2);
- P2=0xEF;
- P0=0x7F;
- delay_ms(2);
- P1=0x00;
- delay_ms(2);
- }
- }
- void int0_inter()interrupt 0 //INT0外部中斷,可暫停、開始所有的單片機狀態
- { if(c%2==0)
- {
- g_ucNum=0;
- TL0=0x18; //定時器賦初值TL0=(8192-5000)%32
- TH0=0x63; //THO=(8192-5000)/32
- TR0=1; //T0定時器計數
- c++; //通過參數c,用一個外部中斷按鍵開關定時器控制單片機的開始與暫停
- }
- else
- {
- TR0=0; //T0定時器計數停止計數
- c++; //通過參數c,用一個外部中斷按鍵開關定時器控制單片機的開始與暫停
- }
- }
- void timer0_inter()interrupt 1 //定時器中斷
- {
- g_ucNum++;
- TL0=0x18;
- TH0=0x63;
- }
- void int1_inter()interrupt 2 //INT1外部中斷,切換單片機狀態
- {
- if(!INT1)
- {
- delay_ms(2);
- if(!INT1)
- {
- K++;
- if(K==7)
- K=1;
- }
- while(!INT1);
- }
- }
- void main(void)
- {
- g_unDisNum=0; //正序秒表初值
- g_unDisNum1=99999; //逆序秒表初值
- g_ucNum=0; //定時計數初值
- P0=0xFF;
- P2=0xFF;
- P3=0xFF;
-
- IT0=1; //外部中斷0下降沿觸發
- IT1=1; //外部中斷1下降沿觸發
- EX0=1; //外部中斷0打開
- EX1=1; //外部中斷1打開
- TMOD=0; //定時器工作模式,工作方式0
- TL0=0x18; //定時器賦初值TL0=(8192-5000)%32
- TH0=0x63; //THO=(8192-5000)/32
- ET0=1; //打開T/C0溢出中斷
- EA=1; //打開全局中斷
- while(1)
- {
- switch(K)
- {
- case 1:modea();break;
- case 2:modeb();break;
- case 3:mode1();break;
- case 4:mode2();break;
- case 5:mode3();break;
- case 6:mode4();break;
- default:mode5();break;
- }
- }
- }
復制代碼
0.png (4.48 KB, 下載次數: 32)
下載附件
2018-11-30 19:19 上傳
所有資料51hei提供下載:
正逆向秒表流水燈.rar
(63.98 KB, 下載次數: 27)
2018-11-30 18:36 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|