找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 5563|回復(fù): 2
收起左側(cè)

單片機(jī)交通燈課設(shè)分享 順帶學(xué)習(xí)心得

[復(fù)制鏈接]
ID:195836 發(fā)表于 2018-3-14 12:56 | 顯示全部樓層 |閱讀模式
上個(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仿真工程文件可到本帖附件中下載)
0.png

單片機(jī)源程序如下:
  1. #include "reg51.h"
  2. sbit Ared=P2^0;
  3. sbit Ayel=P2^1;
  4. sbit Agre=P2^2;
  5. sbit Bred=P2^3;
  6. sbit Byel=P2^4;
  7. sbit Bgre=P2^5;
  8. sbit k1=P0^0;
  9. sbit k2=P0^1;
  10. sbit k3=P0^2;
  11. int flag_key,shine_a,shine_b;                        //通過flag_key來表示當(dāng)前按鍵情況,shine來表示當(dāng)前黃燈情況
  12. int flag_en1,flag_en2,flag_en3,flag_en4,flag_en5;                //五個(gè)任務(wù)的使能標(biāo)志位
  13. int flag_time1,flag_time2,flag_time3,flag_time4,flag_time5;                //定時(shí)器的開啟標(biāo)志位
  14. int time_1,time_2,time_3,time_4,time_5;                //定時(shí)器的計(jì)時(shí)標(biāo)志位
  15. int delay,rst;                //rst是復(fù)位標(biāo)志位,用來判斷中斷結(jié)束后執(zhí)行哪一個(gè)任務(wù)

  16. void scankey()
  17. {
  18.          if(k1==0)
  19.         {
  20.                 delay=1000;
  21.                 while(delay--);
  22.                 if(k1==0)
  23.                 {
  24.                          flag_en5=1;
  25.                         flag_key=1;
  26.                         flag_time1=0;
  27.                         flag_time2=0;
  28.                         flag_time3=0;
  29.                         flag_time4=0;
  30.                         time_1=0;
  31.                         time_2=0;
  32.                         time_3=0;
  33.                         time_4=0;
  34.                         while(!k1);
  35.                 }        
  36.         }
  37.         if(k2==0)
  38.         {
  39.                 delay=1000;
  40.                 while(delay--);
  41.                 if(k2==0)
  42.                 {
  43.                          flag_en5=1;                        
  44.                         flag_key=2;
  45.                         flag_time1=0;
  46.                         flag_time2=0;
  47.                         flag_time3=0;
  48.                         flag_time4=0;
  49.                         time_1=0;
  50.                         time_2=0;
  51.                         time_3=0;
  52.                         time_4=0;
  53.                         while(!k2);
  54.                 }        
  55.         }
  56.         if(k3==0)
  57.         {

  58.                  delay=1000;
  59.                 while(delay--);
  60.                 if(k3==0)
  61.                 {
  62.                          flag_en5=1;
  63.                         flag_key=3;
  64.                         flag_time1=0;
  65.                         flag_time2=0;
  66.                         flag_time3=0;
  67.                         flag_time4=0;
  68.                         time_1=0;
  69.                         time_2=0;
  70.                         time_3=0;
  71.                         time_4=0;
  72.                         while(!k3);
  73.                 }        
  74.         }
  75. }

  76. void led(int r1,r2,r3,r4,r5,r6)
  77. {
  78.         Ared=r1;
  79.         Ayel=r2;
  80.         Agre=r3;
  81.         Bred=r4;
  82.         Byel=r5;
  83.         Bgre=r6;
  84. }

  85. void main()
  86. {
  87. //定時(shí)器初始化
  88.         TMOD=0;
  89.         TH1=(8192-1000)/32;
  90.         TL1=(8192-1000)%32;
  91.         EA=1;
  92.         ET1=1;
  93.         TR1=1;
  94. //參數(shù)初始化
  95.         flag_key=0;
  96.         flag_en1=1;
  97.         flag_en2=0;
  98.         flag_en3=0;
  99.         flag_en4=0;
  100.         flag_en5=0;
  101.         time_1=0;
  102.         time_2=0;
  103.         time_3=0;
  104.         time_4=0;
  105.         time_5=0;
  106.         flag_time1=0;
  107.         flag_time2=0;
  108.         flag_time3=0;
  109.         flag_time4=0;
  110.         flag_time5=0;
  111.         shine_a=1;
  112.         shine_b=1;
  113.         rst=0;
  114.         while(1)
  115.         {
  116.                 scankey();
  117. //按鍵未按下,正常運(yùn)行                 
  118.                 if(flag_key==0)
  119.                 {
  120.                          if(flag_en1==1)
  121.                         {
  122.                                  rst=1;
  123.                                 flag_en1=0;
  124.                                 led(0,0,1,1,0,0);
  125.                                 flag_time1=1;
  126.                         }
  127.                         if(flag_en2==1)
  128.                         {
  129.                                 rst=2;
  130.                                 if(shine_a==1||shine_a==3||shine_a==5)
  131.                                         led(0,1,0,1,0,0);
  132.                                 else if(shine_a==2||shine_a==4||shine_a==6)
  133.                                         led(0,0,0,1,0,0);
  134.                                 flag_time2=1;
  135.                                 if(shine_a==6)
  136.                                         flag_en2=0;                                
  137.                         }
  138.                         if(flag_en3==1)
  139.                         {
  140.                                  rst=3;
  141.                                 flag_en3=0;
  142.                                 led(1,0,0,0,0,1);
  143.                                 flag_time3=1;
  144.                         }
  145.                         if(flag_en4==1)
  146.                         {
  147.                                 rst=4;
  148.                                 if(shine_b==1||shine_b==3||shine_b==5)
  149.                                         led(1,0,0,0,1,0);
  150.                                 else if(shine_b==2||shine_b==4||shine_b==6)
  151.                                         led(1,0,0,0,0,0);
  152.                                 flag_time4=1;
  153.                                 if(shine_b==6)
  154.                                         flag_en4=0;               
  155.                         }
  156.                 }

  157.                 if(flag_key==1)
  158.                 {
  159.                          if(flag_en5==1)
  160.                         {
  161.                                  flag_en5=0;
  162.                                 led(0,0,1,1,0,0);
  163.                                 flag_time5=1;
  164.                         }
  165.                 }

  166.                 if(flag_key==2)
  167.                 {
  168.                          if(flag_en5==1)
  169.                         {
  170.                                  flag_en5=0;
  171.                                 led(1,0,0,0,0,1);
  172.                                 flag_time5=1;
  173.                         }
  174.                 }

  175.                 if(flag_key==3)
  176.                 {
  177.                          if(flag_en5==1)
  178.                         {
  179.                                  flag_en5=0;
  180.                                 led(1,0,0,1,0,0);
  181.                                 flag_time5=1;
  182.                         }
  183.                 }
  184.         }
  185. }

  186. void hml() interrupt 3
  187. {
  188.          if(flag_time1==1)
  189.                 time_1++;
  190.         if(time_1==3000)
  191.         {
  192.                  time_1=0;
  193.                 flag_time1=0;
  194.                 flag_en2=1;
  195.         }

  196.         if(flag_time2==1)
  197.                 time_2++;
  198.         if(time_2==500)
  199.         {
  200.                  time_2=0;
  201.                 shine_a++;
  202.                 if(shine_a==7)
  203.                 {
  204.                          flag_time2=0;
  205.                         flag_en3=1;
  206.                         shine_a=1;
  207.                 }
  208.         }

  209.         if(flag_time3==1)
  210.                 time_3++;
  211.         if(time_3==3000)
  212.         {
  213.                  time_3=0;
  214.                 flag_time3=0;
  215.                 flag_en4=1;
  216.         }

  217.         if(flag_time4==1)
  218.                 time_4++;
  219.         if(time_4==500)
  220.         {
  221.                  time_4=0;
  222.                 shine_b++;
  223.                 if(shine_b==7)
  224.                 {
  225.                          flag_time4=0;
  226.                         flag_en1=1;
  227.                         shine_b=1;
  228.                 }
  229. ……………………

  230. …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼
0.png
所有資料51hei提供下載:
交通燈.rar (115.47 KB, 下載次數(shù): 21)


評(píng)分

參與人數(shù) 1黑幣 +100 收起 理由
admin + 100 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:1 發(fā)表于 2018-3-15 02:40 | 顯示全部樓層
好資料,51黑有你更精彩!!!
回復(fù)

使用道具 舉報(bào)

ID:291647 發(fā)表于 2018-3-15 09:28 | 顯示全部樓層
資料很好,謝謝
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表