MCS-51单片机课程设计报告——交通灯控制系统姓名:朱正威学号:110901418指导老师:潘峰东华大学信息学院自动化系2014.6.22目录一、项目概述 (3)二、系统设计 (3)1.设计思想 (3)2.方案可行性分析 (3)3.总体方案 (3)三、硬件设计 (5)1.单片机最小系统部分 (5)2.LED数码管串行显示部分 (5)3.独立按键部分 (5)四、软件设计 (6)1.软件设计思想 (6)2.程序流程图 (6)3.程序清单 (7)五、系统仿真及调试 (13)六、结果与展望 (15)七、参考文献 (15)一、项目概述项目所要设计的是交通灯控制系统,十字路口交通灯由红、绿两色LED显示器(两位8段LED显示器)组成,LED显示器显示切换倒计时,以秒为单位,每秒更新一次;为确保安全,绿LED计数到0转红,经5秒延时(显示红色0)后,另一道开始绿色倒计时。
1)主干道(A道)先通行且通行时间为45s;(加5秒红灯延时,共50秒)2)支道(B道)通行时间为25 s;(加秒红灯延时,共30秒)3)主道与支道的车辆交错通行;4)若遇紧急情况,按开关时,主道与支道都为红灯20 s5)根据实时交通堵塞情况人为控制时,按K2时,主道延时30 s通行,按K3时,支道延时30 s通行。
设计以AT89C51为核心的控制电路,并编写相关的系统软件。
二、系统设计1.设计思想该模拟交通灯控制系统采用模块化结构,主要分为定时器中断控制、按键扫描、LED数码管显示三个部分。
在设计完成一个方向上的红绿灯数码管计时后,再进行两个方向红绿灯的切换显示以及特殊情况下的处理。
2.方案可行性分析采用AT89C51作为系统主控芯片,其包含两个定时器中断T0和T1、两个外部中断,以及4个I/O端口P0到P3端口。
本系统采用其定时器T1进行定时,每隔一定时间定时中断一次,在中断程序内进行变量自加,以此可以设置任意长的定时时间。
如设置1s的定时改变红绿灯LED数码管显示值,设置0.2m的按键扫描周期进行按键定时扫描。
为了节省I/O口资源以及硬件连接上的方便,采用串口显示芯片MAX7219进行LED数码管显示部分的设计。
整个方案设计结构清晰明了,硬件连接简洁,软件编程模块清晰,经实践验证,此方案可行。
3.总体方案在Proteus环境中进行硬件电路的设计和搭建,具体硬件电路设计如图1、2所示。
在Keil环境下进行软件设计51单片机编程,为定时器中断和MAX7219串口显示和主函数部分分别建立相应的源文件和头文件,进行模块化编程。
图1、硬件连接图图2、整体系统图三、硬件设计系统硬件设计主要分为三个部分,即单片机最小系统部分、LED数码管串行显示部分和独立按键部分。
1.单片机最小系统部分按要求选用AT89C51型号单片机,晶振频率12MHz,使用内部RAM和ROM。
由于Proteus环境下默认无需晶振电路和复位电路等,所以并未画出。
2.LED数码管串行显示部分MAX7219是一种集成化的串行输入/输出共阴极显示驱动器,与单片机只需三根信号进行通信,可以连接8位数字的7段LED数码管。
其内部集成了数据保持、BCD译码器、多路扫描器、段驱动器和位驱动器。
每片MAX7219最多可同时驱动8个LED数码管,而交通灯控制系统正好需要8个LED数码管。
同时,利用其内部BCD译码功能,可以省去额外的软件或硬件译码操作。
具体连接如图3所示。
图3、MAX7219连接图3.独立按键部分该系统需要根据外部按键K1、K2和K3进行人工干预,按键较少,可以采用三个独立按键接在三个单片机I/O引脚上,在定时中断内进行按键的扫描。
按键连接部分如图4所示。
图4、按键连接图四、软件设计1.软件设计思想在Keil环境下进行软件设计51单片机编程,软件部分主要分为定时器中断、MAX7219串口显示和主函数部分,进行模块化编程,为各个部分分别建立相应的.h头文件和.c源文件。
定时器中断部分:选用定时器T1,方式2,8位自动重装初值。
250us产生一次定时器中断,由于单片机晶振为12MHz,经计算,计数初值为6。
在中断服务程序内进行变量counter的自加,当counter自加40次之后即为一次10ms中断,以此为基本时间单位可以进行进一步的定时。
MAX7219串口显示部分:首先定义串口数据发送函数MAX7219_write,然后2.程序流程图整个程序的流程图如图5所示。
图5、程序流程图3.程序清单1)MAX7219串口显示程序#include <reg51.h>#include "MAX7219.h"#define uchar unsigned charsbit MAX7219_DIN = P1^0; //串行数据输入DINsbit MAX7219_CLK = P1^1; //时钟信号CLKsbit MAX7219_LOAD = P1^2; //数据锁存脉冲信号LOAD/************MAX7219写寄存器函数**************/// addr:寄存器地址// dat: 写入寄存器的值//说明: D12~D15为无关位,D8~D11为寄存器地址,D0~D7为命令或待显数据void MAX7219_write(uchar addr, uchar dat){uchar i=0;MAX7219_LOAD=0;for(i=0;i<8;i++) //先写地址{MAX7219_CLK = 0;MAX7219_DIN = (addr&(0x80>>i))? 1:0;i++;i--;MAX7219_CLK = 1; //时钟上升沿写入}for(i=0;i<8;i++) //再写数据{MAX7219_CLK = 0;MAX7219_DIN = (dat&(0x80>>i))? 1:0;i++;i--;MAX7219_CLK = 1;}MAX7219_LOAD=1;}/*********************************************//*************MAX7219初始化函数***************/void MAX7219_init(){MAX7219_write(0x0A,0x07); //亮度地址0AH,0x00~0x0F,0x0F最亮MAX7219_write(0x0B,0x07); //设置扫描LED个数地址0BH,扫描8个MAX7219_write(0x0C,0x01); //工作模式地址0x0C. 0x00:ShutDown;0x01:NormalMAX7219_write(0x09,0xFF); //编码模式地址0x09. 0x00~0xFF:哪一位为1,哪一位就支持译码}/*********************************************/2)按键扫描函数/******************按键扫描函数******************/uchar key_scan(){uchar key,valid_key,delay=125;key=P1&0x70;while(delay--);valid_key=P1&0x70;if(key!=valid_key) //按键消抖return 0;switch(key){case 0x60: //按下K1按键return 1;case 0x50: //按下K2按键return 2;case 0x30: //按下K3按键return 3;default: //其它情况不考虑return 0;}}/************************************************/3)定时器初始化及中断处理/************** 定时器1中断服务程序 *************/void INT_timer0()interrupt 3{uchar key_temp=0;counter++;if(counter==40) //10ms一次中断处理{counter=0;if(cnt>=100 ){cnt = 0;led_counter(); //1s刷新一次数码管}cnt++;if(cnt1>=20) //0.2s一次按键扫描{cnt1=0;key_temp=key_scan();if(key_temp==1)key=1;else if(key_temp==2){num[3]+=3; //主干道为红灯时延时30s通行if(num[3]>9)num[3]=9;}else if(key_temp==3) //支道为红灯时延时30s通行{num[1]+=3;if(num[1]>9)num[1]=9; //可累积延时,但不超过99s}}cnt1++;}}/************************************************//****************** 定时器初始化 ****************/void Init_timer(){counter=0;TMOD=0x20; //8位定时器,自动重装初值TH1= 6; //定时250usTL1= 6;TR1 = 1;ET1 = 1;}/************************************************/4)LED数码管模拟交通灯显示static uchar counter,cnt,cnt5,cnt1,hold_flag=0,dir_flag=0,key; char num[8]={6,4,6,2,1,2,0,0}; //LED初始显示的数字/* 红绿灯数码管显示与数组值对应关系示意图(主道) 红灯绿灯num[3] num[2] num[1] num[0](支道) 绿灯红灯num[3] num[2] num[1] num[0](紧急情况,主道支道) 红灯num[5],num[4]*//***************** 红绿灯计时函数 ***************/void led_counter(){if(key==1) //按下K1按键的处理{num[4]--;if(num[5]>0){if(num[4]<0){num[4]=9; //个位从0数到9循环num[5]--;}}if(num[4]<0) //紧急情况延时20s完之后{key=0;num[4]=1;num[5]=2;}else{MAX7219_write(3,num[4]); //主道红灯20s计数MAX7219_write(4,num[5]);MAX7219_write(7,num[4]); //支道红灯20s计数MAX7219_write(8,num[5]);MAX7219_write(1,15); //主道绿灯灭MAX7219_write(2,15);MAX7219_write(5,15); //支道绿灯灭MAX7219_write(6,15);}}else{if(hold_flag) //5s红灯延时标志置位后5s延时{num[0]=6;num[1]=4;num[2]=6;num[3]=2;cnt5++;if(cnt5>=4){hold_flag=0;cnt5=0;}}else if(!dir_flag) //主干道通行{num[0]--;if(num[1]>0){if(num[0]<0){num[0]=9; //个位从0数到9循环num[1]--;}}if(num[0]<0) //主道绿灯十位为0,个位也为0之后{num[0]=0;num[1]=0;hold_flag=1; //5s红灯延时标志置位dir_flag=1; //换支道行驶标志置位MAX7219_write(3,0); //主道红灯显示"0"MAX7219_write(4,0);MAX7219_write(1,15); //主道绿灯灭MAX7219_write(2,15);}else{MAX7219_write(1,num[0]); //主道绿灯计数MAX7219_write(2,num[1]);MAX7219_write(7,num[0]); //支道红灯和主道绿灯同时计数MAX7219_write(8,num[1]);MAX7219_write(3,15); //主道红灯灭MAX7219_write(4,15);MAX7219_write(5,15); //支道绿灯灭MAX7219_write(6,15);}}else //支道通行{num[2]--;if(num[3]>0){if(num[2]<0){num[2]=9; //个位从0数到9循环num[3]--;}}if(num[2]<0) //主道绿灯十位为0,个位也为0之后{num[2]=0;num[3]=0;hold_flag=1; //5s红灯延时标志置位dir_flag=0; //换主道行驶标志置位MAX7219_write(7,0); //支道红灯显示"0"MAX7219_write(8,0);MAX7219_write(5,15); //支道绿灯灭MAX7219_write(6,15);}else{MAX7219_write(5,num[2]); //支道绿灯计数MAX7219_write(6,num[3]);MAX7219_write(3,num[2]); //主道红灯和支道绿灯同时计数MAX7219_write(4,num[3]);MAX7219_write(7,15);MAX7219_write(8,15); //支道红灯灭MAX7219_write(1,15); //主道绿灯灭MAX7219_write(2,15);}}}}/************************************************/5)主函数#include <reg51.h>#include "MAX7219.h"#include "TIMER.h"void main(void){MAX7219_init(); //7219串口显示芯片初始化Init_timer(); //定时器中断初始化EA=1; //开总中断,系统开始计时while(1);}五、系统仿真及调试在Proteus环境下,将上述程序进行编译后加载到单片机中。