51 单片机红外遥控数码管 + 蜂鸣器音乐系统

📅 2026/7/14 18:15:35
51 单片机红外遥控数码管 + 蜂鸣器音乐系统
一、项目概述1. 项目功能红外遥控解码外部中断 0 接收 NEC 红外信号识别遥控器数字 0~9 按键数码管动态显示8 位共阴极数码管第一位实时显示当前按下的数字蜂鸣器音乐播放按下 0~9 分别触发 10 首完整乐曲播放过程持续刷新数码管乐曲完整播放完毕自动静音无流水灯功能仅保留数码管、红外、蜂鸣器三大模块。2. 硬件资源分配表格外设 引脚 说明数码管段选 P0 共阴极数码管段码输出数码管位选 LSA P2^2 3-8 译码器 A 脚数码管位选 LSB P2^3 3-8 译码器 B 脚数码管位选 LSC P2^4 3-8 译码器 C 脚红外接收管 P3^2 / INT0 外部中断 0下降沿触发解码无源蜂鸣器 P2^5 低电平发声高电平静音3. 开发环境主控STC89C52/AT89C52编译软件Keil C51标准头文件reg52.h二、全局宏与类型定义说明1. 数据类型重定义c运行typedef unsigned int u16; // 16位无符号整型typedef unsigned char u8; // 8位无符号字符typedef unsigned long u32; // 32位无符号长整型统一数据类型提高代码可读性、跨芯片兼容性。2. 音符频率宏无源蜂鸣器L1~L7低音 1~7 频率M1~M7中音 1~7 频率乐曲主音调H1~H7高音 1~7 频率REST 0休止符不发声仅延时3. 歌曲映射关系表格红外按键 数组名 曲目名称0 song0 小星星1 song1 两只老虎2 song2 生日快乐3 song3 茉莉花4 song4 上学歌5 song5 新年好6 song6 欢乐颂7 song7 虫儿飞8 song8 拔萝卜9 song9 世上只有妈妈好song_list[10]歌曲指针数组通过下标快速切换曲目。三、全局变量说明c运行u8 gired_data[4]; // 红外接收4字节缓存地址反地址按键码反按键码bit ir_new_flag 0; // 红外新按键标志1收到有效按键u8 ir_key_save 0; // 锁存有效红外按键码u8 play_song_idx 0; // 当前待播放歌曲下标0~9bit play_flag 0; // 播放标志1触发播放乐曲四、函数接口文档1. 延时函数void delay_10us(u16 ten_us)功能简易 10us 级软件延时参数ten_us 延时单位110 微秒用途数码管动态消隐、红外时序采集void delay_ms(u16 ms)功能毫秒级软件延时参数ms 延时毫秒数用途音符停顿、休止符延时2. 数码管驱动void smg_display(u8 dat[], u8 pos)功能8 位数码管动态扫描显示参数dat[]显示缓存数组存放每一位段码pos起始显示位置本程序固定传入 1只从第一位开始显示数字原理3-8 译码器控制位选输出段码后消隐防止拖影常量数组 smg_std_code[16]共阴极数码管标准段码下标 0~9 对应数字 0~9 显示段码。3. 红外驱动模块void ired_init(void)功能红外外部中断 0 初始化配置下降沿触发中断、开外部中断 0、开总中断 EA、红外引脚拉高void ired() interrupt 0中断号0外部中断 0 服务函数解码流程等待 9ms 低电平引导码等待 4.5ms 高电平分隔码循环读取 32 位数据4 字节校验按键码与反码校验通过保存按键并置ir_new_flag1u8 ir_key_to_seg(u8 ir_code)功能红外按键码匹配转换为数码管段码参数ir_code 红外接收的按键码逻辑遍历ir_key_match_table匹配 0~9匹配成功赋值播放曲目下标、置播放标志返回对应数字段码无匹配返回 0x00消隐ir_key_match_table[10]遥控器 0~9 按键对应的 NEC 码值映射表。4. 蜂鸣器音乐模块void beep_play(u16 freq, u16 time)功能输出指定频率方波驱动蜂鸣器发声参数freq音符频率REST (0) 代表休止符time发声持续时长原理根据频率计算半周期翻转 IO 输出方波休止符仅延时不输出电平。void music_scan(u8 song_idx,u8 dat[])功能完整播放指定下标乐曲播放过程持续刷新数码管参数song_idx歌曲下标 0~9dat[]数码管显示缓存播放时实时刷新数字逻辑遍历乐谱数组读到 0 代表歌曲结束每个音符发声后短暂停顿循环调用数码管显示防止黑屏。5. 主函数 void main(void)主循环逻辑上电初始化蜂鸣器静音、红外模块循环检测红外新按键标志收到按键更新显示缓存第一位数字清除接收标志判断播放标志标志置 1完整播放对应歌曲播放结束清零播放标志、关闭蜂鸣器持续调用数码管动态扫描保证数字常亮。五、工作流程系统上电红外中断开启数码管全灭、蜂鸣器静音按下遥控器数字键外部中断触发解码校验按键码解码成功缓存数字段码置播放标志主循环检测到播放标志进入乐曲播放函数播放全程不断刷新数码管保持数字显示整首乐曲播放完毕退出播放函数蜂鸣器静音循环刷新数码管等待下一次红外按键触发。#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; // 红外接收引脚 sbit BEEP P2^5; // 蜂鸣器输出引脚 // 延时函数声明 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 beep_play(u16 freq, u16 time); void music_scan(u8 song_idx,u8 dat[]); // 音符频率定义 #define L1 262 #define L2 294 #define L3 330 #define L4 349 #define L5 392 #define L6 440 #define L7 494 #define M1 523 #define M2 587 #define M3 659 #define M4 698 #define M5 784 #define M6 880 #define M7 988 #define H1 1047 #define H2 1175 #define H3 1319 #define H4 1397 #define H5 1568 #define H6 1760 #define H7 1976 #define REST 0 // 休止符 // 10首歌曲乐谱数组 // 10首完整加长乐谱数组 u16 code song0[] { M1,M1,M5,M5,M6,M6,M5,REST, M4,M4,M3,M3,M2,M2,M1,REST, M5,M5,M4,M4,M3,M3,M2,REST, M5,M5,M4,M4,M3,M3,M2,REST, M1,M1,M5,M5,M6,M6,M5,REST, M4,M4,M3,M3,M2,M2,M1,REST,0 }; // 小星星 u16 code song1[] { M1,M2,M3,M1,M1,M2,M3,M1, M3,M4,M5,REST,M3,M4,M5,REST, M5,M6,M5,M4,M3,M1,M5,M6,M5,M4,M3,M1, M1,L5,M1,REST,M1,L5,M1,REST,0 }; // 两只老虎 u16 code song2[] { M5,M5,M6,M5,H1,M7,REST, M5,M5,M6,M5,H2,H1,REST, M5,M5,H5,M3,H1,M7,M6,REST, M4,M4,M3,M1,M2,M1,REST,0 }; // 生日快乐 u16 code song3[] { M3,M5,M6,M6,M5,M3,M2,REST, M2,M3,M5,M3,M2,REST, M3,M5,M6,H1,H6,M5,M3,REST, M2,M3,M5,M2,M1,REST,0 }; // 茉莉花 u16 code song4[] { M1,M2,M3,M5,M3,M2,M1,REST, M3,M4,M5,M6,M5,M4,REST, M1,M2,M3,M5,M3,M2,M1,REST, M2,M3,M4,M2,M1,REST,0 }; // 上学歌 u16 code song5[] { M1,M1,M2,M3,M5,M3,M2,REST, M1,M1,M2,M3,M1,REST, M2,M2,M3,M5,M3,M2,REST, M2,M2,M3,M5,M1,REST,0 }; // 新年好 u16 code song6[] { M3,M3,M4,M5,M5,M4,M3,M2, M1,M1,M2,M3,M3,M2,M2,REST, M3,M3,M4,M5,M5,M4,M3,M2, M1,M1,M2,M3,M2,M1,REST,0 }; // 欢乐颂 u16 code song7[] { M3,M5,M6,M7,H1,H1,M7,M6, M7,H1,M2,M2,REST, M3,M5,M6,M7,H1,H1,M7,M6, M7,H1,M2,M1,REST,0 }; // 虫儿飞 u16 code song8[] { M1,M3,M5,M1,REST,M1,M3,M5,M1,REST, M5,M6,M5,M3,M1,REST, M1,M3,M5,M1,REST,M1,M3,M5,M1,REST, M5,M6,M5,M3,M1,REST,0 }; // 拔萝卜 u16 code song9[] { M5,M6,H1,H2,H3,H2,H1,H6, M5,M6,H1,H2,H1,M6,M5,REST, M5,M6,H1,H2,H3,H2,H1,H6, M5,M6,H1,H2,M1,M6,M5,REST,0 }; // 世上只有妈妈好 完整版 u16 *code song_list[10] {song0,song1,song2,song3,song4,song5,song6,song7,song8,song9}; // 全局音乐索引 u8 play_song_idx 0; bit play_flag 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 }; // 红外按键匹配码表 0~9 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) { play_song_idx idx; play_flag 1; return smg_std_code[idx]; } } return 0x00; // 无匹配返回消隐 } /************************* 蜂鸣器驱动 *************************/ void beep_play(u16 freq, u16 time) { u16 i,t; u16 half 50000 / freq; if(freq REST) { delay_ms(time); return; } for(t0;ttime;t) { BEEP 0; for(i0;ihalf;i);{ BEEP 1; } for(i0;ihalf;i); } } /************************* 播放指定歌曲 *************************/ void music_scan(u8 song_idx,u8 dat[]) { u8 i 0; u16 note; u16 *p song_list[song_idx]; while(1) { note p[i]; if(note 0) break; beep_play(note, 150); delay_ms(20); i; smg_display(dat, 1); } } /************************* 主函数 循环显示红外按键 *************************/ void main(void) { // 8位完整缓存默认全部熄灭0x00 u8 disp_buf[8] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; u8 seg_val; BEEP 1; // 蜂鸣器关闭 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; // 清除标志等待下一次按键 } // 播放选中歌曲完整播放整首不中断 if(play_flag 1) { music_scan(play_song_idx,disp_buf); play_flag 0; BEEP 1; } // 持续扫描数码管 smg_display(disp_buf, 1); } }