#include <reg51.h>
#include <intrins.h>
const unsigned char code ST[] = {0x21, 0x81, 0x01, 0x41, 0x24, 0x20, 0x22};
/*0状态0:南北红,东西红00100001;1状态1:南北绿,东西红10000001;2状态1.5,南北闪烁的灭状态;
3状态2:南北黄,东西红01000001;4状态3:南北红,东西绿00100100;5状态3.5:东西闪烁的灭状态;6状态4:南北红,东西黄00100010*/
const unsigned char code LEDcode[] =
{0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b, 0x77, 0x1f, 0x4e, 0x3d, 0x4f, 0x47, 0x00, 0xff };
/*0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,全灭,全亮*/
sbit pinDIN = P2 ^ 0; //max7219串行数据输入端
sbit pinLOAD =P2 ^ 1; //max7219数据锁存端
sbit pinCLK = P2 ^ 2; //max7219时钟输入端
bit flag = 0; //控制整个程序跳转回状态1重新运行
int delay_time = 3;//红绿灯延时时间
int count = 0; //记录定时器1完成的定时次数,供程序判断是否完成计时
void init_max7219(void);//初始化MAX7219
void sendbyte (unsigned char dat);//向MAX7219写入字节(8位)函数
void sendword (unsigned char addr, unsigned char dat);//向MAX7219写入地址和控制字(16位)
void clear_max7219(void);//MAX7219清除显示
void display(int n, bit x); //x==0显示南北方向倒计时数字n,x==1东西方向
void init_t1(void);//初始化定时器1
void delay_twinkle(bit x);//1HZ闪烁2秒,同时输出倒计时信号,x==0南北方向闪烁,x==1东西方向闪烁
void delay_1s(int n,int time0,int time1);//延时n秒,同时输出倒计时信号,南北倒计时time0秒,东西time1秒
void main()
{
int i;
IE = 0x8D; //开总中断,开int0,int1,t1中断
IT0 = 1;
IT1 = 1;
init_max7219();
clear_max7219();
P0 = ST[0]; //状态0
delay_1s(1,1,1);//延时1秒
if(flag);//状态0本身就是南北红东西红打断也无所谓
while(1)
{
for(i = 1; i <= 4; i++)
{
switch(i)
{
case 1:
P0 = ST[1]; //状态1
delay_1s(delay_time,delay_time+2,delay_time+5);//延时t1秒
break;
case 2:
delay_twinkle(0);//状态1.5闪烁2秒
if(flag)break;
P0 = ST[3]; //状态2南北黄东西红
delay_1s(3,3,3);//延时3秒
break;
case 3:
P0 = ST[4]; //状态3
delay_1s(delay_time,delay_time+5,delay_time+2);
break;
case 4:
delay_twinkle(1);//状态3.5闪烁2秒
if(flag)break;
P0 = ST[6];//状态4南北红东西黄
delay_1s(3,3,3);//延时3秒
break;
}
if(flag)
{
flag = 0;
break;//从状态1重新执行
}
}
}
}
void Stop(void) interrupt 0//int0触发中止信号
{
P0 = ST[0];//南北红东西红
clear_max7219();//清空倒计时
while(!INT0);//直到开关断开才返回主程序
flag = 1; //使程序重状态1开始运行
}
void Reset(void) interrupt 2//int1触发重置信号
{
char temp;
P0 = ST[0];//南北红东西红
clear_max7219();//清空倒计时
while(!INT1){
temp = P1 & 0x7f;//取拨码开关数值
delay_time = (int)temp; //重设红绿灯延迟时间
}//直到开关断开才返回主程序
flag = 1; //使程序重状态1开始运行
}
void init_t1(void)
{
count = 0;
TMOD = 0x10; //定时器1定时,模式2
TH1 = (65536 - 50000) / 256;
TL1 = (65536 - 50000) % 256;
TR1 = 1;
}
void T1_intr(void)interrupt 3//每50ms计数加一
{
count++;
TMOD = 0x10; //定时器1定时,模式2
TH1 = (65536 - 50000) / 256;
TL1 = (65536 - 50000) % 256;
}
void display(int n, bit x)
{
int i, j;
if(n >= 99)//大于99只显示99
{
i = 9;
j = 9;
}
else
{
i = n / 10;
j = n % 10;
}
if(!x)//x==0输出南北方向
{
sendword(0x01, LEDcode[i]);
sendword(0x02, LEDcode[j]);
}
else//东西方向
{
sendword(0x03, LEDcode[i]);
sendword(0x04, LEDcode[j]);
}
}
void delay_twinkle(bit x)
{
int i, j;
for(i = 2; i > 0; i--)
{
display(i,x);//显示闪烁倒计时
display(i+3,!x);//显示另一方向倒计时
for(j = 0; j < 2; j++) //南北绿灯1HZ闪烁2秒
{
if(j % 2 == 0)//亮
{
if(!x) P0 = ST[1];//状态1
else P0 = ST[4];//状态3
}
else//灭
{
if(!x)P0 = ST[2];//状态1.5
else P0 = ST[5];//状态3.5
}
init_t1();
while(count < 10 && !flag);//500ms
TR1 = 0;
if(flag)break;//若是紧急情况或重置延时时间,则打断运行
}
if(flag)break;
}
}
void delay_1s(int n,int time0,int time1) //延时n秒,同时输出倒计时信号,南北倒计时time0秒,东西time1秒
{
int i = 0;
for(i = n; i > 0; i--)
{
display(time0--,0);//显示南北倒计时
display(time1--,1);//显示东西倒计时
init_t1();
while(count < 20 && !flag);
TR1 = 0;
if(flag)break;
}
}
void sendbyte (unsigned char dat)//向MAX7219写入字节(8位)函数
{
unsigned char i, temp;
_nop_();
for (i = 0; i < 8; i++)
{
temp = dat & 0x80;
dat = dat << 1;
if(temp)
pinDIN = 1;
else
pinDIN = 0;
pinCLK = 0;
_nop_();
pinCLK = 1;
}
}
void sendword (unsigned char addr, unsigned char dat)//向MAX7219写入地址和控制字(16位)
{
pinLOAD = 0;
_nop_();
sendbyte (addr);
_nop_();
sendbyte (dat);
_nop_();
pinLOAD = 1; //第16个上升沿之后,第17个上升沿之前必须把pinCLK置高,否则数据丢失
}
void init_max7219()//MAX7219初始化
{
sendword (0x0c, 0x01); // 设置电源工作模式
sendword (0x0a, 0x09); // 设置亮度 19/32
sendword (0x0b, 0x03); // 设置扫描界限
sendword (0x09, 0x00); // 设置译码模式
sendword (0x0f, 0x00); //显示测试 00为正常工作状态
}
void clear_max7219(void)//MAX7219清除显示
{
unsigned char i;
for(i = 8; i > 0; i--)
sendword(i, 0x00);
}