上個學期幫老師帶了本科課程設計,40個同學,我就想著先做一遍吧,就隨便選了一個交通燈的題目。題目如下
用AT89S52單片機控制一個交通信號燈系統。設A車道與B車道交叉組成十字路口,A是主道,B是支道,要求如下:
(1)用發光二極管模擬交通信號燈,用按鍵開關模擬車輛檢測信號;
(2)正常情況下,A、B兩車道輪流放行,A車道放行12s,其中3s用于警告;B車道放行8s,其中3s用于警告;(警告為黃燈閃爍)
(3)在交通繁忙時,交通信號燈控制系統應有手控開關,可人為地改變信號燈的狀態,以緩解交通擁擠情況。在B車道放行期間,若A車道有車而B車道無車,按下開關k1使A車道放行5s,在A車道放行期間,若B車道有車而A車道無車,按下開關k2使B車道放行5s;
(4)有緊急車輛通過時,按下k3開關使A、B車道均為紅燈,禁行5s。
看了題目,感覺比較正常,就做唄。其實也簡單,按下按鍵相當于給他一個中斷,執行中斷子程序之后返回原來的地方,大概整個內容兩個小時搞定吧。嗯,比想象的時間要長。
做出來之后,感覺很奇怪。比如此時我是A通道放行,放行到第8s時,我讓B車道通,那么B車道通5s后我又回到A車道通,只通1s就開始警告3s然后又到B,感覺中間時間太短。而且閃爍的時候也挺混亂的。我設置的是閃爍3s,每秒亮0.5s,滅0.5s。那么直接回到中斷點的話這個時間也非常混亂。
基于此,我對這題進行了改進。
某通道通過時,有按鍵按下,執行相應的中斷子程序。執行完畢后會返回,但并不是之前中斷的位置,而是這樣的:
A通過通的過程中,按下k2并不會有任何動作。按下k1,使B通道通行,返回時是重新使A通道通行,即通行12s。按下k3時,返回時是直接使B通道通行。
B通道同理。另外針對黃燈警告的時候,比如A亮黃燈,那么就認為A通道已經放行了很長時間,按鍵之后偏向于直接使得B通道通。
嗯,具體是怎樣的過程我已經忘記了,可能剛剛描述的跟我做的不太準確。但是很明顯看出這是在原來的題目上加以補充的,更貼合于實際情況。
那么我們來編程吧,這就遇到困難了。之前的程序相當于是正常運行,然后三個按鍵進入三個中斷。但是現在我需要記住中斷之前我的狀態,中斷結束后要根據中斷前的狀態及具體執行哪一個中斷程序來判斷結束后執行什么任務。
因此,最重要的就是對各狀態進行判斷。
在最初的版本中,主要就是每個階段點燈的子函數,然后掃描鍵盤的函數觸發中斷。這里的思路是三個按鍵連接3個IO口,同時連接到外部中斷,同時加上拉電阻。當有按鍵按下時給一個低電平到外部中斷,中斷子函數掃描三個IO口判斷哪一個是低電平從而執行相應的操作。這里的連接涉及到一些與非門什么的。
但是這個版本并不能這樣。我考慮的是用定時器中斷而不用外部中斷。首先我使用了20個標志位來輔助判斷程序運行到哪一步了,這個就非常復雜了,環環相扣。另外我是采取的定時掃描方式,每隔1ms掃描各個標志位,來判斷按鍵是否按下,而并非通過中斷來按下按鍵。整個主程序執行時間極短,全部是根據標志位點亮相應的燈,而中斷程序主要根據按鍵及標志位兩者來改變標志位。現在放出來給大家看看,希望不會頭暈。。。
程序有270行,我就不復制過來啦。
嗯,下面是個人的一些心得。我曾經教過不下十個同學學習單片機,我推薦的都是普中的板子,但是他們看了視頻之后就認為自己會了,實際上不是的。比如數碼管,整個視頻大概20分鐘吧(具體記不清了),他們看了之后就沒了,實際上單片機這個東西是需要多練的,我就會出一些題目,比如數碼管顯示0-F,一個按鍵改變顯示頻率,一個開關改變顯示方向(+/-)。做得過程中我自己也會發現一些問題,譬如就這個題目如果不用中斷效果很差(不過我相信可以改進)。交通燈這個題目,應該是各種課程做爛了的,沒想到我竟然做了三天,其中熬了兩天夜。
其次,學習單片機不僅僅只是學會編程,更要學會思考。真正做項目中具體任務都是自己定的,并不會像題目一樣給你限定死了,那么該選取怎樣的目標?甚至包括具體硬件都是自己定的,需要自己靜下心來多思考。而我看得有些同學覺得這一塊不重要,只在意編程,這是不行的。
程序說不定有問題,半年前做的。只是提出一些自己的思路,希望能幫到大家。
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
0.png (16.74 KB, 下載次數: 92)
下載附件
2018-3-15 02:34 上傳
單片機源程序如下:
- #include "reg51.h"
- sbit Ared=P2^0;
- sbit Ayel=P2^1;
- sbit Agre=P2^2;
- sbit Bred=P2^3;
- sbit Byel=P2^4;
- sbit Bgre=P2^5;
- sbit k1=P0^0;
- sbit k2=P0^1;
- sbit k3=P0^2;
- int flag_key,shine_a,shine_b; //通過flag_key來表示當前按鍵情況,shine來表示當前黃燈情況
- int flag_en1,flag_en2,flag_en3,flag_en4,flag_en5; //五個任務的使能標志位
- int flag_time1,flag_time2,flag_time3,flag_time4,flag_time5; //定時器的開啟標志位
- int time_1,time_2,time_3,time_4,time_5; //定時器的計時標志位
- int delay,rst; //rst是復位標志位,用來判斷中斷結束后執行哪一個任務
- void scankey()
- {
- if(k1==0)
- {
- delay=1000;
- while(delay--);
- if(k1==0)
- {
- flag_en5=1;
- flag_key=1;
- flag_time1=0;
- flag_time2=0;
- flag_time3=0;
- flag_time4=0;
- time_1=0;
- time_2=0;
- time_3=0;
- time_4=0;
- while(!k1);
- }
- }
- if(k2==0)
- {
- delay=1000;
- while(delay--);
- if(k2==0)
- {
- flag_en5=1;
- flag_key=2;
- flag_time1=0;
- flag_time2=0;
- flag_time3=0;
- flag_time4=0;
- time_1=0;
- time_2=0;
- time_3=0;
- time_4=0;
- while(!k2);
- }
- }
- if(k3==0)
- {
- delay=1000;
- while(delay--);
- if(k3==0)
- {
- flag_en5=1;
- flag_key=3;
- flag_time1=0;
- flag_time2=0;
- flag_time3=0;
- flag_time4=0;
- time_1=0;
- time_2=0;
- time_3=0;
- time_4=0;
- while(!k3);
- }
- }
- }
- void led(int r1,r2,r3,r4,r5,r6)
- {
- Ared=r1;
- Ayel=r2;
- Agre=r3;
- Bred=r4;
- Byel=r5;
- Bgre=r6;
- }
- void main()
- {
- //定時器初始化
- TMOD=0;
- TH1=(8192-1000)/32;
- TL1=(8192-1000)%32;
- EA=1;
- ET1=1;
- TR1=1;
- //參數初始化
- flag_key=0;
- flag_en1=1;
- flag_en2=0;
- flag_en3=0;
- flag_en4=0;
- flag_en5=0;
- time_1=0;
- time_2=0;
- time_3=0;
- time_4=0;
- time_5=0;
- flag_time1=0;
- flag_time2=0;
- flag_time3=0;
- flag_time4=0;
- flag_time5=0;
- shine_a=1;
- shine_b=1;
- rst=0;
- while(1)
- {
- scankey();
- //按鍵未按下,正常運行
- if(flag_key==0)
- {
- if(flag_en1==1)
- {
- rst=1;
- flag_en1=0;
- led(0,0,1,1,0,0);
- flag_time1=1;
- }
- if(flag_en2==1)
- {
- rst=2;
- if(shine_a==1||shine_a==3||shine_a==5)
- led(0,1,0,1,0,0);
- else if(shine_a==2||shine_a==4||shine_a==6)
- led(0,0,0,1,0,0);
- flag_time2=1;
- if(shine_a==6)
- flag_en2=0;
- }
- if(flag_en3==1)
- {
- rst=3;
- flag_en3=0;
- led(1,0,0,0,0,1);
- flag_time3=1;
- }
- if(flag_en4==1)
- {
- rst=4;
- if(shine_b==1||shine_b==3||shine_b==5)
- led(1,0,0,0,1,0);
- else if(shine_b==2||shine_b==4||shine_b==6)
- led(1,0,0,0,0,0);
- flag_time4=1;
- if(shine_b==6)
- flag_en4=0;
- }
- }
- if(flag_key==1)
- {
- if(flag_en5==1)
- {
- flag_en5=0;
- led(0,0,1,1,0,0);
- flag_time5=1;
- }
- }
- if(flag_key==2)
- {
- if(flag_en5==1)
- {
- flag_en5=0;
- led(1,0,0,0,0,1);
- flag_time5=1;
- }
- }
- if(flag_key==3)
- {
- if(flag_en5==1)
- {
- flag_en5=0;
- led(1,0,0,1,0,0);
- flag_time5=1;
- }
- }
- }
- }
- void hml() interrupt 3
- {
- if(flag_time1==1)
- time_1++;
- if(time_1==3000)
- {
- time_1=0;
- flag_time1=0;
- flag_en2=1;
- }
- if(flag_time2==1)
- time_2++;
- if(time_2==500)
- {
- time_2=0;
- shine_a++;
- if(shine_a==7)
- {
- flag_time2=0;
- flag_en3=1;
- shine_a=1;
- }
- }
- if(flag_time3==1)
- time_3++;
- if(time_3==3000)
- {
- time_3=0;
- flag_time3=0;
- flag_en4=1;
- }
- if(flag_time4==1)
- time_4++;
- if(time_4==500)
- {
- time_4=0;
- shine_b++;
- if(shine_b==7)
- {
- flag_time4=0;
- flag_en1=1;
- shine_b=1;
- }
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
0.png (49.96 KB, 下載次數: 84)
下載附件
2018-3-15 02:34 上傳
所有資料51hei提供下載:
交通燈.rar
(115.47 KB, 下載次數: 21)
2018-3-14 12:54 上傳
點擊文件名下載附件
兩個程序 電路仿真 下載積分: 黑幣 -5
|