[原创]基于51单片机的红外遥控课程设计
[注]:
一眨眼,大学接近尾声,具有找工作需要,所以把大学做的电子设计“劣作”放上来。希望考研失意,还能赶上“好工作”的春招班车。如果大伙有什么工作推荐也可以联系我哦,因为一年考研少接触了这方面,所以难免有些生疏。但请相信我!给我机会我会很认真学的!
邮箱:lydmom@163.com
转载请注明出处呀!
基于51单片机的红外遥控课程设计
目录
第一章 设计简介… 3
第二章 系统方案… 3
一、设计方案对比… 3
二、方案设计… 4
第三章 硬件设计… 5
一、红外遥控器… 5
二、红外接收模块部分… 7
第四章 软件设计… 8
一、红外遥控器软件设计… 8
二、红外接收模块软件设计… 11
三、程序代码… 11
第五章 测试及分析… 11
第六章 结论… 11
第七章 参考文献… 12
附录一(程序代码):… 13
第一章 设计简介
本设计分为红外遥控器与红外接收模块两部分。红外遥控器包括矩阵键盘、增强型51单片机(STC11L04E)、红外发射电路组成。单片机扫描矩阵键盘后,将按键状态进行信源编码与信道编码,载波(38k脉冲)后由红外发射器发射。红外接收模块部分由传统51单片机、数码管、一体化红外接收头组成。一体化红外接收头将信号进行限幅放大、带通滤波、解调、积分、整形后输出解调信号至单片机,并由单片机输出解调信号。
第二章 系统方案
一、设计方案对比
红外遥控器部分
2.1.1 主控芯片
方案一:HT6222
方案二:STC11L04E
分析 :传统红外遥控器芯片HT6222具有性价比高、功能强大、稳定可靠、使用简单等特点,但该芯片难以零购。STC11L04E为增强型51单片机,控制灵活(载波频率可调、通信协议可变更、用户码可变换)、价格较HT6222稍贵。STC11L04E最大的特别是低功耗,功作电压低3.3V,易于应用于移动设备。
结论 :由于STC11L04E单片机的灵活性以及学习性(可增强我们对一个完整通信系统的理解)。因此我们采用方案二。
2.1.2 矩阵键盘
方案一:3*6*2.5 贴片轻触开关
方案二:6*6*6 直插轻触开关
分析 :3*6*2.5贴片轻触开关虽然体积小巧、美观,但与6*6*6直插轻触开关对比,在制板布线上较繁锁。
结论 :综上,我们采用6*6*6直插轻触开关,使得整体布线简单,可布单面版,简化制板流程。
2.1.3电源模块
方案一:钮扣电池CR2032
方案二:可充电锂电池18650
分析 : 可充电锂电池18650容量大,节能环保(可多次利用),但体积大。钮扣电池CR2032价格低廉、替换容易、体积轻巧。
结论 :基于红外遥控器的便携性考虑,我们采用方案一。
2.1.4 红外发射管
方案一:3mm 红外发射管
方案二:5mm 红外发射管
分析 :方案一与方案二的区别在于直径越大发射管发射距离更远、信号稳定。
结论 :鉴于发射距离,我们采用5mm 红外发射管。
红外接收模块部分
2.1.5电源电路
方案一:线性电源AMS1117。AMS1117系列。
方案二:开关电源LM2576。
分析 :AMS1117系列含有可调(ADJ)与固定输出两种。AMS1117具有性价比高、体积小、外部电路简单、输出电流大(800mA)、最大输入电压达16V等特点。其固定输出AMS1117-5.0甚至可以在仅加一个SS14二极管的情况下稳定工作,但为了增强其稳定性,我们在其输出输入端各加一个10uF电解电容。LM2576系列开关,稳压集成电路是线性三端稳压器件的替代品,它具有可靠的工作性能,较高的工作效率,和较强的输出电流驱动能力,从而可为单片机的稳定可靠工作提供强有力的保证。
结论 :虽然LM2576性能极佳,但在本系统对于体积、外部电路、性价比的要求上进行衡量。我决定采用AMS1117-5.0作为供电系统。
二、方案设计
(图2.2.a红外遥控器部分)
(图2.2.b红外接收模块部分)
第三章 硬件设计
一、红外遥控器
单片机由CR2032钮扣电池供电。STC11L04E对矩阵键盘进行按键扫描,并将按键状态进行信源编码、信道编码,载波后由红外发射管向外发射信号。
(图3.1.a )
二、红外接收模块部分
单片机电源由AMS1117-5.0芯片供电。STC89C52将一体化红外接收器传来的信号进行解调,并输出显示至数码管。
(图3.1.a )
第四章 软件设计
一、红外遥控器软件设计
(图4.1.a 主函数)
(图4.1.b 发送一串数据)
(图4.1.c 定时器0中断)
(图4.1.d 发送一字节)
二、红外接收模块软件设计
(略)
三、程序代码
(见附录一)
第五章 测试及分析
测试量 |
参数 |
传输距离 |
|
误码率 |
|
第六章 结论
一、电子技术
- 增强型51单片机如STC11、12、15系列单片机的实际运行速度为传统51单片机的8~12倍。在将程序从传统51单片机移植至增强型51单片机时,时序上只需将延时常数乘以8~12倍,调试可得最佳延时常数。
- 按键扫描程序应添加延时函数以消除按键抖动。
- 常见红外遥控器使的协议有:ITT protocol、NEC protocol、Nokia NRC17 protocol、Sharp protocol等。
- 由于共射放大电路输出的波形与输入信号波形相反、一体化红外接收头输出信号波形与输入波形又相反,故由单片机调制后输出的波形信号应与红外接收头输出信号波形相同,即采用负脉冲载波。
- 不同延时函数的延时效果不一样,有些延时函数的延时时长与形参成正比,有些呈对数关系。
- 单片机时钟频率与晶振频率、谐振电容、晶振引脚长度有关。12M的晶振可选22~30pF的电容,30M的晶振可选30~33pF电容,24M的晶振可选20~22pF的电容。
- 画PCB的时候要选合适的封装。不应0603封装的电容误选1206的封装。
- 调试程序时序可以借助示波器、软件的Debug功能。
- 在这次合作设计中,加强了我们团队配合能力。
- 培养了我们胆大,心细,谨慎的工作作风。
- 养成了敢于发现问题,解决问题的习惯
- 在调试过程中,要多利用万用表、示波器等电子仪器。
二、心得体会
第七章 参考文献
[1] 《HT6122.pdf》 NEC著
[2] 《全面了解红外遥控》 San Bergmans著
[3] 《STC11L04E.pdf》 宏晶科技著
[4] 《例说51单片机(C语言版)(第3版)》 张义和著
[5] 《模拟电子技术基础(第四版)》 华成英.童诗白著
[6] 《Altium Designer原理图与PCB设计》 穆秀春著
[7] 《通信原理》 樊昌信著
[8] 《通信原理》 周烔槃著
附录一(程序代码):
红外遥控器程序
/*———————-Item Description———————————– – Project Name : IR_Remote/基于单片机的红外遥控课程设计 – Files : – Description : 本设计基于单片机的红外遥控,具有稳定可靠、指令、 地址可自定义、控制距离远等特点。 – IDE : Keil uVision4 – Author : Mason 别名:小菜 – Email Address : 1609099954@qq.com – Create Date : 2013/6/7 – Performance : Finished – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ /*—————————-Head—————————————*/ #include <reg52.H> #include “keyboard3_3.H” #include “IR_Tran.H” /*—————————-Grobal Variable—————————-*/ char cmd=0,lastcmd=0,ctemp; /*—————————-Code—————————————*/ void main() { IRtimer_Init(); while(1) { ctemp = scankeyboard3_3(); if(ctemp!=NULL) cmd = ctemp;
if(cmd != lastcmd){ IR_send(cmd); lastcmd = cmd; } } } |
/*—-Head Description—- – File Name : IR_Tran.H – Author : Mason 别名:小菜 – Create Date : 2013/6/7 – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ #ifndef _IR_TRAN_H_ #define _IR_TRAN_H_
#include “MICRO.H”
void IRtimer_Init(void); // 定时器初使化 void IR_Pulse(void); // 频率为精准38k方波(截波) void IR_send(char cmd); // 发送指令
#endif |
/*—-File Description—- – File Name : IR_Tran.c – Functions : void IRtimer_Init(void);void IR_Pulse(void); void timer0() interrupt 1 void IR_send(char cmd); – Description : 红外遥控的驱动程序,调节IR_Pulse函数中的dt可将 程序从传统51单片机移殖至增强型(1T)51单片机。 更改iraddr的值可以改变遥控器的地址。 本设计的晶振采用12M,但实际中只有11.89M,因此为了 使遥控器反应更准确,需根据实际振荡频率调节 void IR_Pulse(void)的延时环节,最终使用频率计测试. – Author : Mason 别名:小菜 – Create Date : 2013/6/7 – Performance : Finished – Global Variable : None – File static Variable : None – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ /*—————————-Head—————————————*/ #include <reg52.H> #include “MICRO.H” #include “intrins.H” /*—————————-Micro————————————–*/ // 由于晶振有误差,以下测量值是用示波器调试出来的,晶振此时频率11.89M #define TH0_0P ((65536-544)/256) // 560us #define TL0_0P ((65535-544)%256) #define TH0_0 ((65536-515)/256) // 560us #define TL0_0 ((65536-515)%256) #define TH0_1 ((65536-1650)/256) // 1690us #define TL0_1 ((65535-1650)%256)
sbit IR_OP = P3^7; /*—————————-Grobal Variable—————————-*/ bit timer_f = 1; // 定时器计时状态位 char const iraddr = 0xff; // 遥控器本机地址 char temp; // 程序引用的临时变量 /*—————————-Code—————————————*/ void IRtimer_Init(void) // 定时器初使化 { TMOD = 0x01; // 16 bit timer EA = 1; ET0 = 1; }
void IR_Pulse(void) // 频率为精准38k方波(截波) { // 需根据实际原器件而定。 unsigned char dt ; // 本设计实际晶振频率为11.89M IR_OP = 0; // 增强型单片机请将延时环节的 for(dt = 71;dt>0;dt–); // 延时系数”dt = 7″改为”dt = _nop_(); // 71″ IR_OP = 1; // 由于发射管采用共射放大电路, } // 故载波为下降沿脉冲。
void timer0() interrupt 1 // 定时器中断 { timer_f = 0; } void IR_Send_Byte(char ca) // cmd or addr { for(temp = 0x01;temp != 0x00;temp <<= 1) { TR0 = 0; TH0 = TH0_0P; // 560us高电平 TL0 = TL0_0P; timer_f = 1; TR0 = 1; while(timer_f) IR_Pulse();
if((temp&ca) == 0){ TH0 = TH0_0; // 560us低电平 TL0 = TL0_0; }else{ TH0 = TH0_1; // 1690us低电平 TL0 = TL0_1; } timer_f = 1; while(timer_f); } }
void IR_send(char cmd) // 发送指令 { TH0 = (65536-9000)/256; // 9ms前导高电平 TL0 = (65535-9000)%256; TR0 = 1; timer_f = 1; while(timer_f) IR_Pulse(); // 载波 TH0 = (65536-4500)/256; // 4.5ms前导低电平 TL0 = (65535-4500)%256; timer_f = 1; while(timer_f); // 延时
// 发送地址原码 IR_Send_Byte(iraddr);
// 发送地址反码 IR_Send_Byte(~iraddr);
// 发送操作原码 IR_Send_Byte(cmd);
// 发送操作反码 IR_Send_Byte(~cmd);
TR0 = 0; // 560us后导脉冲序列 TH0 = TH0_0P; TL0 = TL0_0P; timer_f = 1; TR0 = 1; while(timer_f) IR_Pulse();
TR0 = 0; } |
/*—-Head Description—- – File Name : keyboard3_4.h – Author : Mason 别名:小菜 – Create Date : 2013/6/7 – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ #ifndef __KEYBOARD3_3_H__ #define __KEYBOARD3_3_H__
/*********************************************************** *scankeyboard3*4:return 0_12 by every touch, else return 16* ***********************************************************/
#define NULL -1 extern char scankeyboard3_3(void);
#endif |
/*—-File Description—- – File Name : keyboard3_3.c – Functions : – Description : None
– Author : Mason 别名:小菜 – Create Date : 2013/6/7 – Performance : Finished – Global Variable : None – File static Variable : None – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ /*—————————-Head—————————————*/ #include “keyboard3_3.h” #include <keyboard3_3.h> #include <reg52.h>
/*—————————-Micro————————————–*/ /********************************************************* *keyboard3*3:return 0-12 by every touch, else return null* *********************************************************/ #define KEYB P1 char scannum[3]={0xfe,0xfd,0xfb};
/*—————————-Code—————————————*/ /*Oscillator frequence choose 11.0592MHz ,the debouncert is 600 Oscillator frequence choose 12MHz,the debouncert is 700*/ void debouncer() { unsigned int debouncert; for(debouncert=328;debouncert>0;debouncert–); } char scankeyboard3_3(void) { char column,row; for(row = 0;row < 3;row++) { KEYB = scannum[row]; debouncer(); column = (~KEYB)&0x0f; if(column != 0){ switch(column) { case 0x20:{column = 0; break;} case 0x40:{column = 1; break;} case 0x80:{column = 2; break;} } while((~KEYB&0x0e)!=0); // 去除长按 debouncer(); return (row*3+column); } } return NULL; } |
/*—-Head Description—- – File Name : MICRO_H – Author : Mason 别名:小菜 – Create Date : 2013/3/5 – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/
#ifndef _MICRO_H_ #define _MICRO_H_
//#include <STC12C5A.H> #include <reg52.H>
//MICRO typedef unsigned int uint16; typedef int WORD; typedef long int DWORD; typedef unsigned char uchar; typedef char BYTE;
// ADC 启动转换 #define EN_ADC0 0xf8 // 选择 P1.n ADC引脚,并使能 ADC_START. #define EN_ADC1 0xf9 #define EN_ADC2 0xfa #define EN_ADC5 0xfd #define EN_ADC6 0xfe #define EN_ADC7 0xff
#endif |
红外接收模块程序
/*———————-Item Description———————————– – Project Name : IR_Receiver – Files : – Description : None
– IDE : Keil uVision4 – Author : Mason 别名:小菜 – Email Address : 1609099954@qq.com – Create Date : 2013/6/10 – Performance : Finished – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ /*—————————-Head—————————————*/ #include <reg52.H> #include “NixieTube.H” #include “MICRO.H” #include “IR.H” /*—————————-Grobal Variable—————————-*/ extern uchar IR_value[6];
/*—————————-Code—————————————*/ void main() { IR_init();
while(1); } |
/*—-Head Description—- – File Name : IR.H – Author : Mason 别名:小菜 – Create Date : 2013/4/22 – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ /* 对应按键编码 – 45 46 47 – 44 40 43 – 07 15 09 – 16 19 0D – 0C 18 5E – 08 1C 5A – 42 52 4A ————-*/
#ifndef _IR_H_ #define _IR_H_
#define uchar unsigned char #define uint unsigned int
sbit IRIN = P3^2; // 红外传感器引脚
void IR_init(void); void IR_Delay(uchar t1); // 0.15ms
#endif |
/*—-File Description—- – File Name : IR.c (infrared remoted control) – Functions : 该文件用于处理红外传感器信号。适用于传统51单片机 增强型51单片机需适当调速延时函数。晶振频率为12M。 占用外部中断0;不需定时器中断。只需调用IR_init(void); 便可从全局变量IR_value[4]/IR_value[5]分别读取红外用 户码(0x00)与操作码。 – Description : 对应按键编码: – 45 46 47 – 44 40 43 – 07 15 09 – 16 19 0D – 0C 18 5E – 08 1C 5A – 42 52 4A – Author : Mason 别名:小菜 – Create Date : 2013/4/22 – Performance : Finished – Global Variable : uchar IR_value[6]; – File static Variable : None – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ #include <reg52.H> #include “NixieTube.H” #include “IR.H”
uchar IR_value[6]; uint t = 0;
void IR_init(void) { IE |= 0x81; // EA = 1;EX0 =1;ET0=1; TCON |= 0x01; // IT0 = 1;下降沿触发 IRIN = 1; // 将引脚拉高 }
/*—-Function Description—- – Function Name : void IR_Delay(uchar t1) – Description : 线性延时子函数 延时 t1*0.15ms – Return Code : None – Parameters/Arguments : None – Global Variable : None – static Variable : None ————————————————————————-*/ void IR_Delay(uchar t1) // t1*0.15ms { uchar t2; while(t1–) for(t2=0;t2<13;t2++); }
/*—-Function Description—- – Function Name : void IR_Get(void) – Description : 外部中断读到红外前导信号后调用。将4个字节的用 户码与操作码放于IR_value[0:3]中。 – Return Code : IR_value[0:3] – Parameters/Arguments : None – Global Variable : IR_value[0:3] – static Variable : None ————————————————————————-*/ void IR_Get(void) { uchar i,j,k=0; IR_Delay(5); // 稍做延时,去除干扰,增强型单片机将5改为10 if(IRIN == 1) return; // 检测低电平是否有效 while(!IRIN); // 去除9ms前导低电平 while(IRIN) ; // 去除4.5ms前导高电平 for(i=0;i<4;i++) // 4个字节数据 { for(j=0;j<8;j++) // 8个位 { //while(IRIN) IR_Delay(1); while(!IRIN); // 去除560us while(IRIN) // 软件计时 { IR_Delay(1);// 将 1 改为 9 可移殖至12M 1T 单片机 k++; // 如STC 12C5A60S2 if(k>=30) {k=0; return;} // 时间过长自动返回 } IR_value[i] = IR_value[i] >> 1; if(k>=8) // k值可以有误差,但 k*软件计时(ms)>=0.56ms IR_value[i] = IR_value[i] | 0x80; k=0; // 清零 } } }
/*—-Function Description—- – Function Name : 外部中断0 服务子程序 – Description : 用于检测红外前导电平信号,调用IR_Get(); 验证数据有效性,并将最终用户码与操作码分别存放于 IR_value[4:5]中。 – Return Code : IR_value[4:5] – Parameters/Arguments : None – Global Variable : IR_value[4:5] – static Variable : None ————————————————————————-*/ void IR_ISR(void) interrupt 0 { EX0 = 0; // 关闭 外部中断0 IR_value[0] = IR_value[1] = IR_value[2] = IR_value[3] = 0 ; IR_Get(); // 读IR if(IR_value[0]==~IR_value[1] && IR_value[2]==~IR_value[3]){ IR_value[5] = IR_value[2]; // 保存指令 IR_value[4] = IR_value[0]; // 有效性验证,保存用户码 } Dis_Tube(IR_value[5]%16);
IE0 = 0; // 清空中断标志,防止在数据处理过程中产生中断请求 EX0 = 1; // 打开 外部中断0,准备接收下一条指令 } |
/*—-Head Description—- – File Name : NixieTube.H – Author : Mason 别名:小菜 – Create Date : 2013/4/19 – ——————————————- – Revision History – No. Date Revised by Item Description – ————————————————————————-*/ #ifndef _NIXIETUBE_H_ #define _NIXIETUBE_H_
#include “MICRO.H” void Dis_Tube(uchar dat);
#endif |
/*—-File Description—- – File Name : Nixietube.c – Functions : 数码管驱动程序 – Description : None
– Author : Mason 别名:小菜 – Create Date : 2013/4/19 – Performance : Finished – Global Variable : smg_table[18] – File static Variable : None – ——————————————- – Revision History – No. Date Revised by Item Description – 1 6/11 mason none add ————————————————————————-*/ /*—————————-Head—————————————*/ #include <reg52.h> #include “NixieTube.H” #include “MICRO.H” /*——————————Code Variable—————————-*/ //共阴 char code smg_table[16]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x19, 0x11,0xc1,0xe5,0x85,0x61,0x71}; /*—————————-Code—————————————*/
void Dis_Tube(uchar dat) { P2 = smg_table[dat]; } |