基于STC89C51单片机的简易交通信号灯
文章目录
前言
本设计学校的一次单片机实训。
一、基本原理
利用51单片机控制各个路口红绿灯及时间显示。
1、设计的重点:
1、题目要求
1、各个路口红绿灯亮灭的规则,暂不考虑左转方向;
2、倒计时的实现,利用单片机的定时器进行计数得到秒信号;
3、时间显示:东西南北四个方向的时间一致,当东西方向为60秒绿灯通行时间,同时南北方向为60秒红灯禁止时间,因此硬件连接时可考虑东西南北方向可采用同一接法;最后相当于2个数码管动态显示,具体见参考电路框图。
4、按键设置(扩展要求):设置键按一次,设置主干道通信时间(即次干道禁止时间),按第二次,设置主干道禁止时间(即次干道通信时间),按第三次,可作为紧急通信键。设置时间需要确定,可通过确定键实现,也可通过延时确定,如10秒。当然也可根据需要增加相应的按键。
2、性能指标要求
1、各方向的红、绿色信号灯能按照设定规则运行;
2、绿灯亮之前,黄灯闪烁5次;
3、红灯和绿灯倒计时间能够正确显示;
4、两干道的车辆不会会车冲突。
5、可以扩展其他功能(如按键设置时间,按键模拟警车)
二、原理图设计
1、电路框图
大概的设计流程图如下:
2、原理图
原理图画法有很多种,符合设计要求即可,基本就是在最小系统的基础上加入按键电路、数码管显示电路、led信号灯三个部分就行了。一般情况下数码数码管接到P0口上( 记得加上拉电阻),六个信号灯接到P1口,四个按键接到P3口,(P3.4、P3.5、P3.6、P3.7)。
三、硬件电路搭建
1.元器件
主控芯片:stc89c52rc、数码管:两位共阴数码管(5621AS-1)
洞洞板一块(万用板)
12颗led灯(红黄绿分别4颗)、四个按键、以及搭建最小系统所需的原件
另外还需一个TTL下载器用于代码的烧录。
跳线若干。
1.实物焊接图
实物焊接正面图
实物背面焊接图
焊接过程注意事项(难点)
其实整个电路难点在于焊接,考验对烙铁的使用和实际动手的能力(虽然我焊接的比较丑但在整个焊接过程中只要心中有图基本就不会出什么问题了)。
个人焊接建议是先把最先系统部分焊接完后先烧录一下代码看看能不能成功烧录,不要着急焊接其他部分,只要完成了最小系统的焊接后面的就照着原理图连线。
另外就是分不清数码管上的10个引脚如何焊接的,只要把数码管对应下图连到P0口,a, b, c, d, e, f, g, dp 对应P0.0—P0.7,1和2是位选端,接到P2.0和P2.1。
四、软件代码部分
1、编译环境和烧录软件
编译器是keil5会使用就行这里不过多讲解只要会建工程烧代码就行了,
代码烧录器是stc-isp,
1.代码
代码部分基本每一句我都给了注释,可能有些没描述好,但基本只要了解C语言基本都能读懂了,打开Keil uVision5或者Keil uVision4,新建个工程复制粘贴就去就可以了。
代码如下(示例):
#include"REG52.H"
#include"intrins.h"
#define uchar unsigned char//定义全局变量无符号字符型uchar
#define uint unsigned int//定义全局变量无符号整型uint
uchar Tab[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//数码管段码
uchar nt=60,wt=60,sz=0,t,DJS=60,seg=60,tx=10;//定义变量
bit ms=0;//标志位
sbit k = P3^4; //进入时间设置
sbit g = P3^5; //结束设置
sbit a = P3^7; //时间加
sbit j = P3^6; //时间减
sbit we1=P2^0;//数码管位选端第一位
sbit we2=P2^1;//数码管位选端第二位
sbit NSG=P1^2;//南北方向绿灯
sbit NSY=P1^1;//黄灯
sbit NSR=P1^0;//红灯
sbit WEG=P1^5;//东西方向绿灯
sbit WEY=P1^4;//黄灯
sbit WER=P1^3;//红灯
/函数声明/
void delay(uint t);//延时函数
void display();//数码管显示函数
void Init_Timer0(void);//定时器
void NST();//南北指示灯函数
void WET();//东西指示灯函数
void jstx();//紧急通行
void keycan();//按键设置函数
主函数/
void main()
{
Init_Timer0();//定时器初始化
while(1)
{
if(sz==3) //判断标志位第三次按下为紧急通行
{
//ms==!(1&&0);//ms==3紧急通行时黄灯不闪硕
seg=tx; //数码管显示的值为10
jstx(); //执行紧急通行函数
}
if(sz==1) //判断标志位第1次按下为南北倒计时设置
{seg=nt;} //数码管初始值为南北倒计时时间60秒
if(sz==2) //判断标志位第2次按下为南北倒计时设置
{seg=wt;} //数码管初始值为东西倒计时时间60秒
if(sz==0) //没按下时正常执行正常通行
{
if(ms==0) //如果ms==0,
{NST();} //执行南北倒计时设置
if(ms==1) //如果ms==1,
{WET();} //执行东西倒计时设置
}
keycan();//按键子函数
display();//数码管显示子函数
}
}
/延时函数/
void delay(uint t)
{
uchar x,y;
for(x=0;x<t;x++) //普通延时函数
for(y=0;y<200;y++);
}
///数码管显示函数//
void display()
{
we1=0;//位选十位关
we2=1;//位选个位开
P0=Tab[seg%10]; //显示个位
delay(5); //延时
P0=0x00; //数码管清零(消影)
we1=1; //位选十位开
we2=0; //位选个位关
P0=Tab[seg/10]; //显示十位
delay(5); //延时
P0=0x00; //数码管清零
}
//定时器
void Init_Timer0(void)
{
TMOD &= 0XF0;
TMOD |= 0x01; //使用模式1,16位定时器
TH0=0x3c; //装初值3c b0 为50ms
TL0=0xb0;
IP=0x02; //定时器0优先级高
TR0=1; //启用T0计数器/定时器
ET0=1; //打开T0定时器中断
EA=1; //总中断开关,任何中断都无法执行
}
void timer0 (void) interrupt 1 //using 0
{
TH0=0x3c; //初值,产生50ms定时
TL0=0xb0;
t++; //t一直自加,加一次是50ms加到20次
if(t==20) //20个50毫秒等于1000毫秒等于1秒
{
DJS--; //倒计时自减
t=0;
if(DJS<=5)//如果倒计时小于等于5秒
{
if(ms==1) //判断通道如果标志位ms为1代表南北通道的黄灯闪烁
{NSY=~NSY;} //黄灯闪烁
if(ms==0) //ms为0代表东西通道的黄灯闪烁
{WEY=~WEY;} //黄灯闪烁
else(NSY||WEY==1);
}
if(DJS==0) //如果倒计时结束
{
ms=~ms; //南北通道替换
NSY=1; //南北通道黄灯熄灭
WEY=1; //东西通道黄灯熄灭
if(ms==0) //第一个按键标志位ms=0
{DJS=nt;} //倒计时为初始值nt=60秒
if(ms==1) //第一个按键标志位ms=1
{DJS=wt;} //倒计时为初始值wt=60秒
}
if(sz==3) //判断标志位第3次按下进入紧急通行模式
{
tx--; //紧急模式下的10秒倒计时(tx变量开头处设置的10)
if(tx==0)//如果倒计时结束
{sz=0;}//恢复正常通行状态
}
}
}
/**********东西通行函数*******************/
void WET()
{
seg=DJS;//数码管显示初始状态的60秒倒计时时间
NSG=1;//南北绿灯灭
NSR=0;//南北红灯亮
NSY=1;//南北黄灯灭
WER=1;//东西红灯灭
WEG=0;//东西绿灯亮
WEY=1;//东西黄灯灭
}
/**********南北通行函数*******************/
void NST()
{
seg=DJS;//数码管显示初始状态的60秒倒计时时间
NSG=0;
NSR=1;
NSY=1;
//亮灭情况同东西通行情况同理
WER=0;
WEG=1;
WEY=1;
}
/**************紧急通行函数*******************/
void jstx()
{
NSG=1;
NSR=0;
NSY=1;//只有红灯亮,其他全灭
WEG=1;
WER=0;
WEY=1;
}
/**************按键设置函数*******************/
void keycan()
{
if(k==0)//
{
delay(10);//延时一下是为了消抖
if(k==0) //设置键按下进入设置状态
{
sz++; //设置按键按一次自加一次
if(sz==4) //第四次按下
{sz=0;} //回到初始状态
if(sz==3) //判断标志位第3次按下进入紧急通行模式
{tx=10;} //紧急模式倒计时时间赋值为10
}
while(!k);//不满足第一个按键按下就跳出循环
}
if(a==0&&sz==1) //
{
delay(10);//延时消抖
if(a==0&&sz==1)//a变量代表加按键sz变量代表设置按键
{
nt++; //按了一次设置键后,按时加键,南北方向时间加一
if(nt==61) //南北方向上的时间加到60,为什是61?因为按第61次的时候其实按的是1
{nt=1;} //跳回1
}
while(!a); //跳出循环
}
if(a==0&&sz==2) //按了第二次设置键后,按时加键,西南方向时间加一
{
delay(10);//延时消抖
if(a==0&&sz==2)
{
wt++;//东西方向时间加
if(wt==61)//东西方向上的时间加到60,为什是61?因为按第61次的时候其实按的是1
{wt=1;}//跳回1
}
while(!a);//跳出循环
}
if(j==0&&sz==1)//按了第一次设置键后,按时间减按键,按一次南北方向时间减一
{
delay(10);//延时消抖
if(j==0&&sz==1)
{
nt--;//南北方向时间减
if(nt==0)//减到0
{nt=60;}//跳回60
}
while(!j);//跳出循环
}
if(j==0&&sz==2)//按了第二次设置键后,按时间减键,西南方向时间减一
{
delay(10);//延时消抖
if(j==0&&sz==2)
{
wt--;
if(wt==0)//减到0
{wt=60;}//跳回60
}
while(!j);//跳出循环
}
if(g==0)//设置完成,按下后保存设置,退出设置状态
{
delay(10); //延时消抖
if(g==0)
{sz=0;} //回到初始状态
while(!g); //跳出循环
}
}
总结
这是我大一期间的一个单片机实训,出于最近好多学弟问设计原理就简单潦草的总结了一下,当然最核心的资料都是有的,只要动手能力强一点,照着原理图焊接好电路,烧代码基本就OK了。