上个学期帮老师带了本科课程设计,40个同学,我就想着先做一遍吧,就随便选了一个交通灯的题目。题目如下
用AT89S52单片机控制一个交通信号灯系统。设A车道与B车道交叉组成十字路口,A是主道,B是支道,要求如下:
(1)用发光二极管模拟交通信号灯,用按键开关模拟车辆检测信号;
(2)正常情况下,A、B两车道轮流放行,A车道放行12s,其中3s用于警告;B车道放行8s,其中3s用于警告;(警告为黄灯闪烁)
(3)在交通繁忙时,交通信号灯控制系统应有手控开关,可人为地改变信号灯的状态,以缓解交通拥挤情况。在B车道放行期间,若A车道有车而B车道无车,按下开关k1使A车道放行5s,在A车道放行期间,若B车道有车而A车道无车,按下开关k2使B车道放行5s;
(4)有紧急车辆通过时,按下k3开关使A、B车道均为红灯,禁行5s。
看了题目,感觉比较正常,就做呗。其实也简单,按下按键相当于给他一个中断,执行中断子程序之后返回原来的地方,大概整个内容两个小时搞定吧。嗯,比想象的时间要长。
做出来之后,感觉很奇怪。比如此时我是A通道放行,放行到第8s时,我让B车道通,那么B车道通5s后我又回到A车道通,只通1s就开始警告3s然后又到B,感觉中间时间太短。而且闪烁的时候也挺混乱的。我设置的是闪烁3s,每秒亮0.5s,灭0.5s。那么直接回到中断点的话这个时间也非常混乱。
基于此,我对这题进行了改进。
某通道通过时,有按键按下,执行相应的中断子程序。执行完毕后会返回,但并不是之前中断的位置,而是这样的:
A通过通的过程中,按下k2并不会有任何动作。按下k1,使B通道通行,返回时是重新使A通道通行,即通行12s。按下k3时,返回时是直接使B通道通行。
B通道同理。另外针对黄灯警告的时候,比如A亮黄灯,那么就认为A通道已经放行了很长时间,按键之后偏向于直接使得B通道通。
嗯,具体是怎样的过程我已经忘记了,可能刚刚描述的跟我做的不太准确。但是很明显看出这是在原来的题目上加以补充的,更贴合于实际情况。
那么我们来编程吧,这就遇到困难了。之前的程序相当于是正常运行,然后三个按键进入三个中断。但是现在我需要记住中断之前我的状态,中断结束后要根据中断前的状态及具体执行哪一个中断程序来判断结束后执行什么任务。
因此,最重要的就是对各状态进行判断。
在最初的版本中,主要就是每个阶段点灯的子函数,然后扫描键盘的函数触发中断。这里的思路是三个按键连接3个IO口,同时连接到外部中断,同时加上拉电阻。当有按键按下时给一个低电平到外部中断,中断子函数扫描三个IO口判断哪一个是低电平从而执行相应的操作。这里的连接涉及到一些与非门什么的。
但是这个版本并不能这样。我考虑的是用定时器中断而不用外部中断。首先我使用了20个标志位来辅助判断程序运行到哪一步了,这个就非常复杂了,环环相扣。另外我是采取的定时扫描方式,每隔1ms扫描各个标志位,来判断按键是否按下,而并非通过中断来按下按键。整个主程序执行时间极短,全部是根据标志位点亮相应的灯,而中断程序主要根据按键及标志位两者来改变标志位。现在放出来给大家看看,希望不会头晕。。。
程序有270行,我就不复制过来啦。
嗯,下面是个人的一些心得。我曾经教过不下十个同学学习单片机,我推荐的都是普中的板子,但是他们看了视频之后就认为自己会了,实际上不是的。比如数码管,整个视频大概20分钟吧(具体记不清了),他们看了之后就没了,实际上单片机这个东西是需要多练的,我就会出一些题目,比如数码管显示0-F,一个按键改变显示频率,一个开关改变显示方向(+/-)。做得过程中我自己也会发现一些问题,譬如就这个题目如果不用中断效果很差(不过我相信可以改进)。交通灯这个题目,应该是各种课程做烂了的,没想到我竟然做了三天,其中熬了两天夜。
其次,学习单片机不仅仅只是学会编程,更要学会思考。真正做项目中具体任务都是自己定的,并不会像题目一样给你限定死了,那么该选取怎样的目标?甚至包括具体硬件都是自己定的,需要自己静下心来多思考。而我看得有些同学觉得这一块不重要,只在意编程,这是不行的。
程序说不定有问题,半年前做的。只是提出一些自己的思路,希望能帮到大家。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include "reg51.h"
- sbit Ared=P2^0;
- sbit Ayel=P2^1;
- sbit Agre=P2^2;
- sbit Bred=P2^3;
- sbit Byel=P2^4;
- sbit Bgre=P2^5;
- sbit k1=P0^0;
- sbit k2=P0^1;
- sbit k3=P0^2;
- int flag_key,shine_a,shine_b; //通过flag_key来表示当前按键情况,shine来表示当前黄灯情况
- int flag_en1,flag_en2,flag_en3,flag_en4,flag_en5; //五个任务的使能标志位
- int flag_time1,flag_time2,flag_time3,flag_time4,flag_time5; //定时器的开启标志位
- int time_1,time_2,time_3,time_4,time_5; //定时器的计时标志位
- int delay,rst; //rst是复位标志位,用来判断中断结束后执行哪一个任务
- void scankey()
- {
- if(k1==0)
- {
- delay=1000;
- while(delay--);
- if(k1==0)
- {
- flag_en5=1;
- flag_key=1;
- flag_time1=0;
- flag_time2=0;
- flag_time3=0;
- flag_time4=0;
- time_1=0;
- time_2=0;
- time_3=0;
- time_4=0;
- while(!k1);
- }
- }
- if(k2==0)
- {
- delay=1000;
- while(delay--);
- if(k2==0)
- {
- flag_en5=1;
- flag_key=2;
- flag_time1=0;
- flag_time2=0;
- flag_time3=0;
- flag_time4=0;
- time_1=0;
- time_2=0;
- time_3=0;
- time_4=0;
- while(!k2);
- }
- }
- if(k3==0)
- {
- delay=1000;
- while(delay--);
- if(k3==0)
- {
- flag_en5=1;
- flag_key=3;
- flag_time1=0;
- flag_time2=0;
- flag_time3=0;
- flag_time4=0;
- time_1=0;
- time_2=0;
- time_3=0;
- time_4=0;
- while(!k3);
- }
- }
- }
- void led(int r1,r2,r3,r4,r5,r6)
- {
- Ared=r1;
- Ayel=r2;
- Agre=r3;
- Bred=r4;
- Byel=r5;
- Bgre=r6;
- }
- void main()
- {
- //定时器初始化
- TMOD=0;
- TH1=(8192-1000)/32;
- TL1=(8192-1000)%32;
- EA=1;
- ET1=1;
- TR1=1;
- //参数初始化
- flag_key=0;
- flag_en1=1;
- flag_en2=0;
- flag_en3=0;
- flag_en4=0;
- flag_en5=0;
- time_1=0;
- time_2=0;
- time_3=0;
- time_4=0;
- time_5=0;
- flag_time1=0;
- flag_time2=0;
- flag_time3=0;
- flag_time4=0;
- flag_time5=0;
- shine_a=1;
- shine_b=1;
- rst=0;
- while(1)
- {
- scankey();
- //按键未按下,正常运行
- if(flag_key==0)
- {
- if(flag_en1==1)
- {
- rst=1;
- flag_en1=0;
- led(0,0,1,1,0,0);
- flag_time1=1;
- }
- if(flag_en2==1)
- {
- rst=2;
- if(shine_a==1||shine_a==3||shine_a==5)
- led(0,1,0,1,0,0);
- else if(shine_a==2||shine_a==4||shine_a==6)
- led(0,0,0,1,0,0);
- flag_time2=1;
- if(shine_a==6)
- flag_en2=0;
- }
- if(flag_en3==1)
- {
- rst=3;
- flag_en3=0;
- led(1,0,0,0,0,1);
- flag_time3=1;
- }
- if(flag_en4==1)
- {
- rst=4;
- if(shine_b==1||shine_b==3||shine_b==5)
- led(1,0,0,0,1,0);
- else if(shine_b==2||shine_b==4||shine_b==6)
- led(1,0,0,0,0,0);
- flag_time4=1;
- if(shine_b==6)
- flag_en4=0;
- }
- }
- if(flag_key==1)
- {
- if(flag_en5==1)
- {
- flag_en5=0;
- led(0,0,1,1,0,0);
- flag_time5=1;
- }
- }
- if(flag_key==2)
- {
- if(flag_en5==1)
- {
- flag_en5=0;
- led(1,0,0,0,0,1);
- flag_time5=1;
- }
- }
- if(flag_key==3)
- {
- if(flag_en5==1)
- {
- flag_en5=0;
- led(1,0,0,1,0,0);
- flag_time5=1;
- }
- }
- }
- }
- void hml() interrupt 3
- {
- if(flag_time1==1)
- time_1++;
- if(time_1==3000)
- {
- time_1=0;
- flag_time1=0;
- flag_en2=1;
- }
- if(flag_time2==1)
- time_2++;
- if(time_2==500)
- {
- time_2=0;
- shine_a++;
- if(shine_a==7)
- {
- flag_time2=0;
- flag_en3=1;
- shine_a=1;
- }
- }
- if(flag_time3==1)
- time_3++;
- if(time_3==3000)
- {
- time_3=0;
- flag_time3=0;
- flag_en4=1;
- }
- if(flag_time4==1)
- time_4++;
- if(time_4==500)
- {
- time_4=0;
- shine_b++;
- if(shine_b==7)
- {
- flag_time4=0;
- flag_en1=1;
- shine_b=1;
- }
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
交通灯.rar
(115.47 KB, 下载次数: 21)
|