天天看點

51交通燈系統基于51單片機實作基本交通燈系統

基于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);  //黃燈亮起,死循環
  }      
 }