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++)
}
硬件电路设计
此电中路设计采用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 //关闭所有交通灯
}
}
}
}
//晶振:11.0592 T1-250微溢出一次/*变量的定义:show_val_sn,show_val_ew:显示值0-59
state_val_sn,state_val_ew:状态值 南北反向0-绿灯亮1-黄灯亮2-红灯亮
T1_cnt:定时器计数溢出器
cnt_sn,cnt_ew:倒计时的数值
init_sn[3],int_ew[3]倒计时
leg_seg_code:数码管七段码*/
#include<reg51.h>
sbit SN_green=P3^2//南北方向绿灯
sbit SN_yellow=P3^1//南北方向黄灯
sbit SN_red=P3^0//南北方向红灯
sbit EW_green=P3^5
sbit EW_yellow=P3^4
sbit EW_red=P3^3
unsigned char data cnt_sn,cnt_ew
unsigned int data T1_cnt
unsigned char data state_val_sn,state_val_ew
char code led_seg_code[]={0x3f,0x06,0x05,0x04,0x66,0x6d,0x7d,0x07,0x7f,0x6f}
char code init_sn[3]={14,4,9}
char code init_ew[3]={9,14,4}
//-------------------------------------
void delay(unsigned int i)//延时
{
while(i=0)
}
//---------------------------------------
void led_show(unsigned int u,unsigned int v)
{
unsigned char i
i=u%10//暂存个数
P0=led_seg_code[i]
P2=0xbf
delay(100)//延时
i=u%100/10//暂存十位
P0=led_seg_code[i]
P2=0x7f
delay(100)//延时
i=v%10//暂存个位
P0=led_seg_code[i]
P2=0xfe
delay(100)//延时
i=v%100/10//暂存十位
P0=led_seg_code[i]
P2=0xfd
delay(100)//延时
}
//----------------------------------------
void timer()interrupt 3 //T1中断
{
T1_cnt++
if(T1_cnt>3999)//如果计数>3999,计时1s
{
T1_cnt=0
if(cnt_sn!=0)//南北方向计时
{cnt_sn--}
else
{state_val_sn++
if(state_val_sn>2)state_val_sn=0
cnt_sn=init_sn[state_val_sn]
switch(state_val_sn)//根据状态值,刷新各信号灯的状态
{
case 0:SN_green=0//南北方向绿灯
SN_yellow=1//南北方向黄灯
SN_red=0//南北方向红灯
break
case 1:SN_green=1//南北方向绿灯
SN_yellow=0//南北方向黄灯
SN_red=1//南北方向红灯
break
case 2:SN_green=1//南北方向绿灯
SN_yellow=1//南北方向黄灯
SN_red=0//南北方向红灯
break
}
}
if(cnt_ew!=0)//东西方向计时器
{cnt_ew--}
else
{state_val_ew++
if(state_val_ew>2)state_val_ew=0
cnt_ew=init_ew[state_val_ew]
switch(state_val_ew)//根据状态值,刷新各信号灯的状态
{case 0:EW_green=1
EW_yellow=1
EW_red=0
break
case 1:EW_green=0
EW_yellow=1
EW_red=1
break
case 2:EW_green=1
EW_yellow=0
EW_red=1
break
}
}
}
}
//-------------------------------------
void main()
{
//初始化各变量
cnt_sn=init_sn[0]
cnt_ew=init_ew[0]
T1_cnt=0
state_val_sn=0//启动后,默认工作在序号位1的状态
state_val_ew=0//初始化各灯的状态
SN_green=0//南北方向绿灯亮
SN_yellow=1//南北方向黄灯灭
SN_red=1//南北方向红灯亮
EW_green=1//东西方向绿灯灭
EW_yellow=1//东西方向黄灯灭
EW_red=0//东西方向红灯亮
//初始化51的寄存器
TMOD=0x20//用T1计时8位自动装载定时模式
TH1=0x19//0x4b//500微秒溢出一次, 250=(256-x)*12/11.0592->x=230.4
TL1=0x19
EA=1//开中断
ET1=1
TR1=1//开定时器T1
while(1)
{
led_show(cnt_sn,cnt_ew)
}
}
/*------结束---------------*/
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)