交通灯程序在单片机入门级别的众多程序中属于较为复杂的,其中还用到了intrins.h头文件,给众多学习者造成困扰。
本人经过学习,在前人的基础之上,对每一行比较重要的程序均做了注释说明。希望帮助到列位黑友。
特别说明,intrins.h头文件的添加与*.c文件的添加步骤实际上是一样的。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include<reg51.h>
- #include<intrins.h>
- typedef unsigned char uchar;
- typedef unsigned int uint;
- sbit k1 = P1^6;
- sbit k2 = P1^7;
- sbit k3 = P2^7;
- sbit k4 = P3^0;
- sbit yellowled_dx=P1^1; //东西黄灯
- sbit yellowled_nb=P1^4; //南北黄灯
- uchar code table[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
- uchar dig; //位选
- uchar led=0; //偏移量
- uchar buf[4];
- uchar sec_dx=39;//东西数码指示值
- uchar sec_nb=39;//南北数码指示值
- uchar settime_dx;
- uchar settime_nb;//倒计时设置的键值保存
- uchar b; //定时器中断次数
- bit time; //灯状态循环标志,借助time 实现判断东西通行还是南北通行
- bit int0_time; //中断强行标志
- bit set; //调时方向切换键标志
- /*************************************************
- 函数功能:软件延时(约50ms)
- **************************************************/
- void delay(uint ms)
- {
- uint j,k;
- for(j=0;j<ms;j++)
- for(k=0;k<124;k++);
- }
- /*************************************************
- 函数功能:加 1 调整
- **************************************************/
- void key_ad1()
- {
- TR0=0; //关定时器
- if(set==0)
- sec_nb++; //南北加1S
- else
- sec_dx++;//东西加1S
- if(sec_nb==100)
- sec_nb=1;//加到100置1
- if(sec_dx==100)
- sec_dx=1;//加到100置1
- }
- /*************************************************
- 函数功能:减 1 调整
- **************************************************/
- void key_dec1()
- {
- TR0=0;//关定时器
- if(set==0)
- sec_nb--; //南北减1S
- else
- sec_dx--; //东西减1S
- if(sec_nb==0)
- sec_nb=99;//减到0重置99
- if( sec_dx==0 )
- sec_dx=99;//减到0重置99
- }
- /*************************************************
- 函数功能:按键k1-k4扫描
- **************************************************/
- void key()
- {
- if(k1==0)
- {
- delay(10);
- if(k1==0)
- {
- while(k1==0);
- key_ad1();
- }
- }
- if(k2==0)
- {
- delay(10);
- if(k2==0)
- {
- while(k2==0);
- key_dec1();
- }
- }
- if(k4==0)
- {
- delay(10);
- if(k4==0)
- {
- while(k4==0);
- set=!set;
- }
- }
- if(k3==0&&int0_time==1) //确认调完(k3按下),同时中断强行标志为1
- {
- TR0=1; //启动定时器
- sec_nb=59;
- sec_dx=59;
- int0_time=0;//清标志
- }
- else if(k3==0&&int0_time==0)//确认调完(k3按下),同时中断强行标志为0
- {
- TR0=1;
- settime_nb=sec_nb; //设置的键值返回保存
- settime_dx=sec_dx; //设置的键值返回保存
- }
- }
- /*************************************************
- 函数功能:显示
- **************************************************/
- void display()
- {
- /*************************************************
- 以下6行实现给buf[0-3]赋值,决定数码管要显示的数值
- **************************************************/
- buf[1]=sec_dx/10; //第1位 东西秒十位
- buf[2]=sec_dx%10; //第2位 东西秒个位
- buf[3]=sec_nb/10; //第3位 南北秒十位
- buf[0]=sec_nb%10; //第4位 南北秒个位
- P0=table[buf[led]];//赋初值(因为已经给led赋初值=0,buf[0]=sec_nb%10)
- delay(2); //延时
- /*************************************************
- 以下6行实现给P2^0-3赋值,实现数码管的循环显示
- **************************************************/
- P2=dig; //给P2赋值dig,因为使用P2口低4位,如dig = 1110,则P2.0=0,对应LED不亮
- dig=_crol_(dig,1); //dig数值按位向左 1 位带循环(如1110-1101-1011-0111-1110)
- led++; //在这里实现led = 0、1、2、3,从而实现动态循环显示
- if(led==4) //led只有 0、1、2、3 四位,分别对应buf[]的值,根据此值查表table[]
- {
- led=0;
- dig=0xfe;
- }
- }
- void main()
- {
- TMOD=0x01; //T0计数器工作在模式1
- TH0=0x3C; //定时50000毫秒
- TL0=0xB0; //定时50000毫秒
- EA=1; //开总中断
- ET0=1; //定时器T0溢出中断允许(溢出中断必须开启,否则无法计数)
- TR0=1; //启动定时器T0
- EX0=1; //T0的外部中断允许
- EX1=1; //T1的外部中断允许
- P1=0Xf3; // P1口低四位0011,对应南北红灯亮,东西黄灯亮
- while(1)
- {
- key(); //调用按键扫描程序
- display(); //调用显示程序
- }
- }
- void T0_server() interrupt 1 //T0中断服务程序
- {
- b++;
- if(b==10) // 定时器中断次数。
- {
- b=0;
- sec_dx--;
- sec_nb--;
- //南北黄灯闪烁判断
- if(sec_nb==3&&time==0)
- {
- yellowled_nb=1;//南北黄灯亮
- delay(300);
- yellowled_nb=0;
- }
- if(sec_nb==2&&time==0)
- {
- yellowled_nb=1;//南北黄灯亮
- delay(300);
- yellowled_nb=0;
- }
- if(sec_nb==1&&time==0)
- {
- yellowled_nb=1;//南北黄灯亮
- delay(300);
- yellowled_nb=0;
- }
- //东西黄灯闪判断
- if(sec_dx==3&&time==1)
- {
- yellowled_dx=1;//南北黄灯亮
- delay(300);
- yellowled_dx=0;
- }
- if(sec_dx==2&&time==1)
- {
- yellowled_dx=1;//南北黄灯亮
- delay(300);
- yellowled_dx=0;
- }
- if(sec_dx==1&&time==1)
- {
- yellowled_dx=1;//南北黄灯亮
- delay(300);
- yellowled_dx=0;
- }
- if(sec_dx==0||sec_nb==0) //东西或南北先到达1S时即开始重新计时
- {
- sec_dx=settime_dx;
- sec_nb=settime_nb; //第一次循环结束重置
- if(time==1) //借助time 实现判断东西通行还是南北通行
- {
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
基于51单片机交通灯的设计.zip
(94.47 KB, 下载次数: 32)
|