第一篇:51單片機脈沖產生程序設計
獨立鍵盤控制輸出脈沖信號
用51單片機用獨立鍵盤控制輸出4種頻率:1Hz、2Hz、10Hz、50Hz,占空比為50%的脈沖信號。
#include
#define uint unsigned int #define uchar unsigned char sbit d0=P1^0;sbit d1=P3^2;uintnum=0,counter=0;void delay(uint x){ uinti,j;for(i=x;i>0;i--)for(j=110;j>0;j--);} void main(){
d1=1;
d0=1;
d2=1;num=0;
IT0=1;
EX0=1;
TMOD=0x01;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
EA=1;
ET0=1;
TR0=1;while(1)
{
} } void Int0()interrupt 0 { delay(10);if(d1==0){
d1=1;num++;if(num==4)num=0;counter=0;}
} void Timer0(void)interrupt 1 {
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;counter++;
if(num==0){ if(counter<=500)
d0=0;if(counter>500)
d0=1;if(counter==1000)counter=0;
} if(num==1){ if(counter<=250)
d0=0;if(counter>250)d0=1;if(counter==500)counter=0;}
if(num==2){ if(counter<=50)d0=0;if(counter>50)d0=1;if(counter==100)counter=0;} if(num==3){ if(counter<=10)
d0=0;if(counter>10)
d0=1;
} if(counter==20)counter=0;}
第二篇:單片機-分支程序設計教案
一、復習上次課內容
1、什么是標識符?
答:標識符是程序員選擇的名字,用來標識常量、變量、過程、段名等。
2、什么是偽指令?
答:注釋性的,沒有對應的機器碼,不令計算機做任何操作,不產生目
標程序,不影響程序的執行。
二、講授新課
4.3分支程序設計
在很多實際問題中,都需要根據不同的情況進行不同的處理。這種
思想體現在程序設計中,就是根據不同條件而轉到不同的程序段去執行,這就構成了分支程序。分支程序的結構有兩種,如圖4.2所示。
圖4.2 分支程序結構
圖4.2(a)結構使用條件轉移指令來實現分支,當給出的條件成立時,執行程序段A,否則執行程序段B。
圖4.2(b)結構使用散轉指令JMP來實現多分支轉移,它首先將分支程序按序號的值來實現分支轉移。
分支程序的特點是改變程序的執行順序,跳過一些指令,去執行另外一些指令。應注意:對每一個分支都要單獨編寫一段程序,每一分支的開始地址賦給一個標號。
在編寫分支程序時,關鍵是如何判斷分支的條件。在MCS-51系列單片機中可以直接用來判斷分支條件的指令并不多,只有累加器為零(或不為零)、比較條件轉移指令CJNE等,MCS-51單片機還提供了位條件轉移指令,如JC,JB等。把這些指令結合在一起使用,就可以完成各種各樣的條件判斷。
【例4-5】設補碼X放在內部RAM30H單元中,函數Y與X有如下的關系式:
試編寫程序,根據X的值求出Y,并放回原單元。
解 取出X后先做取值范圍的判斷,用累加器A狀態轉移指令判斷X是否為0,用位狀態轉移指令判斷X是大于0還是小于0。程序流程圖如圖4.3所示。
程序如下:
MOV A,30H JZ ZER0 JNB ACC.7,PLUS
ADD A,#5 MOV 30H,A PLUS: SJMP $ ZERO: MOV 30H,#20H SJMP $ END 【例4-6】內部RAM40H和41H單元中各有一無符號數,比較其大小,將大數存放于內部RAM60H單元,小數存放于內部RAM61H單元,如兩數相等,則分別送往這2個單元。
解 用比較不等轉移指令CJNE比較力兩個無符號書,先確定它們是否相等,若不相等時再根據借位標志確定這兩個無符號書的大小。程序框圖如圖4.4所示。程序如下:
LOOP:
AGEQ:
SJMP END $
XCH MOV A,61H 60H,A
;A<(41H)有借位
;A與(61H)交換 MOV MOV CJNE AJMP JNC A,40H 61H,41H A,41H,LOOP AGEQ AGEQ
;A≥(41H)則無借位
【例4-8】將ASCII碼制轉換為十六進制數。如果不是十六進制數得ASCII碼,用戶標志位置1。解:由ASCII碼表知,30H~39H為0~9的ASCII碼,41H~46H為A~F的ASCII碼。在這一范圍的ASCII碼減去37H就可以獲得對應的十六進制。設ASCII碼放在累加器A中,轉換結果放回A中。程序流程圖如圖4.5所示
三、課堂鞏固
四、課堂小結
五、作業
第三篇:基于51單片機倒計時秒表程序設計
基于51單片機倒計時秒表程序設計
typedef unsigned char UINT8;typedef unsigned int UINT16;code UINT8 SEGMENT[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};code UINT8 SELECT[8] ={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};#define S1 0x0e #define S2 0x0d #define S3 0x0b #define S4 0x07 sbit SPEAK=P3^5;sbit P3_3=P3^3;UINT8 Second;
void timer_10ms(void)//定時器T0定時10ms {
TMOD=0x01;TH0=0xdc;TL0=0x32;TR0=1;//啟動T0 } void Delay(UINT16 t){
UINT16 i,j;
for(i=0;i for(j=0;j<114;j++);} void Display(void){ static UINT8 num=0;P2=0xff;switch(num){ case 0: P0=0xff; break; case 1: P0=0xff; break; case 2: P0=0xff; break; case 3: P0=0xff; break; case 4: P0=0xff; break; case 5: P0=0xff; break; case 6: P0=SEGMENT[Second%100/10]; break; case 7: P0=SEGMENT[Second%10]; break;} P2=SELECT[num];num++;num%=8;//if(num==8)num=0;} UINT8 Scankey(void){ UINT8 key;if((P3&0x0f)==0x0f) return(0xff);Delay(10); if((P3&0x0f)==0x0f) return(0xff);key=P3&0x0f;while((P3&0x0f)!=0x0f);return(key);} void main(){ UINT8 i; EA=1; //打開總中斷 EX1=0;//打開外部中斷1 IT1=1;TH0=0xdc;TL0=0x32;TR0=1;//啟動T0 ET0=1; Second=60;while(1) { Display(); Delay(2); i = Scankey(); if(i==S1)//啟動 { EA=1; } else if(i == S2)//暫停 { EA=0; } } } } void int_0()interrupt 1 { unsigned char z,aa; for(aa=59;aa>0;aa--){ for(z=0;z<50;z++) { P0=SEGMENT[aa/10]; P2=SELECT[3]; delay(5); //10ms P0=SEGMENT[aa%10]; P2=SELECT[4]; delay(5); //10ms } } } } 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 《單片機C語言程序設計實訓100例—基于8051+Proteus仿真》案例 第 01 篇 基礎程序設計 01 閃爍的LED /* 名稱:閃爍的LED */ #include void DelayMS(uint x){ uchar i;while(x--){ 說明:LED按設定的時間間隔閃爍 for(i=0;i<120;i++);} } //主程序 void main(){ } while(1){ } LED=~LED;DelayMS(150); 02 從左到右的流水燈 /* 名稱:從左到右的流水燈 說明:接在P0口的8個LED從左到右循環依次點亮,產生走馬燈效果 */ #include //延時 void DelayMS(uint x){ uchar i;while(x--){ for(i=0;i<120;i++);} } //主程序 void main(){ P0=0xfe; } 03 8只LED左右來回點亮 /* 名稱:8只LED左右來回點亮 說明:程序利用循環移位函數_crol_和_cror_形成來回滾動的效果 */ #include void DelayMS(uint x){ uchar i; while(x--){ } for(i=0;i<120;i++);while(1){ P0=_crol_(P0,1);//P0的值向左循環移動 DelayMS(150);} } //主程序 void main(){ uchar i;P2=0x01;while(1){ 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } } for(i=0;i<7;i++){ P2=_crol_(P2,1);//P2的值向左循環移動 DelayMS(150);} for(i=0;i<7;i++){ P2=_cror_(P2,1);//P2的值向右循環移動 } DelayMS(150);04 花樣流水燈 /* 名稱:花樣流水燈 說明:16只LED分兩組按預設的多種花樣變換顯示 */ #include 0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xe7,0xdb,0xbd,0x7e,0xbd,0xdb,0xe7,0xff,0xe7,0xc3,0x81,0x00,0x81,0xc3,0xe7,0xff, 0xaa,0x55,0x18,0xff,0xf0,0x0f,0x00,0xff,0xf8,0xf1,0xe3,0xc7,0x8f,0x1f,0x3f,0x7f, 0x7f,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xf8,0xff,0x00,0x00,0xff,0xff,0x0f,0xf0,0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe, 0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe, 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff };uchar code Pattern_P2[]= { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0xff, 0xe7,0xdb,0xbd,0x7e,0xbd,0xdb,0xe7,0xff,0xe7,0xc3,0x81,0x00,0x81,0xc3,0xe7,0xff, 0xaa,0x55,0x18,0xff,0xf0,0x0f,0x00,0xff,0xf8,0xf1,0xe3,0xc7,0x8f,0x1f,0x3f,0x7f, 0x7f,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xf8,0xff,0x00,0x00,0xff,0xff,0x0f,0xf0,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f, 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00, 0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 0x00,0xff,0x00,0xff,0x00,0xff,0x00,0xff };//延時 void DelayMS(uint x){ uchar i;while(x--){ } for(i=0;i<120;i++);} //主程序 void main(){ uchar i;while(1){ //從數組中讀取數據送至P0和P2口顯示 } for(i=0;i<136;i++){ } P0=Pattern_P0[i];P2=Pattern_P2[i];DelayMS(100);} 05 LED模擬交通燈 /* 名稱:LED模擬交通燈 說明:東西向綠燈亮若干秒,黃燈閃爍5次后紅燈亮,紅燈亮后,南北向由紅燈變為綠燈,若干秒后南北向黃燈閃爍5此后變紅燈,東西向變綠燈,如此重復。*/ #include //東西向燈 sbit YELLOW_A=P0^1;sbit GREEN_A=P0^2;sbit RED_B=P0^3; //南北向燈 sbit YELLOW_B=P0^4;sbit GREEN_B=P0^5;uchar Flash_Count=0,Operation_Type=1;//閃爍次數,操作類型變量 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 //延時 void DelayMS(uint x){ uchar i;while(x--)for(i=0;i<120;i++);} //交通燈切換 void Traffic_Light(){ switch(Operation_Type){ case 1: //東西向綠燈與南北向紅燈亮 RED_A=1;YELLOW_A=1;GREEN_A=0; RED_B=0;YELLOW_B=1;GREEN_B=1; DelayMS(2000); Operation_Type=2; break; case 2: //東西向黃燈閃爍,綠燈關閉 DelayMS(300); YELLOW_A=~YELLOW_A;GREEN_A=1; if(++Flash_Count!=10)return;//閃爍5次 Flash_Count=0; Operation_Type=3; break; case 3: //東西向紅燈,南北向綠燈亮 RED_A=0;YELLOW_A=1;GREEN_A=1; RED_B=1;YELLOW_B=1;GREEN_B=0; DelayMS(2000); Operation_Type=4; break; case 4: //南北向黃燈閃爍5次 DelayMS(300); YELLOW_B=~YELLOW_B;GREEN_B=1; if(++Flash_Count!=10)return; Flash_Count=0; Operation_Type=1;} } //主程序 void main(){ while(1)Traffic_Light();} 06 單只數碼管循環顯示0~9 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 /* 名稱:單只數碼管循環顯示0~9 */ #include void DelayMS(uint x){ uchar t;while(x--)for(t=0;t<120;t++);} //主程序 void main(){ } uchar i=0;P0=0x00;while(1){ } P0=~DSY_CODE[i];i=(i+1)%10;DelayMS(300);說明:主程序中的循環語句反復將0~9的段碼送至P0口,使數字0~9循環顯示 07 8只數碼管滾動顯示單個數字 /* 名稱:8只數碼管滾動顯示單個數字 說明:數碼管從左到右依次滾動顯示0~7,程序通過每次僅循環選通一只數碼管 */ #include void DelayMS(uint x){ uchar t;while(x--)for(t=0;t<120;t++);上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } //主程序 void main(){ uchar i,wei=0x80;while(1){ for(i=0;i<8;i++) { P2=0xff; //關閉顯示 wei=_crol_(wei,1); P0=DSY_CODE[i];//發送數字段碼 P2=wei; //發送位碼 DelayMS(300); } } } 08 8只數碼管動態顯示多個不同字符 電路如上圖 /* 名稱:8只數碼管動態顯示多個不同字符 說明:數碼管動態掃描顯示0~7。*/ #include void DelayMS(uint x){ uchar t;while(x--)for(t=0;t<120;t++);} //主程序 void main(){ uchar i,wei=0x80;while(1){ for(i=0;i<8;i++) { P0=0xff; P0=DSY_CODE[i];//發送段碼 wei=_crol_(wei,1);上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 P2=wei; //發送位碼 DelayMS(2); } } } 09 8只數碼管閃爍顯示數字串 電路如上圖 /* 名稱:8只數碼管閃爍顯示數字串 說明:數碼管閃爍顯示由0~7構成的一串數字 本例用動態刷新法顯示一串數字,在停止刷新時所有數字顯示消失。 */ #include uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//位碼表 uchar code DSY_IDX[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//延時 void DelayMS(uint x){ uchar t;while(x--)for(t=0;t<120;t++);} //主程序 void main(){ uchar i,j;while(1){ for(i=0;i<30;i++) { for(j=0;j<8;j++) { P0=0xff; P0=DSY_CODE[j];//發送段碼 P2=DSY_IDX[j];//發送位碼 DelayMS(2); } } P2=0x00; //關閉所有數碼管并延時 DelayMS(1000);} } 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 8只數碼管滾動顯示數字串 電路如上圖 /* 名稱:8只數碼管滾動顯示數字串 說明:數碼管向左滾動顯示3個字符構成的數字串 */ #include uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//下面數組看作環形隊列,顯示從某個數開始的8個數(10表示黑屏)uchar Num[]={10,10,10,10,10,10,10,10,2,9,8};//延時 void DelayMS(uint x){ uchar t;while(x--)for(t=0;t<120;t++);} //主程序 void main(){ uchar i,j,k=0,m=0x80;while(1){ //刷新若干次,保持一段時間的穩定顯示 for(i=0;i<15;i++) { for(j=0;j<8;j++) { //發送段碼,采用環形取法,從第k個開始取第j個 P0=0xff; P0=DSY_CODE[Num[(k+j)%11]]; m=_crol_(m,1); P2=m;//發送位碼 DelayMS(2); } } k=(k+1)%11;//環形隊列首支針k遞增,Num下標范圍0~10,故對11取余 } } K1-K4 控制LED移位 /* 名稱:K1-K4 控制LED移位 說明:按下K1時,P0口LED上移一位; 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 */ 按下K2時,P0口LED下移一位; 按下K3時,P2口LED上移一位; 按下K4時,P2口LED下移一位; #include void DelayMS(uint x){ uchar i;while(x--)for(i=0;i<120;i++);} //根據P1口的按鍵移動LED void Move_LED(){ if ((P1&0x10)==0)P0=_cror_(P0,1);//K1 else if((P1&0x20)==0)P0=_crol_(P0,1);//K2 else if((P1&0x40)==0)P2=_cror_(P2,1);//K3 //K4 else if((P1&0x80)==0)P2=_crol_(P2,1);} //主程序 void main(){ uchar Recent_Key;//最近按鍵 } P0=0xfe;P2=0xfe;P1=0xff;Recent_Key=0xff;while(1){ } if(Recent_Key!=P1){ } Recent_Key=P1; //保存最近按鍵 Move_LED();DelayMS(10);K1-K4 按鍵狀態顯示 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 /* 名稱:K1-K4 按鍵狀態顯示 說明:K1、K2按下時LED點亮,松開時熄滅,*/ #include void DelayMS(uint x){ uchar i;while(x--)for(i=0;i<120;i++); K3、K4按下并釋放時LED點亮,再次按下并釋放時熄滅; } //主程序 void main(){ } K1-K4 分組控制LED 上海師范大學信息與機電工程學院—倪繼鋒 P0=0xff;P1=0xff;while(1){ } LED1=K1;LED2=K2;if(K3==0){ while(K3==0);} LED3=~LED3;if(K4==0){ } while(K4==0);LED4=~LED4;DelayMS(10);《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 /* 名稱:K1-K4 分組控制LED 說明:每次按下K1時遞增點亮一只LED,全亮時再次按下則再次循環開始,K2按下后點亮上面4只LED,K3按下后點亮下面4只LED,K4按下后關閉所有LED */ #include void DelayMS(uint x){ uchar i;while(x--)for(i=0;i<120;i++);} //主程序 void main(){ uchar k,t,Key_State;P0=0xff;P1=0xff;while(1){ t=P1;if(t!=0xff){ DelayMS(10);if(t!=P1)continue;//取得4位按鍵值,由模式XXXX1111(X中有一位為0,其他均為1)//變為模式0000XXXX(X中有一位為1,其他均為0)Key_State=~t>>4;k=0;//檢查1所在位置,累加獲取按鍵號k while(Key_State!=0){ k++;Key_State>>=1;} //根據按鍵號k進行4種處理 switch(k){ case 1: if(P0==0x00)P0=0xff;P0<<=1;DelayMS(200);break;P0=0xf0;break;case 2: 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } } } } case 3: case 4: P0=0x0f;break;P0=0xff;14 K1-K4 控制數碼管移位顯示 /* 名稱:K1-K4 控制數碼管移位顯示 說明:按下K1時加1計數并增加顯示位,按下K2時減1計數并減少顯示位,按下K3時清零。 */ #include uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//位碼 uchar code DSY_Index[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};//待顯示到各數碼管的數字緩沖(開始僅在0位顯示0,其他黑屏)uchar Display_Buffer[]={0,10,10,10,10,10,10,10};//延時 void DelayMS(uint x){ uchar i;while(x--)for(i=0;i<120;i++);} void Show_Count_ON_DSY(){ uchar i;for(i=0;i<8;i++) { P0=0xff;P0=DSY_CODE[Display_Buffer[i]]; } P2=DSY_Index[i];DelayMS(2);} //主程序 void main(){ uchar i,Key_NO,Key_Counts=0;上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 P0=0xff;P1=0xff;P2=0x00;while(1){ } Show_Count_ON_DSY();P1=0xff;Key_NO=P1;//P1口按鍵狀態分別為K1-0xfe,K2-0xfd,K3-0xfb switch(Key_NO){ case 0xfe: Key_Counts++;if(Key_Counts>8)Key_Counts=8;Display_Buffer[Key_Counts-1]=Key_Counts;break;if(Key_Counts>0)Display_Buffer[--Key_Counts]=10;break;Display_Buffer[0]=0;for(i=1;i<8;i++)Display_Buffer[i]=10;Key_Counts=0;case 0xfd: case 0xfb: } //若鍵未釋放則僅刷新顯示,不進行鍵掃描 while(P1!=0xff)Show_Count_ON_DSY();} K1-K4 控制數碼管加減演示 /* 名稱:K1-K4 控制數碼管加減演示 說明:按下K1后加1計數,按下K2后減1計數,按下K3后清零。*/ #include uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//待顯示的3位緩沖 uchar Num_Buffer[]={0,0,0};//按鍵代碼,按鍵計數 uchar Key_Code,Key_Counts=0;//延時 void DelayMS(uint x){ 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 uchar i;while(x--)for(i=0;i<120;i++);} //顯示函數 void Show_Counts_ON_DSY(){ uchar i,j=0x01;Num_Buffer[2]=Key_Counts/100;Num_Buffer[1]=Key_Counts/10%10;Num_Buffer[0]=Key_Counts%10;for(i=0;i<3;i++){ j=_cror_(j,1); P0=0xff; P0=DSY_CODE[Num_Buffer[i]]; P2=j;DelayMS(1);} } //主程序 void main(){ uchar i;P0=0xff;P1=0xff;P2=0x00;Key_Code=0xff;while(1){ Show_Counts_ON_DSY(); P1=0xff; Key_Code=P1; //有鍵按下時,數碼管刷新顯示30次,該行代碼同時起到延時作用 if(Key_Code!=0xff) for(i=0;i<30;i++)Show_Counts_ON_DSY(); switch(Key_Code) { case 0xfe: if(Key_Counts<255)Key_Counts++; break; case 0xfd: if(Key_Counts>0)Key_Counts--; break; case 0xfb: Key_Counts=0; } Key_Code=0xff;} 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } 4X4矩陣鍵盤控制條形LED顯示 /* 名稱:4X4矩陣鍵盤控制條形LED顯示 說明:運行本例時,按下的按鍵值越大點亮的LED越多。*/ #include uchar code KeyCodeTable[]={0x11,0x12,0x14,0x18,0x21, 0x22,0x24,0x28,0x41,0x42,0x44,0x48,0x81,0x82,0x84,0x88};//延時 void DelayMS(uint x){ uchar i;while(x--)for(i=0;i<120;i++);} //鍵盤掃描 uchar Keys_Scan(){ uchar sCode,kCode,i,k;//低4位置0,放入4行 P1=0xf0;//若高4位出現0,則有鍵按下 if((P1&0xf0)!=0xf0){ DelayMS(2);if((P1&0xf0)!=0xf0){ sCode=0xfe;{ //行掃描碼初值 for(k=0;k<4;k++)//對4行分別進行掃描 P1=sCode;if((P1&0xf0)!=0xf0){ kCode=~P1;for(i=0;i<16;i++)//查表得到按鍵序號并返回 if(kCode==KeyCodeTable[i])上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } } return(i);else sCode=_crol_(sCode,1);} } return(-1);} //主程序 void main(){ uchar i,P2_LED,P3_LED;uchar KeyNo=-1;//按鍵序號,-1表示無按鍵 } while(1){ KeyNo=Keys_Scan();//掃描鍵盤獲取按鍵序號KeyNo if(KeyNo!=-1){ } } P2_LED=0xff;P3_LED=0xff;for(i=0;i<=KeyNo;i++)//鍵值越大,點亮的LED越多 { if(i<8)P3_LED>>=1;else P2_LED>>=1;} P3=P3_LED;//點亮條形LED P2=P2_LED;數碼管顯示4X4矩陣鍵盤按鍵號 /* 名稱:數碼管顯示4X4矩陣鍵盤按鍵號 說明:按下任意鍵時,數碼管都會顯示其鍵的序號,掃描程序首先判斷按鍵發生在哪一列,然后根據所發生的行附加不同的值,從而得到按鍵的序號。*/ 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 #include uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0x88,0x83,0xc6,0xa1,0x86,0x8e,0x00};sbit BEEP=P3^7;//上次按鍵和當前按鍵的序號,該矩陣中序號范圍0~15,16表示無按鍵 uchar Pre_KeyNo=16,KeyNo=16;//延時 void DelayMS(uint x){ uchar i;while(x--)for(i=0;i<120;i++);} //矩陣鍵盤掃描 void Keys_Scan(){ uchar Tmp;P1=0x0f;//高4位置0,放入4行 DelayMS(1);Tmp=P1^0x0f;//按鍵后0f變成0000XXXX,X中一個為0,3個仍為1,通過異或把3個1變為0,唯一的0變為1 switch(Tmp)//判斷按鍵發生于0~3列的哪一列 { case 1: KeyNo=0;break;case 2: KeyNo=1;break;case 4: KeyNo=2;break;case 8: KeyNo=3;break;default:KeyNo=16;//無鍵按下 } P1=0xf0; //低4位置0,放入4列 DelayMS(1);Tmp=P1>>4^0x0f;//按鍵后f0變成XXXX0000,X中有1個為0,三個仍為1;高4位轉移到低4位并異或得到改變的值 switch(Tmp)//對0~3行分別附加起始值0,4,8,12 { } case 1: case 2: case 4: case 8: KeyNo+=0;break;KeyNo+=4;break;KeyNo+=8;break;KeyNo+=12;} //蜂鳴器 void Beep()上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 { uchar i;for(i=0;i<100;i++){ } DelayMS(1);BEEP=~BEEP;BEEP=0;} //主程序 void main(){ P0=0x00; } BEEP=0;while(1){ } P1=0xf0;if(P1!=0xf0)Keys_Scan();//獲取鍵序號 if(Pre_KeyNo!=KeyNo){ } P0=~DSY_CODE[KeyNo];Beep();Pre_KeyNo=KeyNo;DelayMS(100);18 開關控制LED /* 名稱:開關控制LED 說明:開關S1和S2分別控制LED1和LED2。*/ #include while(1){ LED1=S1;上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } } LED2=S2;19 繼電器控制照明設備 /* 名稱:繼電器控制照明設備 說明:按下K1燈點亮,再次按下時燈熄滅 */ #include void DelayMS(uint ms){ uchar t;while(ms--)for(t=0;t<120;t++);} //主程序 void main(){ } 數碼管顯示撥碼開關編碼 /* 名稱:數碼管顯示撥碼開關編碼 */ #include } if(K1==0){ } while(K1==0);RELAY=~RELAY;DelayMS(20);說明:系統顯示撥碼開關所設置的編碼000~255 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 #define uint unsigned int //各數字的數碼管段碼(共陰) uchar code DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//顯示緩沖 uchar DSY_Buffer[3]={0,0,0};//延時 void DelayMS(uint ms){ uchar t;while(ms--)for(t=0;t<120;t++);} //主程序 void main(){ } uchar i,m,Num;P0=0xff;P2=0xff;while(1){ } m=0xfe;Num=P1;//讀取撥碼開關的值 DSY_Buffer[0]=Num/100;DSY_Buffer[1]=Num/10%10;DSY_Buffer[2]=Num%10;for(i=0;i<3;i++)//刷新顯示在數碼管上 { } m=_crol_(m,1);P2=m;P0=DSY_CODE[DSY_Buffer[i]];DelayMS(10);開關控制報警器 /* 名稱:開關控制報警器 說明:用K1開關控制報警器,程序控制P1.0輸出兩種不同頻率的聲音,模擬很逼真的報警效果 */ #include void Alarm(uchar t){ } void main(){ } 按鍵發音 /* 名稱:按鍵發音 說明:按下不同的按鍵會是SOUNDER發出不同頻率的聲音。本例使用延時函數實現不同頻率的聲音輸出,以后也可使用定時器 */ #include void DelayMS(uint x){ uchar t;SPK=0;while(1){ } if(K1==1){ } Alarm(90);Alarm(120);uchar i,j;for(i=0;i<200;i++){ } SPK=~SPK;for(j=0;j while(x--)for(t=0;t<120;t++);} //按周期t發音 void Play(uchar t){ 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 uchar i;for(i=0;i<100;i++){ BEEP=~BEEP; DelayMS(t);} BEEP=0;} void main(){ P1=0xff;BEEP=0;while(1){ if(K1==0)Play(1); if(K2==0)Play(2); if(K3==0)Play(3); if(K4==0)Play(4);} } 播放音樂 /* 名稱:播放音樂 說明:程序運行時播放生日快樂歌,未使用定時器中斷,所有頻率完全用延時實現 */ #include uchar code SONG_TONE[]={212,212,190,212,159,169,212,212,190,212,142,159,212,212,106,126,159,169,190,119,119,126,159,142,159,0};//生日快樂歌節拍表,節拍決定每個音符的演奏長短 uchar code SONG_LONG[]={9,3,12,12,12,24,9,3,12,12,12,24,9,3,12,12,12,12,12,9,3,12,12,12,24,0};//延時 void DelayMS(uint x){ uchar t;while(x--)for(t=0;t<120;t++);} //播放函數 void PlayMusic(){ 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } uint i=0,j,k;while(SONG_LONG[i]!=0||SONG_TONE[i]!=0){ //播放各個音符,SONG_LONG為拍子長度 } for(j=0;j } DelayMS(10);i++;BEEP=~BEEP;//SONG_TONE延時表決定了每個音符的頻率 for(k=0;k } BEEP=0;while(1){ } PlayMusic();//播放生日快樂 DelayMS(500);//播放完后暫停一段時間 INT0中斷計數 /* 名稱:INT0中斷計數 說明:每次按下計數鍵時觸發INT0中斷,中斷程序累加計數,計數值顯示在3只數碼管上,按下清零鍵時數碼管清零 */ #include uchar code DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};//計數值分解后各個待顯示的數位 uchar DSY_Buffer[]={0,0,0};uchar Count=0;sbit Clear_Key=P3^6;//數碼管上顯示計數值 void Show_Count_ON_DSY(){ DSY_Buffer[2]=Count/100;//獲取3個數 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 DSY_Buffer[1]=Count%100/10;DSY_Buffer[0]=Count%10;if(DSY_Buffer[2]==0) //高位為0時不顯示 { } P0=DSY_CODE[DSY_Buffer[0]];P1=DSY_CODE[DSY_Buffer[1]];DSY_Buffer[2]=0x0a;if(DSY_Buffer[1]==0) //高位為0,若第二位為0同樣不顯示 DSY_Buffer[1]=0x0a;P2=DSY_CODE[DSY_Buffer[2]];} //主程序 void main(){ P0=0x00;P1=0x00;P2=0x00;IE=0x81;//允許INT0中斷 IT0=1;//下降沿觸發 while(1){ if(Clear_Key==0)Count=0;//清0 Show_Count_ON_DSY();} } //INT0中斷函數 void EX_INT0()interrupt 0 { Count++;//計數值遞增 } 外部INT0中斷控制LED /* 名稱:外部INT0中斷控制LED 說明:每次按鍵都會觸發INT0中斷,中斷發生時將LED狀態取反,產生LED狀態由按鍵控制的效果 */ #include { LED=1;EA=1;EX0=1;IT0=1;while(1);} //INT0中斷函數 void EX_INT0()interrupt 0 { } INT0及INT1中斷計數 /* 名稱:INT0及INT1中斷計數 說明:每次按下第1個計數鍵時,第1組計數值累加并顯示在右邊3只數碼管上,每次按下第2個計數鍵時,第2組計數值累加并顯示在左邊3只數碼管上,后兩個按鍵分別清零。*/ #include uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};uchar code DSY_Scan_Bits[]={0x20,0x10,0x08,0x04,0x02,0x01};//2組計數的顯示緩沖,前3位一組,后3位一組 uchar data Buffer_Counts[]={0,0,0,0,0,0};uint Count_A,Count_B=0;//延時 void DelayMS(uint x){ uchar t;while(x--)for(t=0;t<120;t++);LED=~LED;//控制LED亮滅 } //數據顯示 void Show_Counts(){ uchar i;Buffer_Counts[2]=Count_A/100;Buffer_Counts[1]=Count_A%100/10;Buffer_Counts[0]=Count_A%10;上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 if(Buffer_Counts[2]==0){ Buffer_Counts[2]=0x0a;if(Buffer_Counts[1]==0) Buffer_Counts[1]=0x0a;} Buffer_Counts[5]=Count_B/100;Buffer_Counts[4]=Count_B%100/10;Buffer_Counts[3]=Count_B%10;if(Buffer_Counts[5]==0){ Buffer_Counts[5]=0x0a; if(Buffer_Counts[4]==0) Buffer_Counts[4]=0x0a;} for(i=0;i<6;i++){ P2=DSY_Scan_Bits[i]; P1=DSY_CODE[Buffer_Counts[i]];DelayMS(1);} } //主程序 void main(){ IE=0x85;PX0=1;//中斷優先 IT0=1;IT1=1;while(1){ if(K3==0)Count_A=0; if(K4==0)Count_B=0; Show_Counts();} } //INT0中斷函數 void EX_INT0()interrupt 0 { Count_A++; } //INT1中斷函數 void EX_INT1()interrupt 2 { Count_B++; 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } 定時器控制單只LED /* 名稱:定時器控制單只LED 說明:LED在定時器的中斷例程控制下不斷閃爍。*/ #include void main(){ TMOD=0x00; //定時器0工作方式0 TH0=(8192-5000)/32;//5ms定時 TL0=(8192-5000)%32;IE=0x82;//允許T0中斷 TR0=1;while(1);} //T0中斷函數 void LED_Flash()interrupt 1 { } TH0=(8192-5000)/32;//恢復初值 TL0=(8192-5000)%32;if(++T_Count==100)//0.5s開關一次LED { } LED=~LED;T_Count=0;TIMER0控制流水燈 /* 名稱:TIMER0控制流水燈 說明:定時器控制P0、P2口的LED滾動顯示,本例未使用中斷函數。*/ #include //主程序 void main(){ uchar T_Count=0;P0=0xfe;P2=0xfe;TMOD=0x01; TH0=(65536-40000)/256; //定時器0工作方式1 //40ms定時 TL0=(65536-40000)%256;TR0=1; //啟動定時器 while(1){ if(TF0==1) { } TF0=0;TH0=(65536-40000)/256;//恢復初值 TL0=(65536-40000)%256;if(++T_Count==5){ } P0=_crol_(P0,1);P2=_crol_(P2,1);T_Count=0;} } 定時器控制4個LED滾動閃爍 /* 名稱:定時器控制4個LED滾動閃爍 說明:4只LED在定時器控制下滾動閃爍。*/ #include 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 TMOD=0x02; TH0=256-200;TL0=256-200;IE=0x82;TR0=1;//定時器0工作方式2 //200us定時 //啟動定時器 while(1);} //T0中斷函數 void LED_Flash_and_Scroll()interrupt 1 { if(++k<35)k=0;switch(i){ case 0: case 1: case 2: B1=~B1;break;G1=~G1;break;R1=~R1;break;return; //定時中斷若干次后執行閃爍 case 3: Y1=~Y1;break;default:i=0;} if(++j<300)return;//每次閃爍持續一段時間 j=0;P0=0xff;//關閉顯示 i++;//切換到下一個LED } T0控制LED實現二進制計數 /* 名稱:T0控制LED實現二進制計數 說明:本例對按鍵的計數沒有使用查詢法,沒有使用外部中斷函數,沒有使用定時或計數中斷函數。而是啟用了計數器,連接在T0引腳的按鍵每次按下時,會使計數寄存器的值遞增,其值通過LED以二進制形式顯示 */ #include void main(){ TMOD=0x05;//定時器0為計數器,工作方式1,最大計數值65535 TH0=0;//初值為0 TL0=0;TR0=1;while(1)上海師范大學信息與機電工程學院—倪繼鋒 //啟動定時器 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 { } P1=TH0;P2=TL0;} TIMER0與TIMER1控制條形LED /* 名稱:TIMER0與TIMER1控制條形LED 說明:定時器T0定時控制上一組條形LED,滾動速度較快 定時器T1定時控制下一組條形LED,滾動速度較慢 */ #include TH0=(65536-15000)/256; //定時器0:15ms //定時器1:50ms TL0=(65536-15000)%256;TH1=(65536-50000)/256;TL1=(65536-50000)%256;IE=0x8a;TR0=1;//啟動定時器 TR1=1;while(1);} //T0中斷函數 void Time0()interrupt 1 { TH0=(65536-15000)/256; //恢復定時器0初值 TL0=(65536-15000)%256;if(++tc0==10) //150ms轉換狀態 { tc0=0;P0=_crol_(P0,1);} } //T1中斷函數 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 void Time1()interrupt 3 { TH0=(65536-50000)/256; } 10s的秒表 //恢復定時器1初值 TL0=(65536-50000)%256;if(++tc1==10) //500ms轉換狀態 { } tc1=0;P2=_crol_(P2,1); /* 名稱:10s的秒表 說明:首次按鍵計時開始,再次按鍵暫停,第三次按鍵清零。*/ #include void DelayMS(uint ms){ uchar t;while(ms--)for(t=0;t<120;t++);} //處理按鍵事件 void Key_Event_Handle(){ if(Key_State==0){ Key_Flag_Idx=(Key_Flag_Idx+1)%3;switch(Key_Flag_Idx){ } case 1: case 2: case 0: EA=1;ET0=1;TR0=1;break;EA=0;ET0=0;TR0=0;break;P0=0x3f;P2=0x3f;i=0;Second_Counts=0; 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } } //主程序 void main(){ P0=0x3f;//顯示00 P2=0x3f;i=0;Second_Counts=0; Key_Flag_Idx=0; //按鍵次數(取值0,1,2,3) Key_State=1; //按鍵狀態 TMOD=0x01;//定時器0方式1 TH0=(65536-50000)/256; //定時器0:15ms TL0=(65536-50000)%256;while(1){ if(Key_State!=K1) { DelayMS(10); Key_State=K1; Key_Event_Handle();} } } //T0中斷函數 void DSY_Refresh()interrupt 1 { TH0=(65536-50000)/256;//恢復定時器0初值 TL0=(65536-50000)%256;if(++i==2) //50ms*2=0.1s轉換狀態 { i=0; Second_Counts++; P0=DSY_CODE[Second_Counts/10]; P2=DSY_CODE[Second_Counts%10]; if(Second_Counts==100)Second_Counts=0; //滿100(10s)后顯示00 } } 用計數器中斷實現100以內的按鍵計數 /* 名稱:用計數器中斷實現100以內的按鍵計數 說明:本例用T0計數器中斷實現按鍵技術,由于計數寄存器初值為1,因此 P3.4引腳的每次負跳變都會觸發T0中斷,實現計數值累加。 計數器的清零用外部中斷0控制。 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 */ #include code DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};uchar Count=0;//主程序 void main(){ P0=0x00; //計數器T0方式2 //計數值為1 //允許T0中斷 //允許INT0中斷 //允許CPU中斷 P2=0x00;TMOD=0x06;TH0=TL0=256-1;ET0=1; EX0=1; EA=1; IP=0x02;IT0=1;TR0=1;while(1){ //設置優先級,T0高于INT0 //INT0中斷觸發方式為下降沿觸發 //啟動T0 P0=DSY_CODE[Count/10];P2=DSY_CODE[Count%10];} } //T0計數器中斷函數 void Key_Counter()interrupt 1 { Count=(Count+1)%100;//因為只有兩位數碼管,計數控制在100以內(00~99)} //INT0中斷函數 void Clear_Counter()interrupt 0 { } Count=0; 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 100 000s以內的計時程序 /* 名稱:100 000s以內的計時程序 說明:在6只數碼管上完成0~99 999.9s。*/ #include code DSY_CODE[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//6只數碼管上顯示的數字 uchar Digits_of_6DSY[]={0,0,0,0,0,0};uchar Count;sbit Dot=P0^7;//延時 void DelayMS(uint ms){ uchar t;while(ms--)for(t=0;t<120;t++);} //主程序 void main(){ uchar i,j;P0=0x00;P3=0xff; Count=0;TMOD=0x01; TH0=(65536-50000)/256; //計數器T0方式1 //50ms定時 TL0=(65536-50000)%256;IE=0x82;TR0=1; //啟動T0 while(1){ j=0x7f;//顯示Digits_of_6DSY[5]~Digits_of_6DSY[0]的內容 //前面高位,后面低位,循環中i!=-1亦可寫成i!=0xff for(i=5;i!=-1;i--){ j=_crol_(j,1); 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 P3=j;P0=DSY_CODE[Digits_of_6DSY[i]];if(i==1)Dot=1;//加小數點 DelayMS(2); } } } //T0中斷函數 void Timer0()interrupt 1 { uchar i;TH0=(65536-50000)/256;TL0=(65536-50000)%256;if(++Count!=2)return;Count=0;Digits_of_6DSY[0]++;//0.1s位累加 for(i=0;i<=5;i++)//進位處理 { if(Digits_of_6DSY[i]==10){ Digits_of_6DSY[i]=0;if(i!=5)Digits_of_6DSY[i+1]++; //如果0~4位則分別向高一位進位 //若某低位沒有進位,怎循環提前結束 //恢復初值 } else break;} } 定時器控制數碼管動態顯示 /* 名稱:定時器控制數碼管動態顯示 說明:8個數碼管上分兩組動態顯示年月日與時分秒,本例的位顯示延時用定時器實現。*/ #include uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};//待顯示的數據:09-12-25與23-59-58(分兩組顯示) uchar code Table_of_Digits[][8]={{0,9,10,1,2,10,2,5},{2,3,10,5,9,10,5,8}};uchar i,j=0; 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 uint t=0;//主程序 void main(){ P3=0x80; //位碼初值 TMOD=0x00; //計數器T0方式0 TH0=(8192-4000)/32;//4ms定時 TL0=(8192-4000)%32;IE=0x82;TR0=1; //啟動T0 while(1);} //T0中斷函數控制數碼管刷新顯示 void DSY_Show()interrupt 1 { TH0=(8192-4000)/32;//恢復初值 TL0=(8192-4000)%32;P0=0xff; //輸出位碼和段碼 P0=DSY_CODE[Table_of_Digits[i][j]];P3=_crol_(P3,1); j=(j+1)%8; //數組第i行的下一字節索引 if(++t!=350)return;//保持刷新一段時間 t=0;i=(i+1)%2; //數組行i=0時顯示年月日,i=1時顯示時分秒 } 8X8LED點陣顯示數字 /* 名稱:8X8LED點陣顯示數字 說明:8X8LED點陣屏循環顯示數字0~9,刷新過程由定時器中斷完成。*/ #include 0x00,0x3e,0x41,0x41,0x41,0x3e,0x00,0x00, 0x00,0x00,0x00,0x21,0x7f,0x01,0x00,0x00, 0x00,0x27,0x45,0x45,0x45,0x39,0x00,0x00, 0x00,0x22,0x49,0x49,0x49,0x36,0x00,0x00, 0x00,0x0c,0x14,0x24,0x7f,0x04,0x00,0x00,//0 //1 //2 //3 //4 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 0x00,0x72,0x51,0x51,0x51,0x4e,0x00,0x00, 0x00,0x3e,0x49,0x49,0x49,0x26,0x00,0x00, 0x00,0x40,0x40,0x40,0x4f,0x70,0x00,0x00, 0x00,0x36,0x49,0x49,0x49,0x36,0x00,0x00,//5 //6 //7 //8 //9 0x00,0x32,0x49,0x49,0x49,0x3e,0x00,0x00 };uchar i=0,t=0,Num_Index;//主程序 void main(){ P3=0x80; Num_Index=0;TMOD=0x00; //從0開始顯示 //T0方式0 //2ms定時 TH0=(8192-2000)/32;TL0=(8192-2000)%32;IE=0x82;TR0=1; //啟動T0 while(1);} //T0中斷函數 void LED_Screen_Display()interrupt 1 { TH0=(8192-2000)/32;//恢復初值 } 按鍵控制8X8LED點陣屏顯示圖形 /* 名稱:按鍵控制8X8LED點陣屏顯示圖形 說明:每次按下K1時,會使8X8LED點陣屏循環顯示不同圖形。 本例同時使用外部中斷和定時中斷。*/ #include 上海師范大學信息與機電工程學院—倪繼鋒 TL0=(8192-2000)%32;P0=0xff; //輸出位碼和段碼 P0=~Table_of_Digits[Num_Index*8+i];P3=_crol_(P3,1); if(++i==8)i=0; //每屏一個數字由8個字節構成 if(++t==250){ } //每個數字刷新顯示一段時間 t=0;if(++Num_Index==10)Num_Index=0;//顯示下一個數字 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 #include uchar code M[][8]= { {0x00,0x7e,0x7e,0x7e,0x7e,0x7e,0x7e,0x00}, //圖1 {0x00,0x38,0x44,0x54,0x44,0x38,0x00,0x00}, //圖2 {0x00,0x20,0x30,0x38,0x3c,0x3e,0x00,0x00} //圖3 };uchar i,j;//主程序 void main(){ P0=0xff;P1=0xff; TMOD=0x01; //T0方式1 TH0=(65536-2000)/256;//2ms定時 TL0=(65536-2000)%256;IT0=1; //下降沿觸發 IE=0x83; //允許定時器0、外部0中斷 i=0xff;//i的初值設為0xff,加1后將從0開始 while(1);} //T0中斷控制點陣屏顯示 void Show_Dot_Matrix()interrupt 1 { TH0=(65536-2000)/256;//恢復初值 TL0=(65536-2000)%256;P0=0xff; //輸出位碼和段碼 P0=~M[i][j];P1=_crol_(P1,1); j=(j+1)%8;} //INT0中斷(定時器由鍵盤中斷啟動)void Key_Down()interrupt 0 { P0=0xff;P1=0x80;j=0;i=(i+1)%3; //i在0,1,2中取值,因為只要3個圖形 TR0=1;} 用定時器設計的門鈴 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 /* 名稱:用定時器設計的門鈴 */ #include DoorBell=0;TMOD=0x00;//T0方式0 說明:按下按鍵時蜂鳴器發出叮咚的門鈴聲。 TH0=(8192-700)/32;//700us定時 TL0=(8192-700)%32;IE=0x82;while(1){ if(Key==0){ //按下按鍵啟動定時器 TR0=1;while(Key==0); } } } //T0中斷控制點陣屏顯示 void Timer0()interrupt 1 { DoorBell=~DoorBell;p++;if(p<400) //若需要拖長聲音,可以調整400和800 { } { } else { TR0=0; 上海師范大學信息與機電工程學院—倪繼鋒 TH0=(8192-700)/32;//700us定時 TL0=(8192-700)%32; else if(p<800)TH0=(8192-1000)/32;//1ms定時 TL0=(8192-1000)%32;《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } } p=0;39 演奏音階 /* 名稱:演奏音階 說明:本例使用定時器演奏一段音階,播放由K1控制。*/ #include //音符索引 //14個音符放在方式2下的定時寄存器(TH0,TL0) uchar code HI_LIST[]={0,226,229,232,233,236,238,240,241,242,244,245,246,247,248};uchar code LO_LIST[]={0,4,13,10,20,3,8,6,2,23,5,26,1,4,3};//定時器0中斷函數 void T0_INT()interrupt 1 { TL0=LO_LIST[i];TH0=HI_LIST[i];SPK=~SPK;} //延時 void DelayMS(uint ms){ uchar t;while(ms--)for(t=0;t<120;t++);} //主程序 void main(){ TMOD=0x00;IE=0x82;SPK=0;while(1){ //T0方式0 while(K1==1);while(K1==0);for(i=1;i<15;i++){ //未按鍵等待 //等待釋放 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } } } TR0=1; DelayMS(500);TR0=0;DelayMS(50); //播放一個音符 //播放延時 按鍵控制定時器選播多段音樂 /* 名稱:按鍵控制定時器選播多段音樂 說明:本例內置3段音樂,K1可啟動停止音樂播放,K2用于選擇音樂段。*/ #include sbit SPK=P3^7;//播放和停止鍵 //蜂鳴器 //當前音樂段索引,音符索引 uchar Song_Index=0,Tone_Index=0;//數碼管段碼表 uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//標準音符頻率對應的延時表 uchar code HI_LIST[]={0,226,229,232,233,236,238,240,241,242,244,245,246,247,248};uchar code LO_LIST[]={0,4,13,10,20,3,8,6,2,23,5,26,1,4,3};//三段音樂的音符 uchar code Song[][50]= { {1,2,3,1,1,2,3,1,3,4,5,3,4,5,5,6,5,3,5,6,5,3,5,3,2,1,2,1,-1}, {3,3,3,4,5,5,5,5,6,5,3,5,3,2,1,5,6,53,3,2,1,1,-1}, {3,2,1,3,2,1,1,2,3,1,1,2,3,1,3,4,5,3,4,5,5,6,5,3,5,3,2,1,3,2,1,1,-1} };//三段音樂的節拍 uchar code Len[][50]= { {1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,2,1,2,-1}, {1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,2,2,-1}, {1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,1,1,1,1,1,2,1,1,2,2,-1} };//外部中斷0 void EX0_INT()interrupt 0 { TR0=0;//播放結束或者播放中途切換歌曲時停止播放 Song_Index=(Song_Index+1)%3;//跳到下一首的開頭 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 Tone_Index=0;P2=DSY_CODE[Song_Index]; //數碼管顯示當前音樂段號 } //定時器0中斷函數 void T0_INT()interrupt 1 { TL0=LO_LIST[Song[Song_Index][Tone_Index]];TH0=HI_LIST[Song[Song_Index][Tone_Index]];SPK=~SPK;} //延時 void DelayMS(uint ms){ uchar t;while(ms--)for(t=0;t<120;t++);} //主程序 void main(){ P2=0xc0;SPK=0;TMOD=0x00; //T0方式0 IE=0x83;IT0=1;IP=0x02;while(1){ while(K1==1);//未按鍵等待 while(K1==0); //等待釋放 TR0=1; //開始播放 Tone_Index=0;//從第0個音符開始 //播放過程中按下K1可提前停止播放(K1=0)。 //若切換音樂段會觸發外部中斷,導致TR0=0,播放也會停止 while(Song[Song_Index][Tone_Index]!=-1&&K1==1&&TR0==1) { DelayMS(300*Len[Song_Index][Tone_Index]);//播放延時(節拍) Tone_Index++;//當前音樂段的下一音符索引 } TR0=0; //停止播放 while(K1==0);//若提前停止播放,按鍵未釋放時等待 } } 定時器控制交通指示燈 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 /* 名稱:定時器控制交通指示燈 說明:東西向綠燈亮5s后,黃燈閃爍,閃爍5次亮紅燈,紅燈亮后,南北向由紅燈變成綠燈,5s后南北向黃燈閃爍,閃爍5次后亮紅燈,東西向綠燈亮,如此往復。 */ #include uchar Time_Count=0,Flash_Count=0,Operation_Type=1;//定時器0中斷函數 void T0_INT()interrupt 1 { TL0=-50000/256;TH0=-50000%256;switch(Operation_Type){ case 1: //東西向綠燈與南北向紅燈亮5s RED_A=0;YELLOW_A=0;GREEN_A=1;RED_B=1;YELLOW_B=0;GREEN_B=0;if(++Time_Count!=100)return;//5s(100*50ms)切換 Time_Count=0;Operation_Type=2;break;//東西向黃燈開始閃爍,綠燈關閉 if(++Time_Count!=8)return;Time_Count=0;YELLOW_A=~YELLOW_A;GREEN_A=0;if(++Flash_Count!=10)return;//閃爍 Flash_Count=0;Operation_Type=3;break; //東西向紅燈與南北向綠燈亮5s RED_A=1;YELLOW_A=0;GREEN_A=0;RED_B=0;YELLOW_B=0;GREEN_B=1;if(++Time_Count!=100)return;//5s(100*50ms)切換 Time_Count=0;Operation_Type=4; 上海師范大學信息與機電工程學院—倪繼鋒 case 2: case 3: 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } case 4: break;//南北向黃燈開始閃爍,綠燈關閉 if(++Time_Count!=8)return;Time_Count=0;YELLOW_B=~YELLOW_B;GREEN_A=0;if(++Flash_Count!=10)return;//閃爍 Flash_Count=0;Operation_Type=1;break; } //主程序 void main(){ } 報警與旋轉燈 /* 名稱:報警與旋轉燈 說明:定時器控制報警燈旋轉顯示,并發出仿真警報聲。*/ #include void DelayMS(uint ms){ } //INT0中斷函數 void EX0_INT()interrupt 0 { TR0=~TR0;//開啟或停止兩定時器,分別控制報警器的聲音和LED旋轉 TR1=~TR1;if(P2==0x00) 上海師范大學信息與機電工程學院—倪繼鋒 TMOD=0x01;IE=0x82;TR0=1;while(1); //T0方式1 uchar i;while(ms--)for(i=0;i<120;i++);《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 P2=0xe0;//開3個旋轉燈 else P2=0x00;//關閉所有LED } //定時器0中斷 void T0_INT()interrupt 1 { TH0=0xfe;TL0=FRQ;SPK=~SPK;} //定時器1中斷 void T1_INT()interrupt 3 { TH1=-45000/256;TL1=-45000%256;P2=_crol_(P2,1);} //主程序 void main(){ } 串行數據轉換為并行數據 /* 名稱:串行數據轉換為并行數據 說明:串行數據由RXD發送給串并轉換芯片74164,TXD則用于輸出移位時鐘脈沖,74164將串行輸入的1字節轉換為并行數據,并將轉換的數據通過8只LED顯示出來。本例串口工作模式0,即移位寄存器I/O模式。*/ 上海師范大學信息與機電工程學院—倪繼鋒 P2=0x00;SPK=0x00;TMOD=0x11;TH0=0x00;TL0=0xff;IT0=1;IE=0x8b;IP=0x01;TR0=0;TR1=0;while(1){ } FRQ++;DelayMS(1);//T0、T1方式1 //開啟0,1,3號中斷 //INT0設為最高優先 //定時器啟停由INT0控制,初始關閉 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 #include void DelayMS(uint ms){ uchar i;while(ms--)for(i=0;i<120;i++);} //主程序 void main(){ } uchar c=0x80;SCON=0x00;TI=1;while(1){ } c=_crol_(c,1);SBUF=c;while(TI==0);TI=0; DelayMS(400);//串口模式0,即移位寄存器輸入/輸出方式 //等待發送結束 //TI軟件置位 并行數據轉換為串行數據 /* 名稱:并行數據轉換為串行數據 說明:切換連接到并串轉換芯片74LS165的撥碼開關,該芯片將并行數據以串行方式發送到8051的RXD引腳,移位脈沖由TXD提供,顯示在P0口。*/ #include void DelayMS(uint ms){ 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 uchar i;while(ms--)for(i=0;i<120;i++);} //主程序 void main(){ SCON=0x10; } while(1){ } SPL=0;//置數(load),讀入并行輸入口的8位數據 //串口模式0,允許串口接收 SPL=1;//移位(shift),并口輸入被封鎖,串行轉換開始 while(RI==0);//未接收1字節時等待 RI=0; //RI軟件置位 //接收到的數據顯示在P0口,顯示撥碼開關的值 P0=SBUF;DelayMS(20); 甲機通過串口控制乙機LED /* 名稱:甲機發送控制命令字符 說明:甲單片機負責向外發送控制命令字符“A”、“B”、“C”,或者停止發送,乙機根據所接收到的字符完成LED1閃爍、LED2閃爍、雙閃爍、或停止閃爍。*/ #include sbit LED2=P0^3;sbit K1=P1^0;//延時 void DelayMS(uint ms){ uchar i;while(ms--)for(i=0;i<120;i++);} //向串口發送字符 void Putc_to_SerialPort(uchar c){ SBUF=c;while(TI==0);TI=0; 上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 } //主程序 void main(){ uchar Operation_No=0;SCON=0x40;//串口模式1 TMOD=0x20;//T1工作模式2 PCON=0x00;//波特率不倍增 TH1=0xfd;TL1=0xfd;TI=0;TR1=1;while(1){ if(K1==0)//按下K1時選擇操作代碼0,1,2,3 { while(K1==0); Operation_No=(Operation_No+1)%4; } switch(Operation_No)//根據操作代碼發送A/B/C或停止發送 { case 0: LED1=LED2=1; break; case 1: Putc_to_SerialPort('A'); LED1=~LED1;LED2=1; break; case 2: Putc_to_SerialPort('B'); LED2=~LED2;LED1=1; break; case 3: Putc_to_SerialPort('C'); LED1=~LED1;LED2=LED1; break; } DelayMS(100);} } /* 名稱:乙機程序接收甲機發送字符并完成相應動作 說明:乙機接收到甲機發送的信號后,根據相應信號控制LED完成不同閃爍動作。*/ #include sbit LED2=P0^3;上海師范大學信息與機電工程學院—倪繼鋒 《單片機C語言程序設計實訓100例---基于8051和PROTEUS仿真》案例 //延時 void DelayMS(uint ms){ uchar i;while(ms--)for(i=0;i<120;i++);} //主程序 void main(){ } SCON=0x50;TMOD=0x20;PCON=0x00;TH1=0xfd;TL1=0xfd;RI=0;TR1=1;LED1=LED2=1;while(1){ if(RI) } { //串口模式1,允許接收 //T1工作模式2 //波特率不倍增 //波特率9600 //如收到則LED閃爍 RI=0;switch(SBUF)//根據所收到的不同命令字符完成不同動作 { } //關閉LED case 'A': LED1=~LED1;LED2=1;break;case 'B': LED2=~LED2;LED1=1;break;case 'C': LED1=~LED1;LED2=LED1; //LED1閃爍 //LED2閃爍 //雙閃爍 } else LED1=LED2=1;DelayMS(100); 單片機之間雙向通信 /* 名稱:甲機串口程序 說明:甲機向乙機發送控制命令字符,甲機同時接收乙機發送的數字,并顯示在數碼管上。*/ #include 上海師范大學信息與機電工程學院—倪繼鋒 實驗9 多分支程序設計 1、實驗內容 用P1.0、P1.1控制流水燈的變化 P1.0、P1.1=00燈全滅 P1.0、P1.1=01單燈亮左循環 P1.0、P1.1=10單燈亮右循環 P1.0、P1.1=11雙燈亮左循環 燈亮的時時為1秒。用軟件延時實現。*用T0定時選作。 2、實驗步驟 1)打開PV32編程序。匯編正確進入調試界面。否則修改程序重新匯編直到通過。 2)打開P0、P1窗口給 3)調試燈全滅、單燈亮左循環、單燈亮右循環、雙燈亮左循環程序觀察并記祿寄存器、內存的變化。判斷程序是否正確。若發現問題重返編輯界面,修改、存盤、匯編。返回調試界面調試通過。 4)設斷點調試主程序觀察并記祿寄存器、內存的變化。判斷程序是否正確。若發現問題重返編輯界面,修改、存盤、匯編。返回調試界面調試通過。 首先將P1.0、P1.1置00觀察P2窗口燈是否全滅,然后改變P1.0、1.1的設置觀察流水燈運行是否正確。 5)流水燈運行中改變P1.0、1.1看流燈能否隨之變化。若執行正確程序通過。否則在每個流水子程序中加入讀P1口散轉子程序。 3.實驗報告 1.寫出主程序流程圖、子程序流程圖、程序清單 2.根據記淥數據給程序加注解 3.調試心得第四篇:51單片機程序設計實訓100例
第五篇:單片機實驗9 多分支程序設計