当前位置: 首页 > news >正文

单片机——实现交通信号灯管理

随便写写,汇总一下,就一个单片机,没有模拟软件,什么都没有~

点阵、数码管、led同时点亮

#include <reg52.h>sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;// 交通灯控制引脚定义
sbit A_Red    = P0^0;
sbit A_Yellow = P0^1;
sbit A_Green  = P0^2;
sbit B_Red    = P0^3;
sbit B_Yellow = P0^4;
sbit B_Green  = P0^5;unsigned char code LedChar[] = {  // 数码管显示字符转换表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
unsigned char flag1s = 0;          // 1秒定时标志// 交通灯状态变量
unsigned char current_state = 0;   // 0:A绿灯 1:A黄灯 2:B绿灯 3:B黄灯
unsigned char count_down = 27;     // 当前倒计时
bit yellow_blink = 0;              // 黄灯闪烁标志
unsigned int timer_count = 0;      // 定时器计数// LED流水灯变量
static unsigned char j = 0;
static unsigned int shift1 = 0x01;
static unsigned int shift2 = 0x80;
static unsigned char dir1 = 0;void main()
{EA = 1;                     // 开启总中断TMOD = 0x11;                // 使用定时器0和定时器1// 定时器0初始化(2ms,用于1秒定时)TH0 = 0xFC;TL0 = 0x67;ET0 = 1;TR0 = 1;// 定时器1初始化(1ms,用于数码管扫描)TH1 = 0xFC;TL1 = 0x67;ET1 = 1;TR1 = 1;// 初始状态:A绿灯,B红灯A_Green = 0;B_Red = 0;A_Red = B_Green = B_Yellow = A_Yellow = 1;while (1){if (flag1s == 1)        // 每秒触发一次{flag1s = 0;// 交通灯状态机处理if(count_down > 0) count_down--;if(count_down == 0) {switch(current_state) {case 0: // A绿灯结束current_state = 1;count_down = 3;A_Green = 1;A_Yellow = 0;break;case 1: // A黄灯结束current_state = 2;count_down = 17;A_Yellow = 1;B_Red = 1;B_Green = 0;break;case 2: // B绿灯结束current_state = 3;count_down = 3;B_Green = 1;B_Yellow = 0;break;case 3: // B黄灯结束current_state = 0;count_down = 27;B_Yellow = 1;A_Red = 1;A_Green = 0;break;}}// 更新数码管显示(显示倒计时)LedBuff[0] = LedChar[count_down % 10];  // 个位LedBuff[1] = LedChar[count_down / 10];   // 十位// 其余位保持熄灭LedBuff[2] = LedBuff[3] = LedBuff[4] = LedBuff[5] = 0xFF;}}
}// 定时器1中断服务函数(1ms,用于数码管扫描和LED流水灯)
void Timer1_ISR() interrupt 3
{static unsigned char index = 0;TH1 = 0xFC;TL1 = 0x67;// 黄灯闪烁处理(500ms间隔)if(++timer_count % 250 == 0 && (current_state == 1 || current_state == 3)) {yellow_blink = ~yellow_blink;if(current_state == 1) A_Yellow = yellow_blink;else B_Yellow = yellow_blink;}// 数码管动态扫描P0 = 0xFF;                  // 消隐ENLED = 0;ADDR3 = 1;                  // 选择数码管switch(index) {case 0: ADDR2=0; ADDR1=0; ADDR0=0; P0=LedBuff[0]; break;case 1: ADDR2=0; ADDR1=0; ADDR0=1; P0=LedBuff[1]; break;default: P0 = 0xFF;     // 其余位不显示}index = (index >= 1) ? 0 : index+1;// LED流水灯控制(复用case 6)if(index == 0) {  // 每轮扫描结束后处理LEDADDR3 = 1;    // 选择LED控制地址ADDR2 = 1;ADDR1 = 1;ADDR0 = 0;j++;if (j >= 200) {  // 每200ms改变一次LED位置j = 0;if (dir1 == 0) {  // 从左向右移动shift1 <<= 1;shift2 >>= 1;if (shift1 == 0x80 && shift2 == 0x01)dir1 = 1;  // 改变方向} else {  // 从右向左移动shift1 >>= 1;shift2 <<= 1;if (shift1 == 0x01 && shift2 == 0x80)dir1 = 0;  // 改变方向}}P0 = ~(shift1 | shift2);  // 输出LED状态}
}// 定时器0中断服务函数(2ms,用于1秒定时)
void Timer0_ISR() interrupt 1
{static unsigned int sec_count = 0;TH0 = 0xFC;TL0 = 0x67;if(++sec_count >= 500) {  // 500 * 2ms = 1秒sec_count = 0;flag1s = 1;}
}

红绿灯熄灭 

实现30秒绿灯倒计时熄灭,20秒倒计时红灯熄灭 

#include <reg52.h>sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;// 交通灯控制引脚定义
sbit A_Red    = P0^0;
sbit A_Yellow = P0^1;
sbit A_Green  = P0^2;
sbit B_Red    = P0^3;
sbit B_Yellow = P0^4;
sbit B_Green  = P0^5;unsigned char code LedChar[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};volatile unsigned char flag1s = 0;
volatile unsigned int timer_count = 0;
unsigned char current_state = 0;  // 0:A绿灯 1:A黄灯 2:B绿灯 3:B黄灯
unsigned char count_down = 27;    // 当前倒计时
bit yellow_blink = 0;              // 黄灯闪烁标志void main() {EA = 1;TMOD = 0x11;// 定时器0初始化(2ms)TH0 = 0xFC;TL0 = 0x67;ET0 = 1;TR0 = 1;// 定时器1初始化(1ms)TH1 = 0xFC;TL1 = 0x67;ET1 = 1;TR1 = 1;// 初始状态:A绿灯,B红灯A_Green = 0;B_Red = 0;A_Red = B_Green = B_Yellow = A_Yellow = 1;while(1) {if(flag1s) {flag1s = 0;// 状态机处理if(count_down > 0) count_down--;if(count_down == 0) {switch(current_state) {case 0: // A绿灯结束current_state = 1;count_down = 3;A_Green = 1;A_Yellow = 0;break;case 1: // A黄灯结束current_state = 2;count_down = 17;A_Yellow = 1;B_Red = 1;B_Green = 0;break;case 2: // B绿灯结束current_state = 3;count_down = 3;B_Green = 1;B_Yellow = 0;break;case 3: // B黄灯结束current_state = 0;count_down = 27;B_Yellow = 1;A_Red = 1;A_Green = 0;break;}}// 更新数码管显示LedBuff[0] = LedChar[count_down % 10];  // 个位LedBuff[1] = LedChar[count_down / 10];   // 十位}}
}// 定时器1中断(数码管扫描)
void Timer1_ISR() interrupt 3 {static unsigned char index = 0;TH1 = 0xFC;TL1 = 0x67;// 黄灯闪烁处理(500ms间隔)if(++timer_count % 250 == 0 && (current_state == 1 || current_state == 3)) {yellow_blink = ~yellow_blink;if(current_state == 1) A_Yellow = yellow_blink;else B_Yellow = yellow_blink;}// 数码管动态扫描P0 = 0xFF;ENLED = 0;ADDR3 = 1;switch(index) {case 0: ADDR2=0; ADDR1=0; ADDR0=0; P0=LedBuff[0]; break;case 1: ADDR2=0; ADDR1=0; ADDR0=1; P0=LedBuff[1]; break;default: P0 = 0xFF;}index = (index >= 1) ? 0 : index+1;
}// 定时器0中断(1秒定时)
void Timer0_ISR() interrupt 1 {static unsigned int sec_count = 0;TH0 = 0xFC;TL0 = 0x67;if(++sec_count >= 500) { // 500 * 2ms=1秒sec_count = 0;flag1s = 1;}
}

红绿灯跳转

当绿灯30秒剩余三秒时跳转至黄灯,当黄灯3秒后 跳转红灯,红灯20秒后继续跳转

#include <reg52.h>sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;unsigned char code LedChar[] = {  // 数码管显示字符转换表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
unsigned char flag1s = 0;
unsigned char countDownPhase = 0;  // 倒计时阶段:0=30->0, 1=20->0
unsigned long sec = 30;  // 初始值设为30
bit countDownFinished = 0;  // 倒计时结束标志void main()
{char j;unsigned char buf[6];EA = 1;                     // 开启总中断TMOD = 0x01;                // 只使用定时器0// 定时器0初始化(T0)TH0 = 0xFC;                 // 定时1msTL0 = 0x67;ET0 = 1;                    // 使能定时器0中断TR0 = 1;                    // 启动定时器0// 初始化显示30buf[0] = sec%10;            // 个位buf[1] = sec/10%10;         // 十位buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0; // 高位补0// 高位消零处理for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;  // 不显示前导零elsebreak;}// 显示有效数字for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}while (1){if (flag1s == 1)        // 每秒触发一次{flag1s = 0;if (!countDownFinished)  // 如果倒计时未结束{if (sec > 0){sec--;          // 秒计数器减1// 分解秒数为单个数字buf[0] = sec%10;    // 个位buf[1] = sec/10%10; // 十位buf[2] = sec/100%10;buf[3] = sec/1000%10;buf[4] = sec/10000%10;buf[5] = sec/100000%10;// 高位消零处理for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;  // 不显示前导零elsebreak;}// 显示有效数字for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}else{countDownFinished = 1;  // 倒计时结束// 切换到下一阶段countDownPhase++;if (countDownPhase == 1) {// 进入20->0阶段sec = 20;countDownFinished = 0;  // 重置结束标志// 更新显示buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;elsebreak;}for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}else if (countDownPhase >= 2) {// 所有阶段完成,重置到第一阶段countDownPhase = 0;sec = 30;countDownFinished = 0;// 更新显示buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;elsebreak;}for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}}}}}
}// 定时器0中断服务函数(修改LED控制部分)
void Timer0_ISR() interrupt 1
{ static unsigned char j = 0;static unsigned char i = 0;static unsigned int cnt = 0;static unsigned int shift1 = 0x01;static unsigned int shift2 = 0x80;static unsigned char dir1 = 0;TH0 = 0xFC;                 // 重新加载初值TL0 = 0x67;P0 = 0xFF;                  // 显示消隐ENLED = 0;                  // 使能显示ADDR3 = 1;                  // 选择数码管和LED// 数码管动态扫描(保持不变)switch (i){case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;case 5: ADDR2=1; ADDR1=0; ADDR0=1; i++; P0=LedBuff[5]; break;case 6: // LED控制(修改部分)ADDR2=1; ADDR1=1; ADDR0=0;// 根据倒计时阶段控制LEDif (countDownPhase == 0) {// 30秒倒计时阶段,点亮第一个LED(P0.0)P0 = 0xFE;  // 二进制 1111 1110,仅P0.0为低电平} else {// 20秒倒计时阶段,熄灭所有LEDP0 = 0xFF;  // 二进制 1111 1111,所有LED熄灭}i = 0;break;default: break;}// 1秒定时处理(保持不变)cnt++;if (cnt >= 1000)            // 1000ms = 1s{cnt = 0;flag1s = 1;             // 设置1秒标志}
}

增加B车道 

30秒阶段LED 逻辑:

30 秒→4 秒:点亮 LED2和 LED7
3 秒→0 秒:点亮 LED3和 LED

20 秒阶段 LED 逻辑:
20 秒→4 秒:点亮 LED4和 LED5
3 秒→0 秒:点亮 LED4和 LED6

#include <reg52.h>sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;unsigned char code LedChar[] = {  // 数码管显示字符转换表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
unsigned char flag1s = 0;
unsigned char countDownPhase = 0;  // 倒计时阶段:0=30秒阶段, 1=20秒阶段
unsigned long sec = 30;  // 初始值设为30
bit countDownFinished = 0;  // 倒计时结束标志void main()
{char j;unsigned char buf[6];EA = 1;                     // 开启总中断TMOD = 0x01;                // 只使用定时器0// 定时器0初始化(T0)TH0 = 0xFC;                 // 定时1msTL0 = 0x67;ET0 = 1;                    // 使能定时器0中断TR0 = 1;                    // 启动定时器0// 初始化显示30buf[0] = sec%10;            // 个位buf[1] = sec/10%10;         // 十位buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0; // 高位补0// 高位消零处理for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;  // 不显示前导零elsebreak;}// 显示有效数字for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}while (1){if (flag1s == 1)        // 每秒触发一次{flag1s = 0;if (!countDownFinished)  // 如果倒计时未结束{if (sec > 0){sec--;          // 秒计数器减1// 分解秒数为单个数字buf[0] = sec%10;    // 个位buf[1] = sec/10%10; // 十位buf[2] = sec/100%10;buf[3] = sec/1000%10;buf[4] = sec/10000%10;buf[5] = sec/100000%10;// 高位消零处理for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;  // 不显示前导零elsebreak;}// 显示有效数字for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}else{countDownFinished = 1;  // 倒计时结束// 切换到下一阶段countDownPhase++;if (countDownPhase == 1) {// 进入20->0阶段sec = 20;countDownFinished = 0;  // 重置结束标志// 更新显示buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;elsebreak;}for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}else if (countDownPhase >= 2) {// 所有阶段完成,重置到第一阶段countDownPhase = 0;sec = 30;countDownFinished = 0;// 更新显示buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;elsebreak;}for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}}}}}
}// 定时器0中断服务函数(修改LED控制部分)
void Timer0_ISR() interrupt 1
{ static unsigned char j = 0;static unsigned char i = 0;static unsigned int cnt = 0;TH0 = 0xFC;                 // 重新加载初值TL0 = 0x67;P0 = 0xFF;                  // 显示消隐ENLED = 0;                  // 使能显示ADDR3 = 1;                  // 选择数码管和LED// 数码管动态扫描switch (i){case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;case 5: ADDR2=1; ADDR1=0; ADDR0=1; i++; P0=LedBuff[5]; break;case 6: // LED控制部分ADDR2=1; ADDR1=1; ADDR0=0;// 根据倒计时阶段和剩余秒数控制LEDif (countDownPhase == 0) {// 30秒倒计时阶段if (sec > 3) {// 前27秒:LED1(P0.0)和LED6(P0.5)亮P0 = 0xDE;  // 二进制 1101 1110 (P0.0和P0.5低电平)} else if (sec > 0) {// 后3秒:LED2(P0.1)和LED6(P0.5)亮P0 = 0xDD;  // 二进制 1101 1101 (P0.1和P0.5低电平)} else {// 倒计时结束:熄灭所有LEDP0 = 0xFF;}} else if (countDownPhase == 1) {// 20秒倒计时阶段if (sec > 3) {// 前17秒:LED3(P0.2)和LED4(P0.3)亮P0 = 0xF3;  // 二进制 1111 0011 (P0.2和P0.3低电平)} else if (sec > 0) {// 后3秒:LED3(P0.2)和LED5(P0.4)亮P0 = 0xEB;  // 二进制 1110 1011 (P0.2和P0.4低电平)} else {// 倒计时结束:熄灭所有LEDP0 = 0xFF;}} else {// 其他阶段:熄灭所有LEDP0 = 0xFF;}i = 0;break;default: break;}// 1秒定时处理cnt++;if (cnt >= 1000)            // 1000ms = 1s{cnt = 0;flag1s = 1;             // 设置1秒标志}
}

按键控制led灯的10秒定时亮灭

#include <reg52.h>// 引脚定义(补充完整矩阵按键输出和输入引脚)
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY_OUT_1 = P2^3;  // 矩阵按键输出引脚(完整定义)
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P1^2;  // 假设KEY_OUT_3连接到P1^2(避免与ADDR2冲突)
sbit KEY_OUT_4 = P1^3;  // 假设KEY_OUT_4连接到P1^3(避免与ADDR3冲突)
sbit KEY_IN_1  = P2^4;  // 矩阵按键输入引脚(完整定义)
sbit KEY_IN_2  = P2^5;
sbit KEY_IN_3  = P2^6;
sbit KEY_IN_4  = P2^7;
sbit LED1 = P0^0;      // K2控制的LED(原LED)
sbit LED4 = P0^3;      // K1控制的LED4(假设连接到P0^3)// 状态变量
unsigned char KeySta[4][4] = {  // 按键状态数组(使用[0][0]对应K1,[0][1]对应K2){1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}
};
unsigned int Timer10s_LED1 = 0;  // LED1的10秒计时计数器
unsigned int Timer10s_LED4 = 0;  // LED4的10秒计时计数器
bit Led1Active = 0;             // LED1激活标志
bit Led4Active = 0;             // LED4激活标志// 定时器0参数(1ms定时)
#define TIMER0_RELOAD_H 0xFC  // 1ms初值高位
#define TIMER0_RELOAD_L 0x67  // 1ms初值低位void main()
{// 硬件初始化ENLED = 0;                // 使能LED控制ADDR3 = 1;                // 选择LED所在电路(共阳连接)ADDR2 = 1;ADDR1 = 1;ADDR0 = 0;LED1 = 1;                 // 初始熄灭LED1LED4 = 1;                 // 初始熄灭LED4// 定时器0初始化TMOD = 0x01;              // 模式1(16位定时器)TH0 = TIMER0_RELOAD_H;TL0 = TIMER0_RELOAD_L;ET0 = 1;                  // 使能定时器中断EA = 1;                   // 使能总中断TR0 = 1;                  // 启动定时器// 矩阵按键初始化KEY_OUT_1 = 1;            // 初始拉高所有行KEY_OUT_2 = 1;KEY_OUT_3 = 1;KEY_OUT_4 = 1;while (1){// 检测K1按键状态(矩阵坐标[0][0],第1行第1列)if (KeySta[0][0] == 0 && !Led4Active)  // K1按下且LED4未激活{LED4 = 0;                 // 点亮LED4Led4Active = 1;           // 标记LED4激活Timer10s_LED4 = 0;        // 重置LED4计时器while (KeySta[0][0] == 0);  // 等待K1释放}// 检测K2按键状态(矩阵坐标[0][1],第1行第2列)if (KeySta[0][1] == 0 && !Led1Active)  // K2按下且LED1未激活{LED1 = 0;                 // 点亮LED1Led1Active = 1;           // 标记LED1激活Timer10s_LED1 = 0;        // 重置LED1计时器while (KeySta[0][1] == 0);  // 等待K2释放}}
}/* 定时器0中断服务函数(1ms执行一次) */
void InterruptTimer0() interrupt 1
{static unsigned char keyout = 0;       // 矩阵行扫描索引static unsigned char keybuf[4][4] = {  // 按键消抖缓冲区{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}};// 重新加载定时器初值TH0 = TIMER0_RELOAD_H;TL0 = TIMER0_RELOAD_L;// 扫描第1行(KEY_OUT_1)KEY_OUT_1 = 0;          // 拉低第1行KEY_OUT_2 = 1;          // 拉高其他行KEY_OUT_3 = 1;KEY_OUT_4 = 1;// 读取K1和K2的按键值(第1行第1、2列)keybuf[0][0] = (keybuf[0][0] << 1) | KEY_IN_1;  // K1(第1列)keybuf[0][1] = (keybuf[0][1] << 1) | KEY_IN_2;  // K2(第2列)// K1消抖逻辑if ((keybuf[0][0] & 0x0F) == 0x00)  {KeySta[0][0] = 0;  // 标记K1按下}else if ((keybuf[0][0] & 0x0F) == 0x0F){KeySta[0][0] = 1;  // 标记K1释放}// K2消抖逻辑if ((keybuf[0][1] & 0x0F) == 0x00)  {KeySta[0][1] = 0;  // 标记K2按下}else if ((keybuf[0][1] & 0x0F) == 0x0F){KeySta[0][1] = 1;  // 标记K2释放}// LED1计时逻辑if (Led1Active){Timer10s_LED1++;if (Timer10s_LED1 >= 10000)  {LED1 = 1;Led1Active = 0;}}// LED4计时逻辑if (Led4Active){Timer10s_LED4++;if (Timer10s_LED4 >= 10000)  {LED4 = 1;Led4Active = 0;}}
}

按下按键暂停红绿灯时间

#include <reg52.h>// 引脚定义
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P1^2;
sbit KEY_OUT_4 = P1^3;
sbit KEY_IN_1  = P2^4;  // K1按键输入
sbit KEY_IN_2  = P2^5;  // K2按键输入// 数码管显示
unsigned char code LedChar[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};// 状态变量
unsigned char flag1s = 0;
unsigned char flag10ms = 0;
unsigned char countDownPhase = 0;  // 0=30秒阶段, 1=20秒阶段
unsigned long sec = 30;
bit countDownFinished = 0;// 按键状态和LED控制
unsigned char KeySta[4][4] = {{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};
bit K1_Pressed = 0;  // K1按键按下标志
bit K2_Pressed = 0;  // K2按键按下标志
bit LED_SpecialMode = 0; // 特殊LED模式标志
unsigned int SpecialModeTimer = 0; // 特殊模式计时器(10秒)
unsigned int secCnt = 0; // 秒计数器
bit SpecialModeType = 0; // 0=K1模式, 1=K2模式void main()
{char j;unsigned char buf[6];// 初始化EA = 1;TMOD = 0x01;TH0 = 0xFC;TL0 = 0x67;ET0 = 1;TR0 = 1;// 初始化显示30buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;elsebreak;}for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}while (1){// 检测K1按键状态(30秒阶段)if (countDownPhase == 0 && KeySta[0][0] == 0 && !K1_Pressed && sec > 3){K1_Pressed = 1;LED_SpecialMode = 1;SpecialModeTimer = 0;SpecialModeType = 0; // K1模式while (KeySta[0][0] == 0);  // 等待释放}else if (KeySta[0][0] == 1){K1_Pressed = 0;}// 检测K2按键状态(20秒阶段)if (countDownPhase == 1 && KeySta[0][1] == 0 && !K2_Pressed && sec > 3){K2_Pressed = 1;LED_SpecialMode = 1;SpecialModeTimer = 0;SpecialModeType = 1; // K2模式while (KeySta[0][1] == 0);  // 等待释放}else if (KeySta[0][1] == 1){K2_Pressed = 0;}// 特殊模式计时if (flag10ms && LED_SpecialMode) {SpecialModeTimer++;if (SpecialModeTimer >= 1000) { // 1000*10ms = 10秒LED_SpecialMode = 0;}}// 倒计时处理if (flag1s == 1){flag1s = 0;if (!countDownFinished){if (sec > 0){sec--;buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;elsebreak;}for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}else{countDownFinished = 1;countDownPhase++;LED_SpecialMode = 0; // 阶段切换时重置特殊模式if (countDownPhase == 1) {sec = 20;countDownFinished = 0;buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;elsebreak;}for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}else if (countDownPhase >= 2) {countDownPhase = 0;sec = 30;countDownFinished = 0;buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--){if (buf[j] == 0)LedBuff[j] = 0xFF;elsebreak;}for (; j>=0; j--){LedBuff[j] = LedChar[buf[j]];}}}}}}
}// 定时器0中断服务函数
void Timer0_ISR() interrupt 1
{ static unsigned char i = 0;static unsigned int cnt = 0;static unsigned char keyout = 0;static unsigned char keybuf[4][4] = {{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}};TH0 = 0xFC;TL0 = 0x67;// 按键扫描(仅扫描第1行)KEY_OUT_1 = 0;KEY_OUT_2 = 1;KEY_OUT_3 = 1;KEY_OUT_4 = 1;keybuf[0][0] = (keybuf[0][0] << 1) | KEY_IN_1;  // K1keybuf[0][1] = (keybuf[0][1] << 1) | KEY_IN_2;  // K2// K1消抖if ((keybuf[0][0] & 0x0F) == 0x00)KeySta[0][0] = 0;else if ((keybuf[0][0] & 0x0F) == 0x0F)KeySta[0][0] = 1;// K2消抖if ((keybuf[0][1] & 0x0F) == 0x00)KeySta[0][1] = 0;else if ((keybuf[0][1] & 0x0F) == 0x0F)KeySta[0][1] = 1;// 数码管显示和LED控制P0 = 0xFF;ENLED = 0;ADDR3 = 1;switch (i){case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;case 5: ADDR2=1; ADDR1=0; ADDR0=1; i++; P0=LedBuff[5]; break;case 6:ADDR2=1; ADDR1=1; ADDR0=0;if (countDownPhase == 0) {// 30秒阶段if (sec > 3) {// 前27秒if (LED_SpecialMode && !SpecialModeType) {P0 = 0xD7;  // LED1(P0.0)和LED4(P0.3)亮 (11010111)} else {P0 = 0xDE;  // 默认:LED1(P0.0)和LED6(P0.5)亮 (11011110)}} else if (sec > 0) {// 后3秒P0 = 0xDD;  // LED2(P0.1)和LED6(P0.5)亮 (11011101)} else {P0 = 0xFF;  // 熄灭所有}} else if (countDownPhase == 1) {// 20秒阶段if (sec > 3) {// 前17秒if (LED_SpecialMode && SpecialModeType) {P0 = 0xF6;  // LED1(P0.0)和LED4(P0.3)亮 (11110110)} else {P0 = 0xF3;  // 默认:LED3(P0.2)和LED4(P0.3)亮 (11110011)}} else if (sec > 0) {// 后3秒P0 = 0xEB;  // LED3(P0.2)和LED5(P0.4)亮 (11101011)} else {P0 = 0xFF;  // 熄灭所有}} else {P0 = 0xFF;}i = 0;break;default: break;}// 定时处理cnt++;if (cnt >= 10) {  // 10mscnt = 0;flag10ms = 1;secCnt++;if (secCnt >= 100) {  // 100*10ms = 1ssecCnt = 0;flag1s = 1;}} else {flag10ms = 0;}
}

基于STC89C52单片机的交通灯控制系统设计
用单片机控制一个交通信号灯系统,设 A 车道与 B 车道交叉组成十字路口, A 是主车道, B 是支车道。具体要求如下:(1)用发光二极管模拟交通信号灯, A 、 B 车道各三盏灯,分别代表红、黄、绿;用
按键开关模拟车辆检测信号。(2)
正常情况下, A 、 B 辆车道轮流放行, A 车道放行30s,其中3s用于警告; B 车道放行20s,其中3s用于警告。
(3)
在交通繁忙时,交通信号灯控制系统应有手控开关,可人为地改变信号灯的状态,以缓解交通拥挤状况。在 B 车道放行期间,若 A 车道有车而 B 车道无车,按下开关K1使 A 车道放行10s;在 A 车道放行期间,若 B 车道有车而 A 车道无车,按下开关K2使 B 车道放行10s。(4)有紧急车辆通过时,按下K3开关使 A 、 B 车道均为红灯,禁行15s。

 

#include <reg52.h>sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;// 矩阵按键引脚定义
sbit KEY_IN_1 = P2^4;  // 第1列
sbit KEY_IN_2 = P2^5;  // 第2列
sbit KEY_IN_3 = P2^6;  // 第3列
sbit KEY_IN_4 = P2^7;  // 第4列
sbit KEY_OUT_1 = P2^3; // 第1行
sbit KEY_OUT_2 = P2^2; // 第2行
sbit KEY_OUT_3 = P2^1; // 第3行
sbit KEY_OUT_4 = P2^0; // 第4行unsigned char code LedChar[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
unsigned char flag1s = 0;
unsigned char countDownPhase = 0;  // 0=30秒阶段, 1=20秒阶段
unsigned long sec = 30;
bit countDownFinished = 0;// 按键和LED控制变量
bit K1_pressed = 0;          // K1按下标志(第1行第1列)
bit K2_pressed = 0;          // K2按下标志(第1行第2列)
unsigned char K1_holdTime = 0; // K1按下保持时间
unsigned char K2_holdTime = 0; // K2按下保持时间
bit LED_override = 0;        // LED覆盖标志
unsigned char overrideLEDState = 0xFF; // 覆盖的LED状态
unsigned char normalLEDState = 0xFF; // 正常LED状态void KeyScan();
void UpdateLEDs();void main()
{char j;unsigned char buf[6];EA = 1;TMOD = 0x01;TH0 = 0xFC;TL0 = 0x67;ET0 = 1;TR0 = 1;// 初始化显示30buf[0] = sec%10;buf[1] = sec/10%10;buf[2] = 0; buf[3] = 0; buf[4] = 0; buf[5] = 0;for (j=5; j>=1; j--) {if (buf[j] == 0) LedBuff[j] = 0xFF;else break;}for (; j>=0; j--) {LedBuff[j] = LedChar[buf[j]];}while(1) {KeyScan();if (flag1s == 1) {flag1s = 0;// 处理K1按下后的10秒计时if (K1_pressed) {K1_holdTime++;if (K1_holdTime >= 10) {K1_pressed = 0;K1_holdTime = 0;LED_override = 0; // 恢复正常LED状态}}// 处理K2按下后的10秒计时if (K2_pressed) {K2_holdTime++;if (K2_holdTime >= 10) {K2_pressed = 0;K2_holdTime = 0;LED_override = 0; // 恢复正常LED状态}}// 正常倒计时处理if (!countDownFinished) {if (sec > 0) {sec--;// 更新数码管显示buf[0] = sec%10;buf[1] = sec/10%10;for (j=5; j>=1; j--) {if (buf[j] == 0) LedBuff[j] = 0xFF;else break;}for (; j>=0; j--) {LedBuff[j] = LedChar[buf[j]];}// 更新正常LED状态if (countDownPhase == 0) { // 30秒阶段if (sec > 3) normalLEDState = 0xDE; // LED1&6else if (sec > 0) normalLEDState = 0xDD; // LED2&6else normalLEDState = 0xFF;} else if (countDownPhase == 1) { // 20秒阶段if (sec > 3) normalLEDState = 0xF3; // LED3&4else if (sec > 0) normalLEDState = 0xEB; // LED3&5else normalLEDState = 0xFF;}} else {// 倒计时结束,切换到下一阶段countDownFinished = 1;}} else {// 阶段切换处理countDownPhase++;if (countDownPhase == 1) { // 切换到20秒阶段sec = 20;countDownFinished = 0;normalLEDState = 0xF3; // LED3&4} else if (countDownPhase >= 2) { // 循环回到30秒阶段countDownPhase = 0;sec = 30;countDownFinished = 0;normalLEDState = 0xDE; // LED1&6}// 更新数码管显示buf[0] = sec%10;buf[1] = sec/10%10;for (j=5; j>=1; j--) {if (buf[j] == 0) LedBuff[j] = 0xFF;else break;}for (; j>=0; j--) {LedBuff[j] = LedChar[buf[j]];}}}}
}void KeyScan()
{static unsigned char keyDebounceK1 = 0;static unsigned char keyDebounceK2 = 0;// 扫描第1行KEY_OUT_1 = 0;  // 选通第1行KEY_OUT_2 = 1;KEY_OUT_3 = 1;KEY_OUT_4 = 1;// 检测K1 (第1行第1列)if (KEY_IN_1 == 0) { keyDebounceK1++;if (keyDebounceK1 >= 5 && !K1_pressed && countDownPhase == 0 && sec >= 10) {K1_pressed = 1;K1_holdTime = 0;LED_override = 1;overrideLEDState = 0xF3; // LED3和LED4亮}} else {keyDebounceK1 = 0;}// 检测K2 (第1行第2列)if (KEY_IN_2 == 0) { keyDebounceK2++;if (keyDebounceK2 >= 5 && !K2_pressed && countDownPhase == 1 && sec >= 10) {K2_pressed = 1;K2_holdTime = 0;LED_override = 1;overrideLEDState = 0xDE; // LED1和LED6亮}} else {keyDebounceK2 = 0;}
}void Timer0_ISR() interrupt 1
{static unsigned char i = 0;static unsigned int cnt = 0;TH0 = 0xFC;TL0 = 0x67;P0 = 0xFF;ENLED = 0;ADDR3 = 1;// 数码管动态扫描switch(i) {case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;case 5: ADDR2=1; ADDR1=0; ADDR0=1; i++; P0=LedBuff[5]; break;case 6:ADDR2=1; ADDR1=1; ADDR0=0;// LED控制if (LED_override) {P0 = overrideLEDState; // 使用覆盖的LED状态} else {P0 = normalLEDState; // 正常LED状态}i = 0;break;default: break;}// 1秒定时cnt++;if (cnt >= 1000) {cnt = 0;flag1s = 1;}
}

相关文章:

  • 学习STC51单片机13(芯片为STC89C52RC)
  • leetcode 61. Rotate List和86. Partition List
  • 搭建自己的语音对话系统:开源 S2S 流水线深度解析与实战
  • 实验-设计一个应用系统(计算机组成原理)
  • CentOS停止维护了,解决yum不能安装软件的问题
  • windows bat 在目录下(包括子目录)搜索批量指定文件名称复制到另一个文件夹内
  • QT聊天项目DAY12
  • Git企业级——进阶
  • 达梦数据库-学习-21-C 外部函数
  • 怎么判断一个Android APP使用了Cordova这个跨端框架
  • ubuntu设置开机不输密码笔记
  • 《STL--- vector的使用及其底层实现》
  • 会话管理有哪些
  • 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之3D高斯椭球
  • 【三维重建】【3DGS系列】【深度学习】3DGS的理论基础知识之协方差矩阵控制椭球
  • JavaScript篇:解密ES6的“藏宝图“:Set和Map的奇妙冒险
  • 基于注解的Sentinel限流熔断
  • Sentinel+OpenFeign实现服务熔断与降级:构建弹性微服务架构的核心实践
  • PET,Prompt Tuning,P Tuning,Lora,Qlora 大模型微调的简介
  • PyQt5安装,在Pycharm上配置以及使用教程
  • 网站建设基本流程是什么/爱站网 关键词挖掘工具站
  • 哪个网站做任务赚钱的/seo网站搜索优化
  • 成都网络营销网站/网站推广的四个阶段
  • 网站怎么优化到首页/搜索引擎营销的优势和劣势
  • 网站中的文字滑动怎么做的/电脑培训机构
  • 快手怎么引流推广/百度推广seo