基于51單片機實作基本交通燈系統
通過外部中斷0、1實作對交通燈狀态的緊急控制
倒計時用1602顯示分别為
SNTime
EWTime
Wait
lcd頭檔案
#ifndef __LCD_H_
#define __LCD_H_
/**********************************
包含頭檔案
**********************************/
#include<reg52.h>
#include"intrins.h"
//---重定義關鍵詞---//
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
/**********************************
PIN口定義
**********************************/
#define LCD1602_DATAPINS P2
sbit LCD1602_E=P1^0;
sbit LCD1602_RW=P1^1;
sbit LCD1602_RS=P1^2;
/**********************************
函數聲明
**********************************/
/*在51單片機12MHZ時鐘下的延時函數*/
void Lcd1602_Delay1ms(uint c);
void Busy(void);//忙檢測函數
/*LCD1602寫入8位指令子函數*/
void LcdWriteCom(uchar com);
/*LCD1602寫入8位資料子函數*/
void LcdWriteData(uchar dat);
/*LCD1602初始化子程式*/
void LcdInit();
void LcdSetCursor(uchar x,uchar y);
void DisplayOneChar(uchar X, uchar Y, uchar DData);
void LcdShowStr(uchar x,uchar y,uchar *str);
#endif
lcd1602程式
#include "lcd.h"
/*******************************************************************************
* 函 數 名 : Lcd1602_Delay1ms
* 函數功能 : 延時函數,延時1ms
* 輸 入 : c
* 輸 出 : 無
* 說 名 : 該函數是在12MHZ晶振下,12分頻單片機的延時。
*******************************************************************************/
void Lcd1602_Delay1ms(uint c)
{
uchar a,b;
for (; c>0; c--)
{
for (b=199;b>0;b--)
{
for(a=1;a>0;a--);
}
}
}
/*******************************************************************************
* 函 數 名 : Busy
* 函數功能 : 忙檢查函數
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void Busy(void)
{
uchar temp=0;
do{
LCD1602_RW = 1;
LCD1602_RS = 0;
LCD1602_E = 0; //使能
_nop_();
LCD1602_E = 1;
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();//一個機器周期1us,大于150ns即可
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();//為了仿真出來,延長脈寬,28us
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
LCD1602_E = 0;
temp=LCD1602_DATAPINS;
}while(temp&0x80);
}
/*******************************************************************************
* 函 數 名 : LcdWriteCom
* 函數功能 : 向LCD寫入一個位元組的指令
* 輸 入 : com
* 輸 出 : 無
*******************************************************************************/
void LcdWriteCom(uchar com) //寫入指令
{
LCD1602_DATAPINS = com; //放入指令
LCD1602_E = 0; //使能
LCD1602_RS = 0; //選擇發送指令
LCD1602_RW = 0; //選擇寫入
_nop_();//一個機器周期1us,大于30ns即可
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(1);
LCD1602_E = 0;
}
/*******************************************************************************
* 函 數 名 : LcdWriteData
* 函數功能 : 向LCD寫入一個位元組的資料
* 輸 入 : dat
* 輸 出 : 無
*******************************************************************************/
void LcdWriteData(uchar dat) //寫入資料
{
LCD1602_DATAPINS = dat; //寫入資料
LCD1602_E = 0; //使能
LCD1602_RS = 1; //選擇發送資料
LCD1602_RW = 0; //選擇寫入
_nop_();//一個機器周期1us,大于30ns即可
LCD1602_E = 1; //寫入時序
Lcd1602_Delay1ms(1);
LCD1602_E = 0;
}
/*******************************************************************************
* 函 數 名 : LcdInit()
* 函數功能 : 初始化LCD屏
* 輸 入 : 無
* 輸 出 : 無
*******************************************************************************/
void LcdInit() //LCD初始化子程式
{
Lcd1602_Delay1ms(1);
LcdWriteCom(0x38); //設定功能,8位,兩行,5X7
Busy();
LcdWriteCom(0x0c); //開顯示不顯示光标
Busy();
LcdWriteCom(0x06); //寫一個AC指針加1
Busy();
LcdWriteCom(0x01); //清屏
Busy();
LcdWriteCom(0x80); //設定資料指針起點
}
//指定坐标
void LcdSetCursor(uchar x,uchar y)
{
uchar addr;
y &= 0x01;
x &= 0x0F; //限制X不能大于15,Y不能大于1
if(y == 0)
addr = 0x00 + x;
else
addr = 0x40 + x;
LcdWriteCom(addr|0x80);
}
//按指定位置顯示一個字元
void DisplayOneChar(uchar x, uchar y, uchar DData)
{
LcdSetCursor(x,y); //目前字元的坐标
LcdWriteData(DData); //發資料
}
//顯示字元串
void LcdShowStr(uchar x,uchar y,uchar *str)
{
LcdSetCursor(x,y); //目前字元的坐标
while(*str != '\0')
{
LcdWriteData(*str++);
}
}
主函數部分
實作紅黃綠燈的交替變換和lcd1602的倒計時
#include "reg52.h" //定義特殊寄存器
#include "lcd.h" //調用lcd頭檔案 lcd1602
typedef unsigned int u16;
typedef unsigned char u8; //重定義
sbit snred=P1^7;
sbit sngreen=P1^5;
sbit snyellow=P1^6;
sbit ewred=P3^7;
sbit ewgreen=P1^4;
sbit ewyellow=P3^6; //位定義各個led接的io口
sbit k1=P3^2;
sbit k2=P3^3; //位定義按鍵
int time=19; //定義倒計時變量
u8 x=0; //半秒指派變量,黃燈閃爍
u8 ew[]="EWTime";
u8 sn[]="SNTime";
u8 dd[]="Wait"; //lcd第一行顯示函數
u8 code ASCII[13] = {'0','1','2','3','4','5','6','7','8','9','.','-','M'}; //顯示在lcd1602上面的ASCII碼
/****************************
*函數名稱:delay_ms
*函數功能:延時_ms
*****************************/
void delay_ms(u16 x) //延時ms
{
unsigned int i,j;
for(i=x;i>0;i--)
for(j=110;j>0;j--);
}
/****************************
*函數名稱:xianshi
*函數功能:通過檢測time變量的值決定紅綠燈狀态,和時間一起顯示在1602上面
****************************/
void xianshi()
{ u8 i,a=0;
if(time>=10) //判斷是否SN通行
{if(time<=12) //判斷SN是否黃燈
i=2;
else
i=0;
}
else //判斷是否EW通行
{
if(time<=2) //判斷EW是否黃燈
i=3;
else
i=1;
}
switch(i)
{
case(0):{ sngreen=0;snred=1;snyellow=1;ewred=0;ewyellow=1;ewgreen=1; LcdShowStr(4,0,sn);DisplayOneChar(4, 1, ASCII[time-10]);break;} //SN通行狀态
case(1):{ sngreen=1;snred=0;snyellow=1;ewred=1;ewyellow=1;ewgreen=0; LcdShowStr(4,0,ew);DisplayOneChar(4, 1, ASCII[time]);break;} //EW通行狀态
case(2):{ if(x==0) {sngreen=1;snred=1;snyellow=0;ewred=0;ewyellow=1;ewgreen=1;} else{sngreen=1;snred=1;snyellow=1;ewred=0;ewyellow=1;ewgreen=1; } LcdShowStr(4,0,dd);DisplayOneChar(4, 1, ASCII[time-10]);break;} //SN黃燈閃爍
case(3):{ if(x==0) {sngreen=1;snred=0;snyellow=1;ewred=1;ewyellow=0;ewgreen=1;} else{sngreen=1;snred=0;snyellow=1;ewred=1;ewyellow=1;ewgreen=1; } LcdShowStr(4,0,dd);DisplayOneChar(4, 1, ASCII[time]);break;} //EW黃燈閃爍
default:{break;}
}
if(time==-1) //如果時間值到0,重新賦最大值
time=19;
}
/****************************
*函數名稱:timer
*函數功能:打開定時器0和外部中斷0、1允許
****************************/
void timer()
{
TMOD=0x01;//定時器工作于方式1
TH0=(65536-50000)/256;//定時器賦初值
TL0=(65536-50000)%256;
EA=1; //CPU開中斷總允許
ET0=1;//開定時中斷
TR0=1;//啟動定時
IT0=1;//外部中斷0下降沿觸發
EX0=1; //允許外部中斷
IT1=1;//外部中斷0下降沿觸發
EX1=1; //允許外部中斷
}
/****************************
*函數名稱:main
*函數功能:主函數,調用子函數,程式運作的主題
****************************/
void main()
{timer(); //調用中斷允許函數,打開中斷位
LcdInit(); //lcd初始化函數
while(1)
{
xianshi(); //調用led、lcd顯示函數
}
}
/****************************
*函數名稱:timer0
*函數功能:定時器0溢出函數,通過精準計時改變time、x值
****************************/
void timer0()interrupt 1
{
u8 count;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
count++;
if(count==10) //不超過半秒x=0,超過半秒x=1
x++;
if(count==20) //一秒time——
{time--;
count=0;
x=0;
}
}
/****************************
*函數名稱:Int0
*函數功能:外部中斷0控制函數,使lcd變為緊急狀态
****************************/
void Int0 () interrupt 0
{
delay_ms(10);
if(k1==0)
{
sngreen=1;snred=0;snyellow=1;ewred=0;ewyellow=1;ewgreen=1; while(1); //紅燈亮起,死循環
}
}
/****************************
*函數名稱:Int1
*函數功能:外部中斷1控制函數,使lcd變為霧天狀态
****************************/
void Int1 () interrupt 2
{
delay_ms(10);
if(k2==0)
{
sngreen=1;snred=1;snyellow=0;ewred=1;ewyellow=0;ewgreen=1; while(1); //黃燈亮起,死循環
}
}