目录
一、功能要求
要求实现的功能
二、设计方案
1.系统时钟
2. 红绿灯时长及夜间模式时间段的存储
3.紧急情况设计
4.夜间模式设计
5.夜间行人过路设计
6.系统时钟及系统参数设置显示
7.数码管显示倒计时
8.LED显示红绿灯
三、系统硬件设计
1.数码管显示
2.矩阵键盘
3.蜂鸣器
4.PCF8591 八位AD/DA转换器(光——>光强)
5.AT24C02
6.DS1302实时时钟芯片
7.LED
四、系统软件设计
1.延时函数、选择锁存器模块
2.矩阵键盘模块
3.AT24C02存储数据模块
4.DS1302时钟模块
5.LED红绿灯模块
6.LCD1602显示模块
7.数码管显示模块
8.交通灯主模块
设计步骤
五、结论
参考文献
附录
(一)按键功能
在这篇博客中,我将分享自己用单片机8051设计的交通灯的相关内容。 以下我的博客内容仅可借鉴,严禁抄袭。
交通灯演示视频
一、功能要求
用8051单片机为核心控制部件,设计一个十字路口的红绿灯控制系统。
要求实现的功能
1.该交通灯控制器。用LED灯模拟指示东西和南北方向的通行控制,每个方向三种颜色,通行规则遵守一般规则,即“红灯停、绿灯行、黄灯齐止步”。
2.交通灯倒计时以秒为单位,两个方向倒计时需用数码管显示当前剩余秒数。
3.两个方向的每种颜色的灯的计时时长可以通过键盘设定,参数一旦设定在当前计时结束时生效。设定参数保存在EEPROM中,系统开机时,从EEPROM中读取参数配置系统,启动交通控制。
4.控制系统支持情急模式,即当情况发生时,按下紧急按钮,整个系统停止计时,两个方向红灯闪烁,数码管显示当时倒计时的剩余时间,再次按下紧急按钮时,系统从停止的计时时间继续计时。
5.系统实现时钟计时功能。系统时钟采用实时时钟DS1302实现,系统当前时间用LCD显示。
6.系统支持夜间模式,从夜里到凌晨某个时间段,系统工作在夜间模式,此时黄灯闪烁,数码管不显示以降低功耗。
7.在夜间模式下,配置行人过街按键,当行人通过按键触发系统,给行人需要通行的方向一定时长的绿灯倒计时,两个方向的LED和数码管同时工作,倒计时结束后,系统继续夜间模式工作。
8.夜间模式的时间段可以设定,参数保存在EEPROM中。
9.系统参数的设定通过LCD作为显示部件。
10.系统参数支持一键恢复出厂设置。
11. 夜间模式下行人过路配置的绿灯时长可调功能。
二、设计方案
为了完成上述的功能要求,我们需要分析实现各个要求所需要用到的单片机上的模块,思考如何实现功能要求。
1.系统时钟
选择DS1302实时时钟芯片来配置系统时钟。
图2.1.1 DS1302寄存器地址(实时时钟)
2. 红绿灯时长及夜间模式时间段的存储
通过EEPROM芯片AT24C02来存储设置的东西南北方向红绿灯的时长以及夜间模式的时间段。AT24C02存储的内容具有掉电不丢失的特点。东西方向的绿黄红灯时长分别存储在0、2、4单元中,南北方向的绿黄红灯时长分别存储在1、3、5单元中。夜间模式的开始时间的时分存储在6、8单元,结束时间的时分存储在7、9单元。
图2.2.1 AT24C02器件地址
3.紧急情况设计
通过按键S6来切换正常模式与紧急情况模式,当为紧急情况时,关闭中断,红灯闪烁,数码管显示当前倒计时。
4.夜间模式设计
当系统时钟处于夜间模式时,黄灯闪烁,只有液晶显示系统时间,数码管不显示。
5.夜间行人过路设计
液晶显示系统时钟,led东西南北方向一直处于绿灯,数码管显示绿灯倒计时为20s。此时处于程序设计的状态s=6,一直到20s结束,恢复夜间模式。
6.系统时钟及系统参数设置显示
通过LCD1602显示,主要对其进行写操作以及清屏操作。
图2.4.1 LCD1602显示屏
7.数码管显示倒计时
前4个数码管显示东西方向倒计时,后4个显示南北方向倒计时。“A”代表红灯,“B”代表绿灯,“C”代表黄灯。
8.LED显示红绿灯
L1:东西方向红灯;L2:东西方向绿灯;L3:东西方向黄灯
L5:南北方向红灯;L6:南北方向绿灯;L7:南北方向黄灯
三、系统硬件设计
接下来,我将介绍一下单片机上所用到的各模块电路图原理,以及所集成的芯片说明。
1.数码管显示
图3.1 驱动数码管显示电路图
电路图说明:
P2口的P2.7、P2.6、P2.5来作为138译码器的输入端,138译码器的输出端Y4、Y5、Y6、Y7分别用来作为4个74HC02的输入端,然后4个74HC02的输出端分别连接了4个HC573的LE端,用来控制P0口数据的输入直通与锁存 ;4个HC573分别控制LED、蜂鸣器、数码管的显示位和com公共端,通过P2口的数据改变来选通想要的HC573(如控制数码管com公共端的HC573),再改变P0口的数据来选通想要数码管并锁存数据,再改变P2口的数据来选通想要的HC573(如控制数码管显示位的HC573),再改变P0口的数据来让该数码管显示想要的数字,并锁存数据。然后重复上述步骤,依次改变P2口和P1口的数据来让八个数码管依次动态显示 。
2.矩阵键盘
图3.2 矩阵键盘电路图
3.蜂鸣器
图3.3 蜂鸣器相关电路图
4.PCF8591 八位AD/DA转换器(光——>光强)
图3.4 AD/DA转换器电路图
PCF8591是一款单芯片、单电源、低功耗8位CMOS数据采集设备,具有四个模拟输入、一个模拟输出和一个串行IIC总线接口。
三个地址引脚A0, A1和A2用于编程硬件地址,允许使用多达8个设备连接到IIC总线而不需要额外的硬件。
该装置的功能包括模拟输入多路复用、片上跟踪和保持功能、8位模数转换和8位数模转换。最大转换速率由IIC总线的最大速度给出。
5.AT24C02
图3.5 AT24C02存储器电路图
AT24C02为EEPROM,可以实现数据保存,且掉电不丢失。AT24C02的总容量是256个字节,该芯片通过 IIC 总线与外部连接,其有一个专门的写保护功能。该芯片5脚作为数据线,也就是IIC通信的SDA;6脚作为时钟线,也就是IIC通信的SCL。
特点:工作电压:1.8V~5.5V;工作电流1mA,待机电流1uA;支持标准IIC通信协议;双向数据传输协议;支持硬件写保护功能;擦除次数可达10000次;存储数据时间超过100年。
6.DS1302实时时钟芯片
图3.6 DS1302时钟芯片
DS1302时钟芯片可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。DS1302芯片包含一个用于存储实时时钟的 31字节的静态 RAM,可通过简单的串行接口与微处理器通讯,将当前时钟存于RAM。该芯片读写时钟或 RAM 数据时有单字节或多字节(脉冲串模式)数据传送方式;串行输入输出利于减少管脚数。
7.LED
图3.7 LED电路图
8.LCD1602
图3.8 LCD1602电路图
1602液晶也叫1602字符型液晶,它是一种专门用来显示字母、数字、符号等的点阵型液晶模块。1602LCD是指显示的内容16×2,即最多只能显示32个字符。 它由若干个8X5等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用。
四、系统软件设计
(一)设计模块
接下来,我将分享我编写的模块代码以及对模块代码步骤的讲解。
本系统设计模块分为:延时函数、选择锁存器模块、矩阵键盘模块、AT24C02存储数据模块、DS1302时钟模块、LED显示模块、LCD1602显示模块以及交通灯主模块等。
1.延时函数、选择锁存器模块
#include "STC15.h"
#include "common.h"
void HC573_select(unsigned char channel)
{
switch(channel)
{
case 0:P2=(P2&0x1f)|0x00;break;
case 4:P2=(P2&0x1f)|0x80;break;
case 5:P2=(P2&0x1f)|0xa0;break;
case 6:P2=(P2&0x1f)|0xc0;break;
case 7:P2=(P2&0x1f)|0xe0;break;
}
}
void delay(unsigned int k)
{
unsigned char i,j;
while(k--)
{
for(i=0;i<50;i++)
for(j=0;j<10;j++)
;
};
}
图4.1.1 延时函数、选择锁存器模块代码
HC573_select函数用来选通不同的锁存器,来选择对LED、数码管、蜂鸣器进行操作;
Delay函数用于对EEPROM写操作、矩阵键盘模块。
2.矩阵键盘模块
#include "STC15.h"
#include "key_scan.h"
#include "common.h"
unsigned char keynum;
sbit R1=P3^0;
sbit R2=P3^1;
sbit R3=P3^2;
sbit R4=P3^3;
sbit C1=P4^4;
sbit C2=P4^2;
sbit C3=P3^5;
sbit C4=P3^4;
unsigned char keycode[16]={0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbd,0x7d,0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77}; //用线反转法时各个按键对应的段码
unsigned char bdata key; //定义了一个可以位寻址的变量
sbit key0=key^0;
sbit key1=key^1;
sbit key2=key^2;
sbit key3=key^3;
sbit key4=key^4;
sbit key5=key^5;
sbit key6=key^6;
sbit key7=key^7;
void scan2() //线反转法
{
unsigned char i=0;
R1=R2=R3=R4=0;
C1=C2=C3=C4=1;
if(C1==0 || C2==0 | C3==0 | C4==0) //有按键被按下
{
delay(1); //消抖
if(C1==0 || C2==0 | C3==0 | C4==0)
{
key7=C4;
key6=C3;
key5=C2;
key4=C1;
R1=R2=R3=R4=1;
C1=C2=C3=C4=0;
key3=R4;
key2=R3;
key1=R2;
key0=R1;
}
while((P3 & 0x0f)!=0x0f); //等待键释放
while(key!=keycode[i])
{
i++;
}
keynum=i; //得出该按键的序号(从右往左,从上往下编号)
}
}
图4.2.1 矩阵键盘模块代码
该模块采用线反转法。
线反转法:
无论被按键是处于第一行或是最后一行,均只需经过两步便能获得此按键所在的行列值。用线反转法识别闭合键时,要将行线接一个并行口,列线也接到一个并行口(也可以合用一个口),先让行线工作在输出方式,列线工作在输入方式,即往输出端口各行线上全部送“0”,输入端口都送“1”,然后从输入端口读入列线的值。如果此时有某个键被按下,则必定会使某一列线值为“0”。然后,重新设置两个并行端口的工作方式,使其互换,将刚才读得的列线值从并行端口输出,再读取行线的输入值,那么,在闭合键所在的行线上的值必定为“0”,这样,被按下的键的行列值就可以获得了。
3.AT24C02存储数据模块
#include"STC15.h"
#include"iic.h"
#include"AT24C02.h"
void WR_AT24C02(unsigned char address,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(address);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
unsigned char RC_AT24C02(unsigned char address)
{
unsigned char value;
IIC_Start();
IIC_SendByte(0xa0); //器件地址
IIC_WaitAck();
IIC_SendByte(address);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1); //读操作
IIC_WaitAck();
value=IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return value;
}
图4.3.1 AT24C02存储数据模块代码
该模块负责向AT24C02 EEPROM选定存储单元写内容以及对选定存储单元读内容。
4.DS1302时钟模块
#include"STC15.h"
#include"ds1302.h"
#include"AT24C02.h"
#include"time.h"
unsigned char year_0,month_0,day_0,hour_0,min_0,sec_0,week_0,min_1,hour_1;
void ds1302_init(unsigned int year,month,day,hour,minute,second,week)
{
Write_Ds1302_Byte(0x8e,0x00);
Write_Ds1302_Byte(0x8c,year);
Write_Ds1302_Byte(0x88,month);
Write_Ds1302_Byte(0x86,day);
Write_Ds1302_Byte(0x84,hour);
Write_Ds1302_Byte(0x82,minute);
Write_Ds1302_Byte(0x80,second);
Write_Ds1302_Byte(0x8a,week);
Write_Ds1302_Byte(0x8e,0x80);
}
void timer_show(unsigned char *stuno,unsigned char *clock)
{
year_0=Read_Ds1302_Byte(0x8d);
month_0=Read_Ds1302_Byte(0x89);
day_0=Read_Ds1302_Byte(0x87);
hour_0=Read_Ds1302_Byte(0x85);
min_0=Read_Ds1302_Byte(0x83);
sec_0=Read_Ds1302_Byte(0x81);
week_0=Read_Ds1302_Byte(0x8b);
hour_1=hour_0/16*10+hour_0%16;
min_1=min_0/16*10+min_0%16;
stuno[0]=2+48;
stuno[1]=0+48;
stuno[2]=year_0/16%16+48;
stuno[3]=year_0%16+48;
stuno[4]=45;
stuno[5]=month_0/16+48;
stuno[6]=month_0%16+48;
stuno[7]=45;
stuno[8]=day_0/16+48;
stuno[9]=day_0%16+48;
stuno[10]=45;
stuno[11]=week_0/16+48;
stuno[12]=week_0%16+48;
stuno[13]=0;
clock[0]=hour_0/16+48;
clock[1]=hour_0%16+48;
clock[2]=45;
clock[3]=min_0/16+48;
clock[4]=min_0%16+48;
clock[5]=45;
clock[6]=sec_0/16+48;
clock[7]=sec_0%16+48;
clock[8]=0;
}
图4.4.1 DS1302时钟模块代码
该模块中ds1302_init函数功能为将时钟芯片初始化为要求的系统时钟。对该芯片进行写操作时要先对地址0x8Eh写入0x00来关闭写保护,能对该芯片进行写操作,完成该操作后再对地址0x8Eh写入0x80来打开写保护。比如:对地址0x84、0x82、0x80进行写操作是分别对时分秒进行初始化操作。对地址0x85、0x83、0x81进行读操作,是读出此刻的时分秒。
Timer_show函数功能为将此时的时分秒保存在clock数组中,年月日周保存在stuno数组中。
5.LED红绿灯模块
#include"STC15.h"
#include"display.h"
#include "common.h"
#include "led.h"
unsigned char led_table[6]={0xed,0xeb,0xde,0xbe,0xee,0xdd}; //数组红绿黄
void led_1(unsigned char i)
{
P0=led_table[i];
HC573_select(4);
HC573_select(0);
}
图4.5 LED模块代码
6.LCD1602显示模块
#include"STC15.h"
#include"ds1302.h"
#include"AT24C02.h"
#include"time.h"
unsigned char year_0,month_0,day_0,hour_0,min_0,sec_0,week_0,min_1,hour_1;
void ds1302_init(unsigned int year,month,day,hour,minute,second,week)
{
Write_Ds1302_Byte(0x8e,0x00);
Write_Ds1302_Byte(0x8c,year);
Write_Ds1302_Byte(0x88,month);
Write_Ds1302_Byte(0x86,day);
Write_Ds1302_Byte(0x84,hour);
Write_Ds1302_Byte(0x82,minute);
Write_Ds1302_Byte(0x80,second);
Write_Ds1302_Byte(0x8a,week);
Write_Ds1302_Byte(0x8e,0x80);
}
void timer_show(unsigned char *stuno,unsigned char *clock)
{
year_0=Read_Ds1302_Byte(0x8d);
month_0=Read_Ds1302_Byte(0x89);
day_0=Read_Ds1302_Byte(0x87);
hour_0=Read_Ds1302_Byte(0x85);
min_0=Read_Ds1302_Byte(0x83);
sec_0=Read_Ds1302_Byte(0x81);
week_0=Read_Ds1302_Byte(0x8b);
hour_1=hour_0/16*10+hour_0%16;
min_1=min_0/16*10+min_0%16;
stuno[0]=2+48;
stuno[1]=0+48;
stuno[2]=year_0/16%16+48;
stuno[3]=year_0%16+48;
stuno[4]=45;
stuno[5]=month_0/16+48;
stuno[6]=month_0%16+48;
stuno[7]=45;
stuno[8]=day_0/16+48;
stuno[9]=day_0%16+48;
stuno[10]=45;
stuno[11]=week_0/16+48;
stuno[12]=week_0%16+48;
stuno[13]=0;
clock[0]=hour_0/16+48;
clock[1]=hour_0%16+48;
clock[2]=45;
clock[3]=min_0/16+48;
clock[4]=min_0%16+48;
clock[5]=45;
clock[6]=sec_0/16+48;
clock[7]=sec_0%16+48;
clock[8]=0;
}
图4.6.1 LCD1602显示模块代码
该模块代码主要负责向液晶进行写指令、写内容显示操作。
7.数码管显示模块
#include "STC15.h"
#include "display.h"
#include "common.h"
unsigned char tab[15]={0xc0,0xF9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0x88,0x83,0xc6}; //A-HONG,B-LV,C-HUANG
unsigned char cur_led;
unsigned char q;
void display(unsigned char *s,unsigned char n)
{
for(cur_led=0;cur_led<n;cur_led++)
{
q=s[cur_led];
P0=tab[q];
HC573_select(7);
HC573_select(0);
P0=0x01<<cur_led;
HC573_select(6);
HC573_select(0);
delay(3);
P0=0x00;
HC573_select(6);
HC573_select(0);
}
}
图4.7.1 数码管显示模块代码
8.交通灯主模块
在这里,我将只说明主模块的设计思路,而不提供完整代码。主模块主要是利用以上封装后的模块代码函数来进行编写。
设计步骤
1.首先将ds1302.c,iic.h底层模块调进工程中,然后编写好数码管显示、矩阵键盘、存储器读写、实时时钟、LED灯红绿灯、LCD1602显示、交通灯等模块。
2.在主模块中,在定时器0中断服务函数中,写一个状态机,来实现交通灯东西南北方向上状态的自动转换 。状态为:S0:东西绿、南北红;S1: 东西黄、南北红;S2: 东西红、南北绿;S3: 东西红、南北黄;S4: 将红绿灯时长重新赋值;S5: 夜间行人过路,给一定通行时间。
3.在while中,调用scan2()函数判断键值,timer_show读系统时钟,判断是否夜间时间到,若到则开启夜间模式,黄灯闪烁,数码管不显示,可按键触发行人过路模式。当按键S6按下,就开启紧急模式。按键S16对AT24C02重新写入内容并将数据重新读入系统中,为一键恢复出厂设置。设置红绿灯时长,夜间模式开启与结束时分,行人过路配置的绿灯时长的编程思想都类似,将修改的内容写入对应的AT24C02的存储单元中,并读入系统中,要有按键等待键释放的思想。
五、结论
本设计的难点在于要通过定时器来进行红绿灯的倒计时,而紧急情况、夜间模式下又需要关闭定时器中断,还有在进行系统参数的设置时也需要定时器中断关闭。在设计程序中,要时时刻刻考虑定时器是否要关闭,以及系统状态s应该设置的值。本设计中不仅要数码管显示,还要LCD1602显示系统时钟,因此要时刻考虑LCD1602使能端的开和关。交通灯的状态切换以及其他功能的实现主要是通过状态机来判断,根据状态切换的条件来判断系统该处于何种状态。
参考文献
1.单片机原理与应用技术,高惠芳主编. 科学出版社, 2010年5月;
2. MCS-51系列单片机系统及其应用,蔡美琴主编,高等教育出版社,2012年1月第2版;
3. 单片机的C语言应用程序设计,马忠梅主编,北京航空航天大学出版社,2017年10月出版;
4. 蓝桥杯单片机开发板官方资料(电子文档);
5. 其他网络资源。
附录
(一)按键功能
S7:白天模式。
S11:可切换调整的内容“g-东西方向绿灯、G-南北方向绿灯、y-东西方向黄灯、Y-南北方向黄灯、r-东西方向红灯、R-南北方向红灯”。
S15: 可对S11选择内容作加操作,用LCD1602显示。可将设置内容保存在EEPROM中,掉电不丢失。
S19: 可对S11选择内容作减操作,用LCD1602显示。 可将设置内容保存在EEPROM中,掉电不丢失。
S6: 紧急情况按键。
S10:可切换要调整的内容(夜间模式的时间段),用LCD1602显示。“h”“m”代表开始时间的时分,“H”“M”代表终止时间的时分。
S14: 可对S10选择内容作加操作,用LCD1602显示。可将设置内容保存在EEPROM中,掉电不丢失。
S18: 可对S10选择内容作加操作,用LCD1602显示。可将设置内容保存在EEPROM中,掉电不丢失。S5:调出EEPROM中保存的x号闹钟内容。
S8:夜间模式时间段调整结束后的确认按键,若调整了时间段,则该按键必须按下确认。
S5: 对夜间模式下行人过路时间的设置,进行加操作。可将设置内容保存在EEPROM中,掉电不丢失。
S9: 对夜间模式下行人过路时间的设置,进行减操作。可将设置内容保存在EEPROM中,掉电不丢失。
S13: 夜间模式下行人过路时间的设置结束后的确认按键,若调整了该内容,则该按键必须按下确认。
S12:开启夜间模式下行人过路模式。
S16:一键恢复出厂设置。
LED对应的红绿灯关系:
L1:东西方向红灯;L2:东西方向绿灯;L3:东西方向黄灯文章来源:https://www.toymoban.com/news/detail-799066.html
L5:南北方向红灯;L6:南北方向绿灯;L7:南北方向黄灯文章来源地址https://www.toymoban.com/news/detail-799066.html
到了这里,关于单片机8051设计交通灯的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!