功能一:东西方向、南北方向均有红、黄、绿三种信号灯,初始红灯20秒,黄灯闪烁3秒,绿灯10秒。东西方向红灯时刻,南北方向绿灯,南北方向绿灯,东西方向红灯。(时间为标准秒数,信号灯切换顺序为绿黄红) (4分)
功能二:设置夜间模式按钮,按钮按下时,所有方向显示黄灯闪烁。
功能三:通过按键调节整体时间,第一个按键按下每种灯的持续时间增加一秒,第二个按键按下每种灯的持续时间减小一秒。(按键需要灵敏快速反应)
功能四:使用2位数码管实时提醒灯亮的剩余时间。
功能五:分时控制单路红绿灯,在40秒内,0-10秒为北面红绿灯通行,10-20秒内为东面红绿灯通行,20-30s内为南面红绿灯通行,30-40秒内为西面红绿灯通行。
#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>
#include "Delay.h"
#include "Nixie.h"
sbit N_R=P1^0; // 东西南北红绿黄灯定义
sbit N_Y=P1^1;
sbit N_G=P1^2;
sbit S_R=P1^3;
sbit S_Y=P1^4;
sbit S_G=P1^5;
sbit W_R=P2^0;
sbit W_Y=P2^1;
sbit W_G=P2^2;
sbit E_R=P2^3;
sbit E_Y=P2^4;
sbit E_G=P2^5;
sbit K1=P3^0; // 按键定义
sbit K2=P3^1;
sbit K3=P3^2;
sbit K4=P3^3;
sbit E_Tube1=P3^4; //东西南北数码管管脚定义
sbit E_Tube2=P3^5;
sbit S_Tube1=P3^6;
sbit S_Tube2=P3^7;
sbit N_Tube1=P1^6;
sbit N_Tube2=P1^7;
sbit W_Tube1=P2^6;
sbit W_Tube2=P2^7;
int flag_1=10000; //旗帜用来标记进行红绿灯切换
int flag_2=3000;
int flag_3=7000;
int flag_4=3000;
int flag=0;
int Y_flag=0; //黄灯闪烁
int Count=0;
int Compare=0; //对比值
int Change=0; //也是个旗帜
int Change_4=0; //功能4旗帜
int Compare_4=10000; //功能4时间定义
int symbol=0; //记号
int KeyNum=0;
int a,b;
int C_1=0; //数码管显示管脚
int C_2=0;
int N_C1=0;
int N_C2=0;
int E_C1=0;
int E_C2=0;
int S_C1=0;
int S_C2=0;
int W_C1=0;
int W_C2=0;
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x40};
void Nixie(unsigned char Location,Number)
{
switch(Location) //位码输出
{
case 1:
N_Tube1=S_Tube1=W_Tube1=E_Tube1=1; //公用管脚
N_Tube2=S_Tube2=W_Tube2=E_Tube2=0;
break;
case 2:
N_Tube2=S_Tube2=W_Tube2=E_Tube2=1; //公用管脚
N_Tube1=S_Tube1=W_Tube1=E_Tube1=0;
break;
case 3: //东南西北管脚控制
N_Tube1=1;
N_Tube2=S_Tube2=W_Tube2=E_Tube2=0;
break;
case 4:
N_Tube1=0;
N_Tube2=1;
break;
case 5:
E_Tube1=1;
N_Tube2=S_Tube2=W_Tube2=E_Tube2=0;
break;
case 6:
E_Tube1=0;
E_Tube2=1;
break;
case 7:
S_Tube1=1;
N_Tube2=S_Tube2=W_Tube2=E_Tube2=0;
break;
case 8:
S_Tube1=0;
S_Tube2=1;
break;
case 9:
W_Tube1=1;
N_Tube2=S_Tube2=W_Tube2=E_Tube2=0;
break;
case 10:
W_Tube1=0;
W_Tube2=1;
break;
}
P0=~NixieTable[Number]; //段码输出
Delay(1); //显示一段时间
P0=~0x00; //段码清0,消影
}
void Key()
{
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNum=1;} //按键检测
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNum=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNum=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNum=4;}
}
void main()
{
N_Tube1=S_Tube1=W_Tube1=E_Tube1=N_Tube2=S_Tube2=W_Tube2=E_Tube2=0; //初始化
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
while(1){
Key();
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
while(KeyNum==0)
{
Timer0Init();
Nixie(1,a);
Nixie(2,b);
Key();
if(Change==0){ //通过flag和Change相互照应用计时器达到切换效果
Compare=flag_1; //Delay函数行动缓慢弃之
flag=1;
N_R=S_R=W_G=E_G=1;
}
if(Change==1){
Compare=flag_2;
flag=2;
N_Y=S_Y=W_Y=E_Y=1;
}
if(Change==2){
Compare=flag_3;
flag=3;
N_G=S_G=W_R=E_R=1;
}
if(Change==3){
Compare=flag_4;
flag=4;
N_Y=S_Y=W_Y=E_Y=1;
}
}
switch(KeyNum)
{
break;
case 1:
flag_1+=1000; //功能1 按下按键所有时间+1s
flag_2+=1000;
flag_3+=1000;
flag_4+=1000;
KeyNum=0;
break;
case 2:
if(flag_1>1020){flag_1-=1000;} //功能2 按下按键所有时间-1s
if(flag_2>1020){flag_2-=1000;} //边界处理,防止出现负数的情况,1020是让显示更灵敏以防闪烁
if(flag_3>1020){flag_3-=1000;}
if(flag_4>1020){flag_4-=1000;}
KeyNum=0;
break;
case 3:
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
while(KeyNum==3) //功能3 按下按键 黄灯闪烁
{ Nixie(1,10); //数码管显示 - -
Nixie(2,10);
Key();
if(Y_flag==1) //旗帜,用来标记原理跟第一题一样
{
N_Y=S_Y=W_Y=E_Y=1;
}
if(Y_flag==0)
{
N_Y=S_Y=W_Y=E_Y=0;
}
}
break;
case 4:
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Timer0Init();
while(KeyNum==4)
{
N_Tube2=S_Tube2=W_Tube2=E_Tube2=C_2; //到所有数码管个位都一样,所以管脚设置统一
if(symbol==1)
{
N_C1=C_1;
N_C2=C_2;
E_C1=C_1;
S_C1=C_1+1; //用symbol标记,轮流计时,达到转圈圈的效果,防止错乱
W_C1=C_1+2; //四种情况依次考虑
}
if(symbol==2)
{
N_C1=C_1+2;
E_C1=C_1;
S_C1=C_1;
W_C1=C_1+1;
}
if(symbol==3)
{
N_C1=C_1+1;
E_C1=C_1+2;
S_C1=C_1;
W_C1=C_1;
}
if(symbol==4)
{
N_C1=C_1;
E_C1=C_1+1;
S_C1=C_1+2;
W_C1=C_1;
}
Nixie(3,N_C1); //控制显示,交替进行防止错乱
Nixie(2,C_2);
Nixie(5,E_C1);
Nixie(2,C_2);
Nixie(7,S_C1);
Nixie(2,C_2);
Nixie(9,W_C1);
Nixie(2,C_2);
Key();
if(Change_4==0){ //亮灯处理与功能一相似
symbol=1;
N_G=S_R=W_R=E_R=1;
}
if(Change_4==1){
symbol=2;
E_G=W_R=N_R=S_R=1;
}
if(Change_4==2){
symbol=3;
S_G=N_R=W_R=E_R=1;
}
if(Change_4==3){
symbol=4;
W_G=N_R=S_R=E_R=1;
}
}
break;
}
}
}
void Timer0_Routine() interrupt 1 //定时器部分
{
static unsigned int Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
Count++; //T0Count计次,对中断频率进行分频
a=(Compare-Count+999)/10000; //+999为了显示多一秒防止一开始出现数码管跳动
b=((Compare-Count+999)/1000)%10; //a得到十位,b得到个位
C_1=(Compare_4-Count+999)/10000; //同理
C_2=((Compare_4-Count+999)/1000)%10;
if(KeyNum==0)
{
if(Count>=Compare)
{
Count=0;
if(flag==1){ //旗帜照应flag<-->change,实现灯的变换
Count=0;
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Change=1;
}
if(flag==2){
Count=0;
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Change=2;
}
if(flag==3){
Count=0;
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Change=3;
}
if(flag==4){
Count=0;
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Change=0;
}
EA=1;
}
// 功能3
}
if(KeyNum==3) //黄灯闪烁间隔0.3秒频率刚刚好
{
if(Count<300)
{Y_flag=1;}
if(Count>300&&Count<600)
{Y_flag=0;}
if(Count>600){Count=0;}
}
// 功能4
if(KeyNum==4)
{
if(Count>=Compare_4)//MOD 1
{
Count=0;
if(symbol==1){ //symbol<-->Change_4相互照应
Count=0;
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Change_4=1;
}
if(symbol==2){
Count=0;
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Change_4=2;
}
if(symbol==3){
Count=0;
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Change_4=3;
}
if(symbol==4){
Count=0;
N_R=S_R=W_R=E_R=N_Y=S_Y=W_Y=E_Y=N_G=S_G=W_G=E_G=0;
Change_4=0;
}
}
}
}
挺复杂的,缺点是数码管有时候会卡顿。