基于51單片機(jī)的十字路口交通燈系統(tǒng)

1 設(shè)計(jì)名稱

基于51單片機(jī)的十字路口交通燈系統(tǒng)(C語言、Proteus開發(fā)環(huán)境)

2 設(shè)計(jì)要求

1、 基于51系列單片機(jī)設(shè)計(jì)一個(gè)十字路口交通燈控制系統(tǒng),用于模擬道路十字路口交通燈實(shí)際運(yùn)行的場景。

2、 東西向、南北向依次進(jìn)行周期通行,默認(rèn)設(shè)置為:東西向直行(綠燈)時(shí)間30秒,左轉(zhuǎn)(藍(lán)燈)時(shí)間15秒;南北向直行(綠燈)時(shí)間20秒,左轉(zhuǎn)(藍(lán)燈)時(shí)間10秒。

3、 每次直行(綠燈)變左轉(zhuǎn)(藍(lán)燈)和左轉(zhuǎn)(藍(lán)燈)變停車(紅燈)前,黃燈需先閃爍3秒,此3秒時(shí)長包含在上述直行和左轉(zhuǎn)時(shí)間內(nèi)。

4、 可通過控制臺(tái)按鍵實(shí)現(xiàn)對十字路口進(jìn)行交通管制的功能。

5、 可通過控制臺(tái)按鍵實(shí)現(xiàn)對十字路口各方向的通行時(shí)間進(jìn)行設(shè)置的功能。

3 功能說明

整個(gè)十字路口由東西向道路和南北向道路垂直交叉形成,我們采用“上北下南,左西右東”的慣例進(jìn)行構(gòu)圖。每個(gè)方向都有一組4色的LED燈來控制交通的流向和節(jié)奏。流向也即方向,通過不同LED燈顏色進(jìn)行表征:紅燈停,綠燈行,黃燈等一等,這里左轉(zhuǎn)我們用藍(lán)燈表示;節(jié)奏通過倒計(jì)時(shí)時(shí)間進(jìn)行控制,該時(shí)間的時(shí)基由單片機(jī)的定時(shí)器提供。

十字路口的倒計(jì)時(shí)時(shí)間分別通過四個(gè)2位的七段共陰極數(shù)碼管顯示。綠燈點(diǎn)亮道路上的數(shù)碼管顯示的數(shù)字是該道路所剩余的可通行時(shí)間,紅燈點(diǎn)亮道路上的數(shù)碼管顯示的數(shù)字是該道路所剩余的禁行時(shí)間,小伙伴需要注意區(qū)分兩者不同的物理含義。

系統(tǒng)上電后,默認(rèn)運(yùn)行在“正常模式”下。此時(shí)南北向綠燈點(diǎn)亮,允許直行;東西向紅燈點(diǎn)亮,禁止直行和左轉(zhuǎn)。具體的狀態(tài)遷移順序可參照下面第 6 部分內(nèi)容。

4 系統(tǒng)架構(gòu)

整個(gè)架構(gòu)非常簡單,主要由四部分組成。分別是MCU單片機(jī)控制模塊、按鍵輸入掃描模塊、數(shù)碼管顯示模塊和交通燈顯示模塊。按鍵、數(shù)碼管和LED燈都是典型的人機(jī)交互的元器件,按鍵用于接收命令,數(shù)碼管和LED燈用于反饋信號和狀態(tài)。數(shù)據(jù)流向也是單向的,由左至右。

圖1 交通燈系統(tǒng)架構(gòu)圖

我們現(xiàn)在將十字路口交通燈的運(yùn)行場景抽象歸納一下,然后用下面的圖表進(jìn)行復(fù)盤。

5 運(yùn)行模式

對照日常生活,我們來盤點(diǎn)一下交通燈運(yùn)行的模式:

“正常模式”:模擬十字路口正常運(yùn)行的場景,交通燈按正常的順序進(jìn)行周期循環(huán);

“夜間模式”:模擬十字路口夜間運(yùn)行的場景,東西向和南北向的黃燈同時(shí)閃爍;

“緊急模式”:模擬十字路口進(jìn)入緊急情況下的場景(救護(hù)車、消防車通過等),東西向和南北向的紅燈全部點(diǎn)亮;

“強(qiáng)制東西向通行模式”:強(qiáng)制東西向通行,南北向停車等待。

“強(qiáng)制南北向通行模式”:強(qiáng)制南北向通行,東西向停車等待。

6 ”正常模式“下狀態(tài)遷移之狀態(tài)機(jī)

不同國家、不同城市、不同十字路口都有不同的狀態(tài)設(shè)置。有的路口是先直行再左轉(zhuǎn),有的路口是先允許左轉(zhuǎn)再允許直行,有的路口壓根就沒有專門的左轉(zhuǎn)燈,有的路口有人行道指示燈,而有的沒有。所謂千人千面,五官各不相同,但確有一個(gè)共性,就是都有五官。狀態(tài)機(jī)的思路可以很好的解決這個(gè)問題。

圖2 正常模式下狀態(tài)機(jī)

7 ”正常模式“下狀態(tài)遷移之矩陣表

圖3 正常模式下狀態(tài)矩陣表

1?- 表征對應(yīng)顏色交通燈點(diǎn)亮;

0?- 表征對應(yīng)顏色交通燈熄滅;

1/0?- 表征對應(yīng)顏色交通燈閃爍;

藍(lán)色燈?- 表征對應(yīng)道路左轉(zhuǎn)狀態(tài);

8 仿真電路圖

因?yàn)榘咐鼈?cè)重功能的實(shí)現(xiàn),對于硬件電路的設(shè)計(jì)要求不是太高,達(dá)到能用就行的標(biāo)準(zhǔn)就行,所以這里只簡要說一下重點(diǎn)吧。

1 單片機(jī)P0一定要加上拉電阻。為什么?因?yàn)镻0口內(nèi)部為開集電極輸出,無法輸出高電平,只有加了上拉電阻,P0口才能輸出高電平。

2 數(shù)碼管的驅(qū)動(dòng)一定要加限流電阻。雖然在Proteus中仿真不加問題也不大,但是實(shí)際產(chǎn)品肯定是不允許的,而且也無法工作。

3 LED燈驅(qū)動(dòng)一定要加限流電阻。如果不加限流電阻,單片機(jī)會(huì)工作異常,因?yàn)閱纹瑱C(jī)引腳的驅(qū)動(dòng)電流的能力是有限制的,超出則正常功能無法保證,甚至燒壞單片機(jī)。

4 LED燈不建議直接并聯(lián)使用。雖然LED燈具有正向單調(diào)的伏安特性曲線,但是它的溫度系數(shù)卻是負(fù)向的,不利于均流。

5 按鍵模塊采用的是普通的點(diǎn)對點(diǎn)的結(jié)構(gòu),但設(shè)計(jì)中也可采用矩陣式按鍵,小伙伴可以自行發(fā)揮。

6 當(dāng)前的設(shè)計(jì),單片機(jī)引腳基本被全部分配用完,沒有冗余。對于實(shí)物產(chǎn)品的開發(fā)這是不被允許的,因?yàn)檫^于捉襟見肘的單片機(jī)資源完全不利于產(chǎn)品后期的功能升級和延展。如果單片機(jī)引腳緊張,除可以采用矩陣式鍵盤節(jié)省引腳外,也可以采用數(shù)字鎖存器或者譯碼器對引腳進(jìn)行擴(kuò)展使用。

圖4 Proteus環(huán)境仿真圖
圖5 Proteus環(huán)境十字路口放大視圖
圖6 Proteus環(huán)境單片機(jī)模塊放大視圖
圖7 Proteus環(huán)境控制臺(tái)按鍵模塊放大視圖

9 器件清單

圖8 交通燈仿真圖元器件清單

其他未盡事宜,諸如導(dǎo)線啊,芯片底座啊,電源插座啊,電源啊等等,都是基本功,這里暫就不表了。

10 C 語言核心源代碼

軟件架構(gòu)采用的是時(shí)間觸發(fā)機(jī)制+狀態(tài)機(jī)的設(shè)計(jì)模式,這種模式的好處是MCU執(zhí)行效率高,實(shí)時(shí)性好,另外一點(diǎn)很重要的就是靈活性,代碼容易擴(kuò)展。時(shí)間片調(diào)度周期為20ms,用于按鍵的掃描識別和LED數(shù)碼管的動(dòng)態(tài)刷新。交通燈運(yùn)轉(zhuǎn)的狀態(tài)機(jī)是通過switch來完成的。大俠看到網(wǎng)絡(luò)上很多的案例代碼用到了外部中斷來實(shí)現(xiàn)按鍵掃描,這是完全沒必要的,主函數(shù)輪詢掃描的方式完全就夠用了,51單片機(jī)的外部中斷資源畢竟有限且珍貴,何以要用中斷呢?難道江郎才盡了?此外,設(shè)計(jì)中按鍵掃描模塊實(shí)現(xiàn)了去抖的功能。

因版面受限,這里只能貼出核心狀態(tài)機(jī)的源代碼供各位看管參考學(xué)習(xí)了。其他功能相對簡單,大家可以適當(dāng)腦補(bǔ),或者也可劃至文章最后尋找解決方案。

10.1 變量定義

sbit Gb_SN_LEDH_En = P2^0; // 南北向高位LED數(shù)碼管使能控制位

sbit Gb_SN_LEDL_En = P2^1; // 南北向低位LED數(shù)碼管使能控制位

sbit Gb_EW_LEDH_En = P2^2; // 東西向高位LED數(shù)碼管使能控制位

sbit Gb_EW_LEDL_En = P2^3; // 東西向低位LED數(shù)碼管使能控制位

sbit Gb_Debug_LEDH_En = P2^4; // 調(diào)試用高位LED數(shù)碼管使能控制位

sbit Gb_Debug_LEDL_En = P2^5; // 調(diào)試用低位LED數(shù)碼管使能控制位

sbit Gb_EW_Walk_Green_En = P2^6;? // 東西向人行道綠燈使能控制位

sbit Gb_SN_Walk_Green_En = P2^7;? // 南北向人行道綠燈使能控制位

sbit Gb_EW_Yellow_En = P1^2;? // 東西向黃燈使能控制位

sbit Gb_SN_Yellow_En = P1^6;? // 南北向黃燈使能控制位

sbit Gb_EW_Red_En = P1^3;? // 東西向黃燈使能控制位

sbit Gb_SN_Red_En = P1^7;? // 南北向黃燈使能控制位

#define SET 0? // 設(shè)置/確認(rèn)按鈕

#define SET_ADD 1? // 設(shè)置+

#define SET_SUB 2? //設(shè)置-

#define SET_HOME 3? // 正常模式

#define SET_YELLOW 4? // 夜間模式

#define SET_RED 5? // 緊急模式

#define SET_EW 6? // 強(qiáng)制東西向通行模式

#define SET_SN 7? //強(qiáng)制南北向通行模式

uint_8 Gb_Traffic_RunMode;? // 紅綠燈運(yùn)行模式? 0-正常? 1-夜間? 2-緊急? 3-東西強(qiáng)制? 4-南北強(qiáng)制

uint_8 Gb_SET_Active_Flag;? // 使能設(shè)置功能標(biāo)志位

uint_8 Gb_SET_LEDSEG_Blink_Flag;? // 控制臺(tái)數(shù)碼管閃爍時(shí)基標(biāo)志位

uint_8 Gb_LED_SEG_Update_Flag;? // LED數(shù)碼管刷新調(diào)度標(biāo)志位

uint_8 Gb_LED_YellowControl_Flag;? // LED黃燈閃爍調(diào)度標(biāo)志位

uint_8 Gb_LED_Task1s_Flag;? // 交通燈任務(wù)調(diào)度標(biāo)志位

uint_8 Gb_EW_YellowLight_Flag;? // 東西向黃燈閃爍標(biāo)志位

uint_8 Gb_SN_YellowLight_Flag;? // 南北向黃燈閃爍標(biāo)志位

uint_8 Gb_EW_LED_RealTime;? // 東西向LED數(shù)碼管顯示時(shí)間

uint_8 Gb_SN_LED_RealTime;? // 南北向LED數(shù)碼管顯示時(shí)間

uint_8 Gb_SET_LED_RealTime;? // 控制臺(tái)LED數(shù)碼管顯示時(shí)間,默認(rèn)無顯示

uint_8 Gb_System_Step_Index = 0;? // 正常模式下紅綠燈運(yùn)行進(jìn)度標(biāo)志

uint_8 Cc_EW_DirectPass_Time = 10;? // 東西向道路直行時(shí)間參數(shù)(不含黃燈閃爍時(shí)間),單位秒

uint_8 Cc_SN_DirectPass_Time = 15;? // 南北向道路直行時(shí)間參數(shù)(不含黃燈閃爍時(shí)間),單位秒

uint_8 Cc_EW_LeftPass_Time = 5;? // 東西向道路左轉(zhuǎn)時(shí)間參數(shù)(不含黃燈閃爍時(shí)間),單位秒

uint_8 Cc_SN_LeftPass_Time = 5;? // 南北向道路左轉(zhuǎn)時(shí)間參數(shù)(不含黃燈閃爍時(shí)間),單位秒

uint_8 Cc_YellowLight_Time = 3;? // 黃燈閃爍時(shí)間參數(shù),單位秒

uint_8 code LED_SEG_Table[11]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};? //共陰數(shù)碼管0-9段選碼表,及無顯示狀態(tài)

uint_8 code LED_Light_Table[4]={0X28,0X18,0X82,0X81};? //交通信號燈控制代碼,對應(yīng)P1引腳

10.2 交通燈控制函數(shù)

/*************************************************

函數(shù)名:十字路口交通燈控制函數(shù)

參? 數(shù):無

返回值:無

結(jié)? 果:管理紅綠藍(lán)交通燈,管理人行道交通燈

************************************************/

void Traffic_Control(void)

{

? ? Gb_SN_LED_RealTime--;? // 南北向時(shí)間倒計(jì)時(shí)

? ? Gb_EW_LED_RealTime--;? // 東西向時(shí)間倒計(jì)時(shí)

? ? switch(Gb_System_Step_Index)

? ? {

? ? ? ? case 0:? // 狀態(tài)0 - 南北向綠燈,東西向紅燈

? ? ? ? ? ? if(Gb_SN_LED_RealTime <= Cc_YellowLight_Time)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? P1 = P1&0x0F;

? ? ? ? ? ? ? ? Gb_SN_YellowLight_Flag = 1;

? ? ? ? ? ? ? ? Gb_System_Step_Index++;

? ? ? ? ? ? }

? ? ? ? ? ? break;

? ? ? ? case 1:? // 狀態(tài)1 - 南北向黃燈,東西向紅燈

? ? ? ? ? ? if(Gb_SN_LED_RealTime <= 0)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? P1 = LED_Light_Table[1];

? ? ? ? ? ? ? ? Gb_SN_LED_RealTime = Cc_SN_LeftPass_Time + Cc_YellowLight_Time;

? ? ? ? ? ? ? ? Gb_SN_YellowLight_Flag = 0;

? ? ? ? ? ? ? ? Gb_System_Step_Index++;

? ? ? ? ? ? }? ? ? ? ? ?

? ? ? ? ? ? break;

? ? ? ? case 2:? // 狀態(tài)2 - 南北向左轉(zhuǎn)燈亮,東西向紅燈

? ? ? ? ? ? if(Gb_SN_LED_RealTime <= Cc_YellowLight_Time)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? P1 = P1&0x0F;

? ? ? ? ? ? ? ? Gb_SN_YellowLight_Flag = 1;

? ? ? ? ? ? ? ? Gb_System_Step_Index++;

? ? ? ? ? ? }

? ? ? ? ? ? break;

? ? ? ? case 3:? // 狀態(tài)3 - 南北向黃燈,東西向紅燈

? ? ? ? ? ? if(Gb_SN_LED_RealTime <= 0)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? P1 = LED_Light_Table[2];

? ? ? ? ? ? ? ? Gb_SN_LED_RealTime = Cc_EW_DirectPass_Time + Cc_EW_LeftPass_Time + 2*Cc_YellowLight_Time;

? ? ? ? ? ? ? ? Gb_EW_LED_RealTime = Cc_EW_DirectPass_Time + Cc_YellowLight_Time;

? ? ? ? ? ? ? ? Gb_SN_Walk_Green_En = 0;

? ? ? ? ? ? ? ? Gb_EW_Walk_Green_En = 1;

? ? ? ? ? ? ? ? Gb_SN_YellowLight_Flag = 0;

? ? ? ? ? ? ? ? Gb_System_Step_Index++;

? ? ? ? ? ? }? ? ? ? ? ?

? ? ? ? ? ? break;

? ? ? ? case 4:? // 狀態(tài)4 - 南北向紅燈,東西向綠燈

? ? ? ? ? ? if(Gb_EW_LED_RealTime <= Cc_YellowLight_Time)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? P1 = P1&0xF0;

? ? ? ? ? ? ? ? Gb_EW_YellowLight_Flag = 1;

? ? ? ? ? ? ? ? Gb_System_Step_Index++;

? ? ? ? ? ? }? ? ? ?

? ? ? ? ? ? break;

? ? ? ? case 5:? // 狀態(tài)5 - 南北向紅燈,東西向黃燈

? ? ? ? ? ? if(Gb_EW_LED_RealTime <= 0)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? P1 = LED_Light_Table[3];

? ? ? ? ? ? ? ? Gb_EW_LED_RealTime = Cc_EW_LeftPass_Time + Cc_YellowLight_Time;

? ? ? ? ? ? ? ? Gb_EW_YellowLight_Flag = 0;

? ? ? ? ? ? ? ? Gb_System_Step_Index++;

? ? ? ? ? ? }? ? ? ?

? ? ? ? ? ? break;

? ? ? ? case 6:? // 狀態(tài)6 - 南北向紅燈,東西向左轉(zhuǎn)燈亮

? ? ? ? ? ? if(Gb_EW_LED_RealTime <= Cc_YellowLight_Time)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? P1 = P1&0xF0;

? ? ? ? ? ? ? ? Gb_EW_YellowLight_Flag = 1;

? ? ? ? ? ? ? ? Gb_System_Step_Index++;

? ? ? ? ? ? }? ? ? ?

? ? ? ? ? ? break;

? ? ? ? case 7:? // 狀態(tài)7 - 南北向紅燈,東西向黃燈

? ? ? ? ? ? if(Gb_SN_LED_RealTime <= 0)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Cc_EW_DirectPass_Time = Cc_EW_DirectPass_Time2;?

? ? ? ? ? ? ? ? Cc_SN_DirectPass_Time = Cc_SN_DirectPass_Time2;?

? ? ? ? ? ? ? ? Cc_EW_LeftPass_Time = Cc_EW_LeftPass_Time2;?

? ? ? ? ? ? ? ? Cc_SN_LeftPass_Time = Cc_SN_LeftPass_Time2;?

? ? ? ? ? ? ? ? Cc_YellowLight_Time = Cc_YellowLight_Time2;

? ? ? ? ? ? ? ? Gb_SN_LED_RealTime = Cc_SN_DirectPass_Time + Cc_YellowLight_Time;

? ? ? ? ? ? ? ? Gb_EW_LED_RealTime = Cc_SN_DirectPass_Time + Cc_SN_LeftPass_Time + 2*Cc_YellowLight_Time;

? ? ? ? ? ? ? ? P1 = LED_Light_Table[0];

? ? ? ? ? ? ? ? Gb_SN_Walk_Green_En = 1;

? ? ? ? ? ? ? ? Gb_EW_Walk_Green_En = 0;

? ? ? ? ? ? ? ? Gb_EW_YellowLight_Flag = 0;

? ? ? ? ? ? ? ? Gb_System_Step_Index = 0;

? ? ? ? ? ? }? ? ? ?

? ? ? ? ? ? break;

? ? ? ? default:

? ? ? ? ? ? break;

? ? }

}

11 操作說明

從按鍵用途的角度進(jìn)行劃分,上圖中的8個(gè)按鍵可以被歸為兩類。一類是用來設(shè)置時(shí)間參數(shù)的,另一類是用來切換交通燈系統(tǒng)運(yùn)行模式的,我們就根據(jù)這2種大的分類分別進(jìn)行詳細(xì)的解釋和說明。

11.1 “參數(shù)設(shè)置”按鍵操作說明

“參數(shù)設(shè)置”類的按鍵有三個(gè),由上至下分別為“設(shè)置/確認(rèn)“按鈕、”加+“按鈕和”減-“按鈕。其主要功能是用來對十字路口東西向和南北向在各個(gè)階段(東西向直行、東西向左轉(zhuǎn)、南北向直行、南北向左轉(zhuǎn)和黃燈等待)的通行時(shí)間參數(shù)進(jìn)行設(shè)置和更新。

”設(shè)置/確認(rèn)“按鈕:共有三種功能:1 使系統(tǒng)進(jìn)入時(shí)間參數(shù)設(shè)置狀態(tài);2 對設(shè)置參數(shù)進(jìn)行順序切換;3 完成參數(shù)設(shè)置并返回退出;

”加+“按鈕:單擊一下,對應(yīng)時(shí)間參數(shù)加1。

” 減-“按鈕:單擊一下, 對應(yīng)時(shí)間參數(shù)減1。

11.2 “模式切換”按鍵操作說明

“模式切換”類按鍵共有五個(gè),由上至下分別為“正常模式“按鈕、”夜間模式“按鈕、”緊急模式“按鈕、”強(qiáng)制東西向通行模式“按鈕和”強(qiáng)制南北向通行模式“按鈕。此處操作非常簡單,不再贅述。交通燈在個(gè)模式下運(yùn)行時(shí)對應(yīng)的實(shí)際場景請參照上文說明。

以上為全部分享內(nèi)容,如有任何技術(shù)疑問,可以在文章下方留言交流或關(guān)注下方公眾號討論。

- END -

如果你覺得我的分享對你有那么一點(diǎn)點(diǎn)啟發(fā)和幫助,請幫忙點(diǎn)贊!

更多案例分享,請關(guān)注公眾號【電控夜雨十年燈】,一個(gè)專注于分享硬件電路設(shè)計(jì)、單片機(jī)開發(fā)、C語言設(shè)計(jì)和Proteus案例的旮旯,保證干貨滿滿!

本文為作者原創(chuàng),未經(jīng)允許,不得轉(zhuǎn)載,謝謝支持!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。