基于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); //黄灯亮起,死循环
}
}