#include "reg52.h"
#include "iic.h"
#include "ds1302.h"
#define Data_Port P0//定义数据端口为P0
//-------------------------变量声明---------------------------
unsigned char code SMG_DuanMa[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//数码管段码
unsigned char code Write_DS1302_addr[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //1302地址
unsigned char code Read_DS1302_addr[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
unsigned char Timer[]={0x50,0x59,0x22,0x03,0x03,0x06,0x23};
unsigned char display_buff[12]="00:00:00";
unsigned char lcd_buff[16]=" ";
unsigned char count = 0;
unsigned char count1 = 0;
unsigned char SMG_state = 0; //秒闪状态参量
unsigned char eve_mode = 0;
unsigned char s1 = 0; //东西方向显示数(主路)
unsigned char s2 = 0; //南北方向显示数(辅路)
unsigned char color_state = 0; //状态机状态参量
// 用于存储当前设置的时间参数
unsigned char current_time1 = 25;
unsigned char current_time2 = 3;
unsigned char current_time3 = 15;
unsigned char keystate_7 = 0;
unsigned char sz1,sz2,sz3,sz4,sz5; // 参数存储变量(添加sz5声明)
sbit S5 = P3^2;//调整按键(减)
sbit L1 = P0^0;//东西,绿(主路)
sbit L2 = P0^1;//东西,黄(主路)
sbit L3 = P0^2;//东西,红(主路)
sbit L6 = P0^5;//南北,绿(辅路)
sbit L7 = P0^6;//南北,黄(辅路)
sbit L8 = P0^7;//南北,红(辅路)
sfr P4 = 0xC0;
sbit P44 = P4^4;
sbit P42 = P4^2;
sbit P30 = P3^0;
sbit P31 = P3^1;
sbit P32 = P3^2;
sbit P33 = P3^3;
sbit P34 = P3^4;
sbit P35 = P3^5;
sbit rs=P2^0;
sbit rw=P2^1;
sbit en=P1^2;
sbit LCD_E =P1^2;
void Delay(unsigned int t)
{
while(t--);
}
void select(unsigned char channel)
{
switch(channel)
{
case 4: //选LED
P2 = (P2 & 0x1f) | 0x80;
break;
case 5: //选蜂鸣器等
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6: //数码管位选
P2 = (P2 & 0x1f) | 0xc0;
break;
case 7: //数码管显示
P2 = (P2 & 0x1f) | 0xe0;
break;
case 0: //置零
P2 = (P2 & 0x1f) | 0x00;
break;
}
}
unsigned char Read24c02(unsigned char addr);
void Write24c02(unsigned char addr,unsigned char dat);
//系统初始化函数
void Initsystem()
{
LCD_E = 0; //关闭LCD使能
select(5);
P0 = 0x00; //关闭蜂鸣器
select(4);
P0 = 0xff; //关闭LED
select(0);
// 从EEPROM读取时间参数
current_time1 = Read24c02(0x01); //主路绿灯时间
current_time2 = Read24c02(0x02); //黄灯时间
current_time3 = Read24c02(0x03); //辅路绿灯时间
// 参数合法性检查,确保主路绿灯时间 > 辅路绿灯时间
if (current_time1 <= current_time3 || current_time1 < 10 || current_time3 < 5)
{
current_time1 = 25; // 默认主路绿灯25秒
current_time3 = 15; // 默认辅路绿灯15秒
current_time2 = 3; // 默认黄灯3秒
Write24c02(0x01, current_time1); // 保存到EEPROM
Write24c02(0x02, current_time2);
Write24c02(0x03, current_time3);
}
sz1 = current_time1; //保存绿灯时间
sz2 = current_time2; //保存黄灯时间
sz3 = Read24c02(0x04); //读取夜间模式开始时间
sz4 = Read24c02(0x05); //读取夜间模式结束时间
// 初始化显示值
s1 = current_time1; //主路初始为绿灯
s2 = current_time1 + current_time2; //辅路初始为红灯(主路绿灯+黄灯时间)
}
void Write24c02(unsigned char addr,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
unsigned char Read24c02(unsigned char addr)
{
unsigned char dat;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
dat = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return dat;
}
///////////////////////////////定时器0初始化
void InitTimer0()
{
TMOD = 0x00;
TH0 = (65535 - 50000) / 256;
TL0 = (65535 - 50000) % 256;
ET0 = 1;
EA = 1;
TR0 = 1;
}
void CloseSMG();
/////////////////////////////定时器0服务函数
void ServiceTimer0() interrupt 1
{
count++;//计数累加(每50ms一次)
if(color_state == 0)//状态0:东西绿(主路),南北红(辅路)
{
if(count == 20)//// 计数到20次(1秒)
{
count = 0;
s1--; //东西方向倒计时减1(绿灯)
s2--; //南北方向倒计时减1(红灯)
}
if(s1 == 0) //主路绿灯倒计时结束
{
s1 = current_time2; //进入下一状态,切换为主路黄灯时间
color_state = 1;//切换到状态1
}
}
else if(color_state == 1)//状态1:东西黄(主路),南北红(辅路)
{
if(count == 20) //计时一秒
{
count = 0;
s1--; //主路黄灯倒计时
s2--; //辅路红灯倒计时
}
if(s1 == 0) //主路黄灯倒计时结束
{
s1 = current_time1 + current_time2; //主路切换为红灯(辅路绿灯+黄灯时间)
s2 = current_time3; //辅路切换为绿灯
color_state = 2; //切换到状态2
}
}
else if(color_state == 2)//状态2:东西红(主路),南北绿(辅路)
{
if(count == 20)
{
count = 0; //计时
s1--; //主路红灯倒计时
s2--; //辅路绿灯倒计时
}
if(s2 == 0) //辅路绿灯倒计时结束
{
s2 = current_time2; //辅路切换为黄灯
color_state = 3; //切换到状态3
}
}
else if(color_state == 3) //状态3:东西红(主路),南北黄(辅路)
{
if(count == 20)
{
count = 0;
s1--; //主路红灯倒计时
s2--; //辅路黄灯倒计时
}
if(s2 == 0) //辅路黄灯倒计时结束
{
// 重新读取参数(可能已被修改)
current_time1 = Read24c02(0x01);
current_time2 = Read24c02(0x02);
current_time3 = Read24c02(0x03);
s1 = current_time1; //主路切换为绿灯
s2 = current_time1 + current_time2; //辅路切换为红灯
color_state = 0; //回到第一状态
}
}
}
void InitTimer1()
{
TMOD = 0x00;
TH1 = (65535 - 50000) / 256; //0.05s
TL1 = (65535 - 50000) % 256;
ET1 = 1;
EA = 1;
TR1 = 1;
}
//定时器 1 用于控制数码管秒闪烁效果(每 0.5 秒切换一次显示状态)。
void ServiceTimer1() interrupt 3
{
count1++;
if(count1 == 10)// 计数到10次(0.5秒)
{
count1 = 0;
SMG_state = ~SMG_state;// 切换秒闪状态(0→1或1→0)
}
}
void DisplaySMG_Bit(unsigned char pos,unsigned char dat)
{
LCD_E = 0;
select(7);
P0 = 0xff;
select(6);
P0 = 0x01 << pos;
select(7);
P0 = dat;
select(0);
}
void CloseSMG()
{
LCD_E = 0;
select(6);
P0 = 0xff;
select(7);
P0 = 0xff;
select(0);
}
void LED_working()
{
LCD_E = 0;
select(4);
if(keystate_7 == 0) //非设置状态
{
if(eve_mode == 1) //夜间模式
{
if(SMG_state)
{
P0 = 0xbd; //黄灯闪烁(东西和南北黄灯亮)
}
else
{
P0 = 0xff;
}
select(0);
}
else //正常模式
{
if(color_state == 0) //东西绿灯(主路),南北红灯(辅路)
{
P0 = 0xff;
L1 = 0; //东西绿
L8 = 0; //南北红
}
else if(color_state == 1) //东西黄灯(主路),南北红灯(辅路)
{
P0 = 0xff;
L2 = 0; //东西黄
L8 = 0; //南北红
}
else if(color_state == 2) //东西红灯(主路),南北绿灯(辅路)
{
P0 = 0xff;
L3 = 0; //东西红
L6 = 0; //南北绿
}
else if(color_state == 3) //东西红灯(主路),南北黄灯(辅路)
{
P0 = 0xff;
L3 = 0; //东西红
L7 = 0; //南北黄
}
select(0);
}
}
}
void SMG_working()
{
if(eve_mode != 1) //非夜间模式
{
// 显示东西方向(主路)倒计时
DisplaySMG_Bit(0, SMG_DuanMa[s1/10]);
Delay(100);
DisplaySMG_Bit(1, SMG_DuanMa[s1%10]);
Delay(100);
// 显示南北方向(辅路)倒计时
DisplaySMG_Bit(4, SMG_DuanMa[s2/10]);
Delay(100);
DisplaySMG_Bit(5, SMG_DuanMa[s2%10]);
Delay(100);
CloseSMG();
}
}
void scan_key()
{
P3 = 0x0f; P44 = 0; P42 = 0;
if((P3 & 0x0f) != 0x0f) //检测到按键按下
{
Delay(1000); //消抖
if((P3 & 0x0f) != 0x0f) //确认按键按下
{
P3 = 0xf0; P44 = 1; P42 = 1;
if(P44 == 0)
{
P3 = 0x0f; P44 = 0; P42 = 0;
if(P30 == 0) //S7:模式切换
{
keystate_7++;
while(P30 == 0) //等待按键释放
{
SMG_working();
}
if(keystate_7 == 5)
{
keystate_7 = 0; //循环回到模式0
}
}
else if(P31 == 0) //S6:参数加
{
if(keystate_7 == 1 && sz1 < 99) //主路绿灯时间增加(上限99秒)
{
sz1++;
Write24c02(0x01, sz1);
Delay(20000);
current_time1 = sz1;
// 确保主路绿灯时间 > 辅路绿灯时间
if(current_time1 <= sz3)
{
sz3 = current_time1 - 5; //辅路绿灯比主路少5秒
if(sz3 < 5) sz3 = 5; //辅路绿灯最小5秒
Write24c02(0x03, sz3);
Delay(20000);
current_time3 = sz3;
}
}
else if(keystate_7 == 2 && sz2 < 10) //黄灯时间增加(上限10秒)
{
sz2++;
Write24c02(0x02, sz2);
Delay(20000);
current_time2 = sz2;
}
else if(keystate_7 == 3) //夜间开始时间
{
sz3 = (sz3 + 1) % 24; //24小时循环
Write24c02(0x04, sz3);
Delay(20000);
}
else if(keystate_7 == 3) //夜间开始时间
{
sz3 = (sz3 + 1) % 24; //24小时循环
Write24c02(0x04, sz3);
Delay(20000);
}
else if(keystate_7 == 4) //夜间结束时间
{
sz4 = (sz4 + 1) % 24; //24小时循环
Write24c02(0x05, sz4);
Delay(20000);
}
while(P31 == 0) //等待按键释放
{
SMG_working();
}
}
else if(P32 == 0) //S5:参数减
{
if(keystate_7 == 1 && sz1 > 10) //主路绿灯时间减少(下限10秒)
{
sz1--;
Write24c02(0x01, sz1);
Delay(20000);
current_time1 = sz1;
// 确保主路绿灯时间 > 辅路绿灯时间
if(current_time1 <= sz3)
{
sz3 = current_time1 - 5; //辅路绿灯比主路少5秒
if(sz3 < 5) sz3 = 5; //辅路绿灯最小5秒
Write24c02(0x03, sz3);
Delay(20000);
current_time3 = sz3;
}
}
else if(keystate_7 == 2 && sz2 > 1) //黄灯时间减少(下限1秒)
{
sz2--;
Write24c02(0x02, sz2);
Delay(20000);
current_time2 = sz2;
}
else if(keystate_7 == 3) //夜间开始时间
{
sz3 = (sz3 + 23) % 24; //24小时循环
Write24c02(0x04, sz3);
Delay(20000);
}
else if(keystate_7 == 4) //夜间结束时间
{
sz4 = (sz4 + 23) % 24; //24小时循环
Write24c02(0x05, sz4);
Delay(20000);
}
while(P32 == 0) //等待按键释放
{
SMG_working();
}
}
}
else if(P42 == 0)
{
P3 = 0x0f; P44 = 0; P42 = 0;
if(P31 == 0) //S10:恢复默认参数
{
sz1 = 25; //主路绿灯25秒
sz2 = 3; //黄灯3秒
sz3 = 15; //辅路绿灯15秒
sz4 = 22; //夜间模式22:00开始
sz5 = 6; //夜间模式6:00结束
Write24c02(0x01, sz1);
Delay(20000);
Write24c02(0x02, sz2);
Delay(20000);
Write24c02(0x03, sz3);
Delay(20000);
Write24c02(0x04, sz4);
Delay(20000);
Write24c02(0x05, sz5);
Delay(20000);
// 更新当前参数
current_time1 = sz1;
current_time2 = sz2;
current_time3 = sz3;
while(P31 == 0); //等待按键释放
}
}
}
}
}
void InitDS1302()
{
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00); //关闭写保护
for(i=0; i<7; i++)
{
Write_Ds1302_Byte(Write_DS1302_addr[i], Timer[i]);
}
Write_Ds1302_Byte(0x8e,0x80); //打开写保护
}
void write_string(unsigned char X,unsigned char Y,unsigned char *s);
void ReadDS1302_Timer()
{
unsigned char i;
for(i=0; i<7; i++)
{
Timer[i] = Read_Ds1302_Byte(Read_DS1302_addr[i]);
}
// 更新时间显示缓冲区
display_buff[0] = (Timer[2] >> 4) + 48; //小时十位
display_buff[1] = (Timer[2] & 0x0f) + 48; //小时个位
display_buff[3] = (Timer[1] >> 4) + 48; //分钟十位
display_buff[4] = (Timer[1] & 0x0f) + 48; //分钟个位
display_buff[6] = (Timer[0] >> 4) + 48; //秒十位
display_buff[7] = (Timer[0] & 0x0f) + 48; //秒个位
// 在LCD上显示时间和状态
rw = 0;
en = 0;
write_string(2, 1, display_buff); //第二行显示时间
write_string(0, 0, lcd_buff); //第一行显示状态信息
}
//////////////////////////////////LCD相关子函数
void write_order(unsigned char lcd_order)
{
rs = 0; //写入命令
Data_Port = lcd_order; //输出命令名
Delay(200); //延时等待
en = 1; //使能信号上升沿触发
Delay(200);
en = 0;
}
void write_data(unsigned char lcd_data)
{
rs = 1; //写入数据
Data_Port = lcd_data; //输出数据
Delay(200);
en = 1; //使能信号上升沿触发
Delay(200);
en = 0;
}
void init_lcd()
{
rw = 0; //写模式
en = 0; //关闭使能
write_order(0x38); //设置8位数据接口,2行显示,5x8点阵
write_order(0x0c); //开显示,关光标,不闪烁
write_order(0x06); //写操作后光标右移,不移动屏幕
write_order(0x01); //清屏
}
void set_xy(unsigned char x, unsigned char y)
{
unsigned char address;
if(y == 0)
address = 0x80 + x; //第一行地址(0x80为起始地址)
else
address = 0xc0 + x; //第二行地址(0xc0为起始地址)
write_order(address); //设置显示位置
}
void write_string(unsigned char X, unsigned char Y, unsigned char *s)
{
set_xy(X, Y); //设置起始位置
while(*s) //循环写入字符串直到结束符
{
write_data(*s); //写入单个字符
s++; //指针后移
}
}
////////////////////////////////////夜间模式判断
void Eve_Jud()
{
// 获取当前小时
unsigned char current_hour = (Timer[2] >> 4) * 10 + (Timer[2] & 0x0f);
// 处理跨零点的夜间模式(如23:00-5:00)
if (sz3 > sz4) // 开始时间 > 结束时间,表示跨零点
{
if (current_hour >= sz3 || current_hour < sz4)
{
eve_mode = 1; // 夜间模式
}
else
{
eve_mode = 0; // 白天模式
}
}
else // 正常时段(如2:00-5:00)
{
if (current_hour >= sz3 && current_hour < sz4)
{
eve_mode = 1; // 夜间模式
}
else
{
eve_mode = 0; // 白天模式
}
}
}
//LCD状态显示函数
void Lcd_Display()
{
unsigned char i; // 声明循环变量i
if(keystate_7 == 0) //菜单状态0:显示默认信息
{
// 显示当前模式和状态
lcd_buff[0] = 'M';
lcd_buff[1] = 'A';
lcd_buff[2] = 'I';
lcd_buff[3] = 'N';
lcd_buff[4] = ':';
lcd_buff[5] = s1/10 + 48; //主路剩余时间十位
lcd_buff[6] = s1%10 + 48; //主路剩余时间个位
lcd_buff[7] = ' ';
lcd_buff[8] = 'S';
lcd_buff[9] = 'U';
lcd_buff[10] = 'B';
lcd_buff[11] = ':';
lcd_buff[12] = s2/10 + 48; //辅路剩余时间十位
lcd_buff[13] = s2%10 + 48; //辅路剩余时间个位
lcd_buff[14] = ' ';
lcd_buff[15] = ' ';
}
else if(keystate_7 == 1) //菜单状态1:设置主路绿灯时间
{
lcd_buff[0] = 'M';
lcd_buff[1] = 'A';
lcd_buff[2] = 'I';
lcd_buff[3] = 'N';
lcd_buff[4] = ' ';
lcd_buff[5] = 'G';
lcd_buff[6] = 'R';
lcd_buff[7] = 'E';
lcd_buff[8] = 'E';
lcd_buff[9] = 'N';
lcd_buff[10] = ':';
lcd_buff[11] = ' ';
if(SMG_state) //秒闪状态为1时显示数值
{
lcd_buff[12] = sz1/10 + 48; //主路绿灯时间十位
lcd_buff[13] = sz1%10 + 48; //主路绿灯时间个位
}
else //秒闪状态为0时隐藏数值
{
lcd_buff[12] = ' ';
lcd_buff[13] = ' ';
}
lcd_buff[14] = 's';
lcd_buff[15] = ' ';
}
else if(keystate_7 == 2) //设置黄灯时间
{
lcd_buff[0] = 'Y';
lcd_buff[1] = 'E';
lcd_buff[2] = 'L';
lcd_buff[3] = 'L';
lcd_buff[4] = 'O';
lcd_buff[5] = 'W';
lcd_buff[6] = ' ';
lcd_buff[7] = ' ';
lcd_buff[8] = ' ';
lcd_buff[9] = ' ';
lcd_buff[10] = ':';
lcd_buff[11] = ' ';
if(SMG_state)
{
lcd_buff[12] = sz2/10 + 48; //黄灯时间十位
lcd_buff[13] = sz2%10 + 48; //黄灯时间个位
}
else
{
lcd_buff[12] = ' ';
lcd_buff[13] = ' ';
}
lcd_buff[14] = 's';
lcd_buff[15] = ' ';
}
else if(keystate_7 == 3) //设置夜间开始时间
{
lcd_buff[0] = 'N';
lcd_buff[1] = 'I';
lcd_buff[2] = 'G';
lcd_buff[3] = 'H';
lcd_buff[4] = 'T';
lcd_buff[5] = ' ';
lcd_buff[6] = 'S';
lcd_buff[7] = 'T';
lcd_buff[8] = 'A';
lcd_buff[9] = 'R';
lcd_buff[10] = 'T';
lcd_buff[11] = ':';
if(SMG_state)
{
lcd_buff[12] = sz3/10 + 48; //开始时间十位
lcd_buff[13] = sz3%10 + 48; //开始时间个位
}
else
{
lcd_buff[12] = ' ';
lcd_buff[13] = ' ';
}
lcd_buff[14] = 'h';
lcd_buff[15] = ' ';
}
else if(keystate_7 == 4) //设置夜间结束时间
{
lcd_buff[0] = 'N';
lcd_buff[1] = 'I';
lcd_buff[2] = 'G';
lcd_buff[3] = 'H';
lcd_buff[4] = 'T';
lcd_buff[5] = ' ';
lcd_buff[6] = 'E';
lcd_buff[7] = 'N';
lcd_buff[8] = 'D';
lcd_buff[9] = ':';
lcd_buff[10] = ' ';
lcd_buff[11] = ' ';
if(SMG_state)
{
lcd_buff[12] = sz4/10 + 48; //结束时间十位
lcd_buff[13] = sz4%10 + 48; //结束时间个位
}
else
{
lcd_buff[12] = ' ';
lcd_buff[13] = ' ';
}
lcd_buff[14] = 'h';
lcd_buff[15] = ' ';
}
else
{
// 清空显示
for(i = 0; i < 16; i++) // 使用已声明的i变量
lcd_buff[i] = ' ';
}
}
void main()
{
Initsystem();
InitTimer0();
InitTimer1();
init_lcd();
InitDS1302();
while(1)
{
LED_working(); //控制LED显示
SMG_working(); //控制数码管显示倒计时
ReadDS1302_Timer(); //读取并显示时间
scan_key(); //扫描按键
Eve_Jud(); //判断是否处于夜间模式
Lcd_Display(); //更新LCD显示
}
}修改代码,使主路的绿,黄,红,辅路的绿,黄,红计时时长都可以通过键盘设定,参数应该合理,参数一旦设定在当前计时结束时生效。设定参数保存在EEPROM中,系统开机时,从EEPROM中读取参数配置系统,启动交通控制。最后给出完整的代码,不要省略