Proteus仿真原理图:
程序如下:
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar data buf[4]
uchar data sec_dx=20//东西数默认
uchar data sec_nb=30//南北默认值
uchar data set_timedx=20
uchar data set_timenb=30
int n
uchar data b//定时器中断次数
sbit k1=P1^6//定义5组开关
sbit k2=P1^7
sbit k3=P2^7
sbit k4=P3^0
sbit k5=P3^1
sbit Yellow_nb=P2^5 //南北黄灯标志
sbit Yellow_dx=P2^2 //东西黄灯标志
sbit Green_nb=P2^4
sbit Green_dx=P2^1
sbit Buzz=P3^7
bit Buzzer_Indicate
bit time=0//灯状态循环标志
bit set=1//调时方向切换键标志
uchar code table[11]={ //共阴极字型码
0x3f, //--0
0x06, //--1
0x5b, //--2
0x4f, //--3
0x66, //--4
0x6d, //--5
0x7d, //--6
0x07, //--7
0x7f, //--8
0x6f, //--9
0x00 //--NULL
}
//函数的声明部分
void delay(int ms)//延时子程序
void key()//按键扫描子程序
void key_to1()//键处理子程序
void key_to2()
void key_to3()
void display()//显示子程序
void logo() //开机LOGO
void Buzzer()
//主程序
void main()
{
TMOD=0X01
TH0=0XD8
TL0=0XF0
EA=1
ET0=1
TR0=1
EX0=1
EX1=1
logo()
P2=0Xc3// 开始默认状态,东西绿灯,南北黄灯
sec_nb=sec_dx+5
while(1)
{
key()//调用按键扫描程序
display()//调用显示程序
Buzzer()
}
}
//函数的定义部分
void key() //按键扫描子程序
{
if(k1!=1)
{
delay(10)
if(k1!=1)
{
while(k1!=1)
{
key_to1()
for(n=0n<40n++)
{ display()}
}
}
}
if(k2!=1)
{
delay(10)
if(k2!=1)
{
while(k2!=1)
{
key_to2()
for(n=0n<40n++)
{ display()}
}
}
}
if(k3!=1)
{
TR0=1 //启动定时器
Buzzer_Indicate=0
sec_nb=set_timenb //从中断回复,仍显示设置过的数值
sec_dx=set_timedx
if(time==0)
{ P2=0X99sec_nb=sec_dx+5}
else { P2=0xC3sec_dx=sec_nb+5}
}
if(k4!=1)
{
delay(5)
if(k4!=1)
{
while(k4!=1)
set=!set
}
}
if(k5!=1)
{
delay(5)
if(k5!=1)
{
while(k5!=1)
key_to3()
}
}
}
void display() //显示子程序
{
buf[1]=sec_dx/10//第1位 东西秒十位
buf[2]=sec_dx%10//第2位 东西秒个位
buf[3]=sec_nb/10//第3位 南北秒十位
buf[0]=sec_nb%10//第4位 南北秒个位
P1=0xff // 初始灯为灭的
P0=0x00
P1=0xfe //片选LCD1
P0=table[buf[1]]
delay(1)
P1=0xff
P0=0x00
P1=0xfd //片选LCD2
P0=table[buf[2]]
delay(1)
P1=0xff
P0=0x00
P1=0Xfb //片选LCD3
P0=table[buf[3]]
delay(1)
P1=0xff
P0=0x00
P1=0Xf7
P0=table[buf[0]] //片选LCD4
delay(1)
}
void time0(void) interrupt 1 using 1 //定时中断子程序
{
b++
if(b==19) // 定时器中断次数
{ b=0
sec_dx--
sec_nb--
if(sec_nb<=5&&time==0) //东西黄灯闪
{ Green_dx=0Yellow_dx=!Yellow_dx}
if(sec_dx<=5&&time==1) //南北黄灯闪
{ Green_nb=0Yellow_nb=!Yellow_nb}
if(sec_dx==0&&sec_nb==5)
sec_dx=5
if(sec_nb==0&&sec_dx==5)
sec_nb=5
if(time==0&&sec_nb==0)
{ P2=0x99time=!timesec_nb=set_timenbsec_dx=set_timenb+5}
if(time==1&&sec_dx==0)
{P2=0Xc3time=!timesec_dx=set_timedxsec_nb=set_timedx+5}
}
}
void key_to1() //键盘处理子程序之+
{
TR0=0 //关定时器
if(set==0)
set_timenb++ //南北加1S
else
set_timedx++ //东西加1S
if(set_timenb==100)
set_timenb=1
if( set_timedx==100)
set_timedx=1 //加到100置1
sec_nb=set_timenb //设置的数值赋给东西南北
sec_dx=set_timedx
}
void key_to2() //键盘处理子程序之-
{
TR0=0 //关定时器
if(set==0)
set_timenb-- //南北减1S
else
set_timedx-- //东西减1S
if(set_timenb==0)
set_timenb=99
if( set_timedx==0 )
set_timedx=99 //减到1重置99
sec_nb=set_timenb //设置的数值赋给东西南北
sec_dx=set_timedx
}
void key_to3() //键盘处理之紧急车通行
{
TR0=0
P2=0Xc9
sec_dx=00
sec_nb=00
Buzzer_Indicate=1
}
void int0(void) interrupt 0 using 1 //只允许东西通行
{
TR0=0
P2=0Xc3
Buzzer_Indicate=0
sec_dx=00
sec_nb=00
}
void int1(void) interrupt 2 using 1 //只允许南北通行
{
TR0=0
P2=0X99
Buzzer_Indicate=0
sec_nb=00
sec_dx=00
}
void logo()//开机的Logo "- - - -"
{ for(n=0n<50n++)
{
P0=0x40
P1=0xfe
delay(1)
P1=0xfd
delay(1)
P1=0Xfb
delay(1)
P1=0Xf7
delay(1)
P1 = 0xff
}
}
void Buzzer()
{
if(Buzzer_Indicate==1)
Buzz=!Buzz
else Buzz=0
}
void delay(int ms) //延时子程序
{
uint j,k
for(j=0j<msj++)
for(k=0k<124k++)
}
SNF EQU 00H 南北通行标志位EWF EQU 01H 东西通行标志位URF EQU 02H 紧急事件标志位ORG 0000HLJMP MAIN 上电转主程序ORG 000BH 定时中断入口LJMP DSZD ORG 0003H 紧急中断入口LJMP URZDORG 0030H MAIN: LCALL INIT 调用初始化子程序LOOP: LCALL DIS 循环执行显示子程序 AJMP LOOP///////////初始化程序INIT: SETB SNF SETB EWF SETB URF MOV R2,#20 定时器中断20次为1s MOV TMOD,#01H 初始化定时器 MOV TL0,#0B0H MOV TH0,#3CH SETB EA 开定时中断与紧急中断 SETB ET0 SETB TR0 SETB EX0 SETB IT0 设置中断程控方式 MOV DPTR,#TAB 数值首地址放入DPTR中 MOV 40H,#40 东南西北通行时间设置 MOV 41H,#40 MOV 30H,#40 通行时间初始化 MOV 31H,#60 MOV P0,#4CH 初始化时南北通行并把交通灯状态分别放在32H和33H中 MOV 32H,#4CH MOV P2,#15H MOV 33H,#15H RET////////////显示子程序DIS: MOV P3,#0DFH 选中南北方向的十位数码管 MOV A,30H 把显示数据送人数码管显示 MOV B,#10 DIV AB MOVC A,@A+DPTR MOV P1,A LCALL D1MS MOV P3,#0EFH 选中南北方向的个位数码管 MOV A,B 送入数码管显示 MOVC A,@A+DPTR MOV P1,A LCALL D1MS
MOV P3,#7FH 选中第东西方向的十位数码管 MOV A,31H 送入数码管显示 MOV B,#10 DIV AB MOVC A,@A+DPTR MOV P1,A LCALL D1MS MOV P3,#0BFH 选中第东西方向的个位数码管 MOV A,B MOVC A,@A+DPTR MOV P1,A LCALL D1MS SETB P3.0 SETB P3.1 JNB P3.0,DIS_S 查询是否第一个按键按下 JNB P3.1,DIS_E 查询是否第二个按键按下 AJMP DIS_R 没有键按下则返回DIS_S:LCALL D5MS 按键去抖 JNB P3.0,DIS_SN AJMP DIS_R DIS_SN:MOV 40H,#50 对通行时间从新分配,南北通行时间加长 MOV 41H,#30 AJMP DIS_RDIS_E:LCALL D5MS 按键去抖 JNB P3.1,DIS_EW AJMP DIS_RDIS_EW:MOV 40H,#30 东西通行时间加长 MOV 41H,#50DIS_R:RET ///////定时中断处理程序DS_C: LJMP DS_R 接力跳转DSZD: PUSH ACC 保护现场 PUSH PSW CLR TR0 关定时器及中断标志位并重新赋值 CLR TF0 MOV TL0,#0B0H MOV TH0,#3CH DJNZ R2,DS_C 判断1m时间是否到达 MOV R2,#20 到达重新赋值 DEC 30H 南北方向通行时间减一 MOV A,30H 把减一后的时间送入显示存储单元南北通行到达最后4秒时黄灯闪烁DS_10:CJNE A,#4,DS_11 如果通行时间剩余4秒 JNB SNF,DS_11 判断是否是南北通行 MOV P0,#8AH MOV 32H, #8AH 把交通灯状态存入存储单元(后面类似)DS_11:CJNE A,#3,DS_12 不是剩余3秒,返回 JNB SNF,DS_12 不是南北通行时间,返回 MOV P0,#88H MOV 32H, #88HDS_12:CJNE A,#2,DS_13 JNB SNF,DS_13 MOV P0,#8AH MOV 32H, #8AH DS_13:CJNE A,#1,DS_14 JNB SNF,DS_14 MOV P0,#88H MOV 32H, #88H------------------------DS_14:JNZ DS_NE 通行时间没有结束转向改变东西方向的数码管 CPL SNF 如果通行时间结束则对标志位取反 JNB SNF,DS_1 判断是否南北通行 MOV 30H,40H 是,点亮相应的交通灯 MOV P0,#4CH MOV 32H,#4CH 存储交通灯状态 MOV P2,#15H MOV 33H, #15H 存储交通灯状态DS_NE:DEC 31H 东西方向通行时间减一 MOV A,31H 把通行剩余时间送入显示存储单元东西方向通行时间剩余4秒钟黄灯闪烁(程序注释与南北方向类似 略)DS_20:CJNE A,#4,DS_21 JB EWF,DS_21 MOV P0,#51H MOV 32H, #51HDS_21:CJNE A,#3,DS_22 JB EWF,DS_22 MOV P0,#41H MOV 32H, #41HDS_22:CJNE A,#2,DS_23 JB EWF,DS_23 MOV P0,#51H MOV 32H, #51HDS_23:CJNE A,#1,DS_24 JB EWF,DS_24 MOV P0,#41H MOV 32H, #41H-----------------------------DS_24:JNZ DS_R 东西方向时间没有结束,返回 CPL EWF 对通行状态取反 JNB EWF,DS_2 东西方向通行时间到来,跳转 MOV 31H,#80 东西方向通行结束,重新显示时间 MOV P0,#89H 点亮相应的交通灯 MOV 32H, #89H MOV P2,#29H MOV 33H, #29H AJMP DS_R DS_1: MOV 30H,#80 南北通行时间结束,重新对显示存储单元赋值 MOV P0,#89H 执行转弯状态1 MOV 32H, #89H MOV P2,#26H MOV 33H, #26H AJMP DS_NE DS_2: MOV 31H,41H 东西方向开始通行,赋值予显示
硬件电路设计
此电中路设计采用AT89C51单片机,74LS47(数码管驱动)74LS373(数码管驱动输出锁存),8个数码管显示其延时值,四个红、黄、绿指示灯。硬件设计关键在于,延时显示时,要考虑到当个位数字显示时,要确保十位数字显示输出的不变。因此,可加输出锁存器。在延时最后三秒时,要让黄灯进行闪烁,并同时显示数字(这一步在软件设计上很关键)。
(1)电路连接图:
三、软件程序(C语言)
以下是整个设计的软件程序,直接可以编译成*。Hex代码。通过以上电路,下载到单片机,可直接运行。
//*****************************////程序名:十字路口交通灯控制
//编写人:黄庭剑
//初写时间:2009年1月2日
//程序功能:南北为车行道,延时60秒东西方向为人行道,延时20秒,且在最后3秒黄灯显示2秒钟再实现切换.
//CPU说明:AT89C51型单片机 24MHZ晶体振荡器
//完成时间:2009年1月6日
//*****************************//
#include<stdio.h>
#include<reg51.h>
#include<intrins.h>
sfr p0 = 0x80
sfr p1 = 0x90
sfr p2 = 0xA0
sfr p3 = 0xb0 //这部分内容其实在“#include<reg51.h>”里已经有,但里面定义的必须区分大小写,在这里,因为我程序采用的是小写,reg51.h里对各个端口与寄存器的定义都是大写,所以在编译连接时,会报错,所以,在本设计程序里,我只用到了端口,在这里也就只定义了四个,而没有去改reg51.h里面的内容。其实两者是一样的。
sbit sw = p0^0
sbit OE =P0^6
sbit LE =P0^7 //74LS373锁存器控制端定义
char display[]={ 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99 } //p1口的数码管时间显示调用,利用74L74BCD码,8位驱动输出 //函数声明 begin
void delay1(int count)
void delay_long(int number1,int number2)
void people_car_drive()
//函数声明end
//***********************//延时子程序
void delay1(int count)
{ int i
for(i=counti>0i--)
{ }
}
void delay_long(int number1,int number2)
{
int a,b
for(a=number1a>0a--)
{
for(b=number2b>0b--)
{ _nop_() }
}
}
//**********************//延时子程序
void people_car_drive()
{
int p_1=2,i,j=9,p_2=6 //****************//行人通行时,延时20秒
p2=0x09 //南北红灯亮
p3=0x24 //东西绿灯亮
while(p_1-->0)
{ LE=1
OE=0
if(p_1==0){OE=1} //当十位数减到0时,只显示个位数
p1=display[p_1]
delay1(1000)
LE=0
j=9
for(i=10i>0i--)
{
if(p_1==0&&j==3)break //减到3时退出循环,让其黄灯闪烁显示
p1=display[j--]
delay_long(16000,2)
if(sw==1)return
}
}
//*******************************************************************************//
p2=0x12 //南北黄灯闪烁三秒,以提醒行人注意
p3=0x12
p1=display[3]
delay_long(8000,1)
p2=0x00
p3=0x00
delay_long(14000,1)
p2=0x12
p3=0x12
p1=display[2]
delay_long(8000,1)
p2=0x00
p3=0x00
delay_long(14000,1)
p2=0x12
p3=0x12
p1=display[1]
delay_long(8000,1)
p2=0x00
p3=0x00
delay_long(14000,1)
//*****************以下是车辆通行时延时60秒//
p2=0x24 //南北绿灯亮
p3=0x09 //东西红灯亮
while(p_2-->0)
{ LE=1
OE=0
if(p_2==0){OE=1} //当十位数减到0时,只显示个位数
p1=display[p_2]
delay1(1000)
LE=0
j=9
for(i=10i>0i--)
{
if(p_2==0&&j==3)break //减到2时退出循环
p1=display[j--]
delay_long(16000,2)
if(sw==1)return
}
}
p2=0x12 //南北黄灯闪烁三秒,以提醒行人注意
p3=0x12
p1=display[3]
delay_long(8000,1)
p2=0x00
p3=0x00
delay_long(14000,1)
p2=0x12
p3=0x12
p1=display[2]
delay_long(8000,1)
p2=0x00
p3=0x00
delay_long(14000,1)
p2=0x12
p3=0x12
p1=display[1]
delay_long(8000,1)
p2=0x00
p3=0x00
delay_long(14000,1) //南北黄灯闪烁三秒完毕
}
void main() //主函数入口处
{
p0=0x01
p1=0x00
p2=0x00
p3=0x00 //初始化各端口
{ while(1)
{
if(sw==0)
{ people_car_drive()}
else
{
p2=0x00
p3=0x00 //关闭所有交通灯
}
}
}
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)