一、實驗名稱:十字路口交通燈實驗
二、實驗目的:
利用51單片機完成模擬正常路口交通燈的運行過程,過程中配備緊急調控按鍵(路口均爲紅燈,模擬突發情況禁止路口通行),南北調度按鍵(緊急調度南北或者東西方向的通行),每個事件結束後,均可以恢復原來的通行秩序,也就是涉及了保護現場和恢復現場。
三、實驗平臺:
Keil4編寫代碼,Proteus仿真程序
四、Proteus仿真搭建:
顯示路口時間器件我們選擇了兩位數碼管動態顯示,動態顯示的特點是將所有數碼管的段選線並聯在一起,通過控制位選信號來控制數碼管的點亮。這樣一來,就沒有必要給每一位數碼管配一個鎖存器,從而大大簡化了硬件電路。數碼管採用動態掃描顯示,即輪流向各位數碼管送出字形碼和相應的位選,利用發光管的餘輝和人眼的視覺暫留作用,使人感覺好像各位數碼管在同時顯示,因此亮度比靜態顯示要差一些,所以在選擇限流電阻時應略小於靜態顯示電路中的限流電阻。
五、程序分析
1、對於需要用到的單片機外設的初始化設置,外設的意義我在初始化函數裏寫的很清楚了,下面上代碼:
void init()
{
second=25; //當前數碼管顯示南北方向紅綠燈初始時間
second1=30; //當前數碼管顯示東西方向紅綠燈時間
TMOD=0x01; // M0=1,M1=0 定時器0設置工作方式爲方式1,即16位定時器/計數器
TH0=(65536-50000)/256;//晶振默認爲12MHz,所以執行一條指令的時間爲1us
TL0=(65536-50000)%256;//這裏表示進入一次定時器中斷,耗時爲50ms
EA=1; //系統允許中斷,即開啓總中斷
ET0=1;//定時0(TR0)定時中斷開啓位
EX0=1;//外部中斷0使能
IT0=1;//外部中斷0觸發方式爲:下降沿觸發,即引腳P30接受到一次下降信號,觸發外部中斷0
EX1=1;//外部中斷1使能
IT1=1;//外部中斷1觸發方式爲:下降沿觸發,即引腳P31接受到一次下降信號,觸發外部中斷0
IP=0x02;//定時器0中斷優先,這個比較重要,不然默認外部中斷0優先級是先於定時器0中斷的
TR0=1;//開啓定時器0
a=0;
b=0;
c=10;
d=10;
e=10;
f=10;
}
我們在初始化函數裏面開啓了定時器,開啓了定時器中斷,開啓了外部中斷,並且設置了中斷的優先級,防止緊急情況定時器中斷由於優先級被擋死在外面,導致定時器不進行。其實給abcdef這幾個變量的賦值本質上就是一個bool值得關係,是非0即1的關係,所以給這些變量賦值10,或者賦值100,1,18…都是沒有影響的。
2、定時器中斷:
在定時器中斷我們其實只是完成一個定時1s後對設定值second自減(比如南北方向我們設定初始綠燈30s,那麼定時器就會在每秒對30這個設定值second自減),在主程序中我們把這個動態的設定值顯示在數碼管上即可。代碼太長我們這裏就不全列出來了。
有一點我們講一下,就是這個程序中標誌量c d 爲一組,e f 爲一組,用來完成緊急事件的定時工作和恢復現場(即按下按鍵之前各個交通燈是什麼值,恢復回來,系統又可以穩定的運行了。)這裏以e f(禁止通行標誌量)列一下代碼吧:
if(e==0)
{
timer3++;
if(timer3==15)
{
timer3=0;
second--;
}
if(second==0)//保護現場
{
a=m;b=n;
e=10;f=10;
second=v;second1=x;
}
if(f==0)
{
timer3++;
if(timer3==15)
{
timer3=0;
second1--;
}
}
3、外部中斷:
在仿真圖中我們可以很容易的看到我們單片機上的外部中斷引腳連接了兩個按鍵,根據初始化函數,按下按鍵就會觸發中斷進入外部中斷0/1中。
這裏我們以外部中斷0爲例,這個中斷是緊急禁行(全是紅燈)事件,我們按下按鍵,進入該中斷裏:
void waibu0(void) interrupt 0
{
TR0=0;
m=a;n=b;v=second;x=second1;//保存進入外部中斷0後,程序的變量大小
second=20; //設定禁止通行時間,並通過數碼管顯示出來
second1=20;
a=10;b=10; //改變這6個標誌位,控制進入定時器中斷執行哪些語句
c=10;d=10;
e=0;f=0;
EX0=0; //關閉外部中斷,即在此按下不會打斷現有狀況
EX1=0;
TR0=1;
g=1;r=0;y=1; //改變交通燈,使其均變爲紅燈
G1=1;R1=0;Y1=1;
}
在這個中斷裏面有一行指令m=a;n=b;v=second;x=second1;這個指令其實就是我們平時說的保護現場,把進入中斷時當前場景的有關變量保存起來,執行完相關命令後,再恢復現場。
再說一下外部中斷1函數吧:
void waibu1(void) interrupt 2
{
if(key1==0)
{
TR0=0;
j=second;h=second1;
second=20;
second1=20;
a=10;b=10;
c=0;d=0;
e=10;f=10;
TR0=1;
g=1;r=0;y=1;
G1=0;R1=1;Y1=1;
}
if(key2==0)
{
TR0=0;
j=second;h=second1;
second=20;
second1=20;
a=10;b=10;
c=0;d=0;
e=10;f=10;
TR0=1;
g=0;r=1;y=1;
G1=1;R1=0;Y1=1;
}
}
其實思路和外部中斷0裏的一樣,但是我們這裏設計的是在按下這個按鍵之前就要先選擇是哪一路通行,即按下key1或者key2並自鎖以後,再按下這個外部中斷1按鍵,才能正常的進行調控,這裏是程序不太合理的地方,有時間改改!
4、主程序:
主程序就很簡單了,就是數碼管的掃描和顯示,根據標誌位判斷路口交通燈的變化。我們這裏把程序列一下:
void main()
{
init();
while(1)
{
// P1=0x02;
YOU1=1;ZUO1=0;ZUO2=0;YOU2=0;
P2=~table[second/10];
delay(10);
// P1=0x01;
YOU1=0;ZUO1=1;ZUO2=0;YOU2=0;
P2=~table[second%10];
delay(10);
// P1=0x04;
ZUO1=0;YOU1=0;ZUO2=1;YOU2=0;
P0=~table[second1/10];
delay(10);
// P1=0x08;
ZUO1=0;YOU1=0;ZUO2=0;YOU2=1;
P0=~table[second1%10];
delay(10);
if(a==0)
{g=0;r=1;}
if(a==1)
{y=0;g=1;}
if(a==2)
{r=0;y=1;}
if(b==0)
{R1=0;Y1=1;}
if(b==1)
{G1=0;R1=1;}
if(b==2)
{Y1=0;G1=1;}
}
}
六、實驗現象:
其中按鍵功能我們通過圖片不好表示,我又懶得上視頻,有時間把程序和仿真圖都放出來大家可以自己下載測試一下!
代碼及仿真圖