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