红外线遥控器控制数码管显示0到9

📅 发布时间:2026/7/13 13:55:17
红外线遥控器控制数码管显示0到9 一、项目概述1.1 项目名称红外遥控器按键解码 数码管静态锁存显示实验1.2 硬件平台普中 51 单片机开发板STC89C52/AT89C521.3 实现功能通过外部中断 0 接收 NEC 协议红外遥控器信号对红外 4 字节数据校验解析按键键值匹配预设按键码表转换为数码管段码数码管锁存显示按键数字松开遥控器数值不消失动态扫描 8 位共阴极数码管无按键时数码管熄灭。1.4 接线说明表格硬件外设单片机引脚说明红外接收头 OUTP3.2(INT0)外部中断 0 输入数码管段选P0 口输出段码数码管位选 LSAP2.23-8 译码器 A 脚数码管位选 LSBP2.33-8 译码器 B 脚数码管位选 LSCP2.43-8 译码器 C 脚二、程序整体架构程序单文件实现分为 7 大模块头文件、类型、引脚全局定义区基础延时底层函数数码管段码常量数组数码管动态扫描驱动函数红外初始化 外部中断解码服务函数键值转段码工具函数Main 主循环显示逻辑三、全局变量 / 宏定义说明3.1 数据类型重定义c运行typedef unsigned int u16; // 16位无符号整型 typedef unsigned char u8; // 8位无符号字符寄存器/数据专用 typedef unsigned long u32; // 32位无符号长整型预留扩展3.2 硬件引脚宏与位定义c运行#define SMG_SEG_PORT P0 // 数码管段选统一端口宏 sbit LSA P2^2; sbit LSB P2^3; sbit LSC P2^4; // 3-8译码器位选引脚 sbit IR_RX P3^2; // 红外接收信号引脚外部中断03.3 红外全局缓存变量c运行u8 gired_data[4]; // NEC协议4字节接收缓存[0]设备地址 [1]地址反码 [2]按键码 [3]按键反码 bit ir_new_flag 0; // 新按键标志位1收到有效按键0无新按键 u8 ir_key_save 0; // 按键锁存变量保存上一次合法按键码松开不丢失3.4 常量码表smg_std_code[16]共阴极数码管 0~F 标准段码ir_key_match_table[10]遥控器 10 个数字按键对应原始红外键值映射表四、各模块函数详细说明4.1 延时函数模块4.1.1 void delay_10us(u16 ten_us)功能简易 10us 级延时用于数码管动态扫描消隐、红外电平计时参数ten_us延时倍数单位 10us实现空循环消耗机器周期不精准满足驱动时序即可4.1.2 void delay_ms(u16 ms)功能毫秒级延时预留扩展使用本程序未调用参数ms延时毫秒数4.2 数码管驱动函数 void smg_display (u8 dat [], u8 pos)函数功能8 位数码管动态扫描显示从指定位置开始输出段码数组入参dat[]段码缓存数组存储要显示的每一位数码管段码pos起始显示位置范围 1~81 为最左侧数码管执行流程计算起始下标start_idx pos - 1循环从起始位到第 8 位数码管通过 LSA/LSB/LSC 组合输出 3-8 译码器位选选中当前数码管P0 口输出对应段码延时维持亮度P0 置 0 消隐消除拖影关键特性传入完整 8 字节缓存数值长期保存在数组内不会刷新空白。4.3 红外驱动模块4.3.1 void ired_init(void)红外接收外部中断初始化IT01外部中断 0 下降沿触发EX01使能 INT0 中断EA1开启 CPU 总中断IR_RX1红外引脚默认拉高。4.3.2 中断服务函数 void ired () interrupt 0触发条件红外接收头出现下降沿NEC 引导码低电平NEC 协议解码完整流程快速校验引脚不为低电平直接退出过滤杂波等待 9ms 引导低电平超时直接退出解码等待 4.5ms 引导高电平超时直接退出双层循环读取 4 字节、每字节 8bit 数据等待 bit 前 0.56ms 低电平统计高电平持续时间区分 bit0/bit1高电平≥0.8ms 判定为 1否则为 0数据校验判断按键码与反码是否互补校验通过保存键值到ir_key_save置ir_new_flag1通知主程序刷新显示校验失败仅清空临时接收缓存不覆盖已锁存按键值。中断安全设计全程多处超时判断异常信号直接 return 退出避免卡死中断。4.4 工具函数 static u8 ir_key_to_seg (u8 ir_code)修饰符static仅本文件内可调用外部不可访问功能根据红外原始键值匹配码表返回对应数字段码逻辑遍历ir_key_match_table匹配成功返回对应 0~9 段码无匹配返回 0x00熄灭。4.5 主函数 void main (void)变量定义u8 disp_buf[8]8 位数码管全局显示缓存全程保存显示内容u8 seg_val临时存储转换后的数码管段码。执行流程调用ired_init()初始化红外中断无限循环判断ir_new_flag是否收到新按键新按键转换键值为段码存入显示缓存清除标志持续调用smg_display扫描数码管核心解决 “显示消失” 逻辑显示缓存数值仅在收到新按键时更新无按键时缓存不变数码管持续显示旧数值不会归零消失。五、程序关键机制说明5.1 按键锁存机制中断解码成功后将键值存入ir_key_save仅新按键到来时才修改显示缓存松开遥控器后gired_data会被清空但ir_key_save永久保留数值数码管循环扫描不变的缓存画面稳定不消失。5.2 中断标志隔离机制ir_new_flag作为中断与主循环的通讯桥梁中断收到合法数据置 1主循环读取后置 0 避免主循环重复刷新、闪烁。5.3 NEC 数据校验机制NEC 协议规定第 3 字节按键码与第 4 字节互为按位取反校验失败判定为干扰信号仅清空临时缓存不覆盖显示值提升抗干扰能力。5.4 数码管消隐设计每次扫描完成后SMG_SEG_PORT 0x00清空段选消除多位同时点亮的拖影、重影。六、程序运行现象上电初始化无按键8 位数码管全部熄灭按下码表内匹配按键最左侧第一位数码管显示对应数字松开遥控器数字保持常亮不会消失按下其他按键数码管刷新为新按键数字无匹配红外按键数码管保持上一次有效数值不变。七、故障排查说明按键显示一闪就消失原代码无锁存变量每次循环读取归零的gired_data本程序通过ir_key_save锁存解决。数码管亮度暗、闪烁严重显示缓存长度不足使用完整 8 字节disp_buf[8]从第一位扫描刷新稳定。红外无反应检查 P3.2 接线、红外接收头正反、中断初始化 EA/EX0/IT0 是否开启。按键显示乱码 / 不显示核对ir_key_match_table键值与遥控器实际输出是否匹配。干扰导致数值乱跳程序内置 NEC 校验错误数据不会覆盖已保存按键抗干扰更强。#include reg52.h // 类型重定义统一放头部 typedef unsigned int u16; typedef unsigned char u8; typedef unsigned long u32; // 硬件引脚宏定义区 #define SMG_SEG_PORT P0 // 数码管段选P0 sbit LSA P2^2; sbit LSB P2^3; sbit LSC P2^4; sbit IR_RX P3^2; // 红外接收引脚 // 延时函数声明 void delay_10us(u16 ten_us); void delay_ms(u16 ms); // 数码管驱动声明 void smg_display(u8 dat[], u8 pos); // 红外驱动声明 void ired_init(void); u8 gired_data[4]; // 红外接收全局缓存 bit ir_new_flag 0; // 新按键接收标志 u8 ir_key_save 0; // 锁存保存有效按键码 /************************* 延时底层函数 *************************/ void delay_10us(u16 ten_us) { while(ten_us--); } void delay_ms(u16 ms) { u16 i, j; for(i ms; i 0; i--) for(j 110; j 0; j--); } /************************* 数码管段码表 *************************/ // 共阴极0~F标准段码 u8 code smg_std_code[16] { 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71 }; // 红外按键匹配码表 u8 code ir_key_match_table[10] {0x16,0x0C,0x18,0x5E,0x08,0x1C,0x5A,0x42,0x52,0x4A}; /************************* 数码管动态显示函数 *************************/ void smg_display(u8 dat[], u8 pos) { u8 i; u8 start_idx pos - 1; for(i start_idx; i 8; i) { // 位选译码 switch(i) { case 0: LSC1;LSB1;LSA1; break; case 1: LSC1;LSB1;LSA0; break; case 2: LSC1;LSB0;LSA1; break; case 3: LSC1;LSB0;LSA0; break; case 4: LSC0;LSB1;LSA1; break; case 5: LSC0;LSB1;LSA0; break; case 6: LSC0;LSB0;LSA1; break; case 7: LSC0;LSB0;LSA0; break; } SMG_SEG_PORT dat[i - start_idx]; delay_10us(100); SMG_SEG_PORT 0x00; // 消隐 } } /************************* 红外初始化 外部中断0 *************************/ void ired_init(void) { IT0 1; // 下降沿触发中断 EX0 1; // 使能外部中断0 EA 1; // 开总中断 IR_RX 1; // 红外接收脚拉高 } void ired() interrupt 0 { u8 ired_high_time 0; u16 time_cnt 0; u8 i, j; if (IR_RX ! 0) { return; } // 1.等待9ms引导低电平 time_cnt 1000; while ((IR_RX 0) (time_cnt 0)) { delay_10us(1); time_cnt--; } if (time_cnt 0) return; // 2.等待4.5ms引导高电平 time_cnt 500; while ((IR_RX 1) (time_cnt 0)) { delay_10us(1); time_cnt--; } if (time_cnt 0) return; // 3.读取4字节数据 for (i 0; i 4; i) { for (j 0; j 8; j) { time_cnt 600; while ((IR_RX 0) (time_cnt 0)) { delay_10us(1); time_cnt--; } if (time_cnt 0) return; ired_high_time 0; time_cnt 20; while ((IR_RX 1) (time_cnt 0)) { delay_10us(10); ired_high_time; time_cnt--; } if (ired_high_time 20) return; gired_data[i] 1; if (ired_high_time 8) { gired_data[i] | 0x80; } } } // 校验通过保存按键并置新数据标志 if (gired_data[2] (~gired_data[3])) { ir_key_save gired_data[2]; ir_new_flag 1; } else { // 校验失败不清空保存的旧按键只清空缓存 for (i 0; i 4; i) { gired_data[i] 0; } } } /************************* 红外按键码转换工具函数 *************************/ static u8 ir_key_to_seg(u8 ir_code) { u8 idx; for(idx 0; idx 10; idx) { if(ir_key_match_table[idx] ir_code) { return smg_std_code[idx]; } } return 0x00; // 无匹配返回消隐 } /************************* 主函数 循环显示红外按键 *************************/ void main(void) { // 8位完整缓存默认全部熄灭0x00 u8 disp_buf[8] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; u8 seg_val; ired_init(); while(1) { // 收到新按键才更新显示缓存 if(ir_new_flag 1) { seg_val ir_key_to_seg(ir_key_save); disp_buf[0] seg_val; ir_new_flag 0; // 清除标志等待下一次按键 } // 持续扫描显示缓存缓存数值不变数码管常亮不消失 smg_display(disp_buf, 1); } }