万能红外遥控解码模块【精选】
- 格式:doc
- 大小:238.00 KB
- 文档页数:55
龙源期刊网
通用红外遥控解码器的设计
作者:余东峰刘强刘虎生孙兆林
来源:《现代电子技术》2011年第16期
摘要:在此设计了一款通用红外遥控解码器,能够对大部分红外遥控器发出的红外信号进行解码、压缩、识别和存储。
设计中利用了矢量量化和聚类的方法,大大提高了红外遥控信号的解码效率。
对重复模式的识别进一步减轻了系统的存储压力。
该设计很好地解决了消费电子中红外遥控器不通用的问题,已经成功运用于2套样机的开发中,具有广阔的运用前景。
关键词:红外遥控解码;聚类;重复模式识别;效率
中图分类号:TN919-34 文献标识码:A 文章编号:1004-373X(2011)16-0158-03。
利用A VR(M8)的输入捕获(ICP)对万能红外线遥控器进行解码本实例程序为自创,若转载请注明出处,谢谢!小弟不久前买了一个科朗公司出版的万能电视遥控器RM-2008,用作对设备的红外遥控,折腾了几天,今天终于弄清楚了如何对该遥控器进行解码,很开心,所以把成果与各位大虾分享,有什么错误的地方请指正。
万能遥控器在使用前一般要进行设置,针对RM-2008这款万能遥控,设置方法如下:先按住“设置”键不放,再按下“电源”(“开/关”)键,工作指示灯亮起,然后释放两键,在此时进入代码输入状态,依次键入0 0 0 指示灯熄灭,设置成功!说明一下:0 0 0 编码是日立公司初期的红外编码方式,也就是网上到处都通用的红外编码方式(如下图),另外本程序只能对此编码进行解码数据头的时间:Th=9+4.5=13.5ms数据“0”的时间:T0=0.565+0.56=1.125ms数据“1”的时间:T1=1.685+0.56=2.245ms本程序通过使用输入捕获功能(ICP)捕捉红外信号的高电平脉宽,达到解码的目的;如果捕获到的脉宽是4.5ms 则表示此信号为同步码,如果捕获到的脉宽是1.685ms 的话则表示“1”否则表示“0”测试电路如下:使用DNW 串口调试软件时的效果/////////////////////////////////只有一个文件main.c/////////////////////////////////// #include <avr/io.h>#include <avr/signal.h>#include <avr/interrupt.h>#include <avr/wdt.h>#include <util/delay.h>#include <stdio.h>/*----------------------遥控操作值--------------------*/// key code (hex)#define Key_1 0x01#define Key_2 0x02#define Key_3 0x03#define Key_4 0x04#define Key_5 0x05#define Key_6 0x06#define Key_7 0x07#define Key_8 0x08#define Key_9 0x09#define Key_0 0x00#define Menu 0x5c // 菜单#define Menu_up 0x56 // 菜单上#define Menu_down 0x57 // 菜单下#define Menu_left 0x5f // 菜单左#define Menu_right 0x5b // 菜单右#define Menu_ok 0x16 // 菜单确认#define Channel_up 0x1b // 频道+ #define Channel_down 0x1f // 频道- #define Sound_up 0x1e // 音量+ #define Sound_down 0x1a // 音量- #define Open_Close 0x12 // 开/关#define Mute 0x10 // 静音#define Pic_in_pic 0x51 //画中画#define Standard 0x58 // 制式#define Return 0x52 // 返回#define Times 0x0b // 倍数#define Screen 0x16 // 屏幕#define Audio 0x1d // 伴音#define NICAM 0x13 // 丽音#define TV_Vedio 0x0f // 电视/视频#define Sleep 0x0e //睡眠/*----------------------常用参数定义-------------------*/ #define P0 0#define P1 1#define P2 2#define P3 3#define P4 4#define P5 5#define P6 6#define P7 7#define FREQ 8 //定义单片机工作频率为8M#define uint unsigned int#define uchar unsigned char#define Start_T1 TCCR1B|=_BV(CS11);TCNT1=0//复位预计分频器并开启定时器T1#define Stop_T1 TCCR1B&=~_BV(CS11) //关闭定时器T1/*-----------------IR信号指示灯操作函数---------*/#define EN_IR_LED DDRB|=_BV(P1)#define CLR_IR_LED PORTB&=~_BV(P1)#define SET_IR_LED PORTB|=_BV(P1)/*----------------------某些端口操作-------------------*/volatile unsigned char i,j,k;volatile unsigned long IRcode; //定义一个长度为4字节的无符号long 类型变量来存储代码volatile unsigned char *IRcodePointer ; //定义一个无符号的单字节指针变量,//用此地址变量来分别读取IRCode的//4个字节其中操作码为IRcodePointer[2]//用户码为IRcodePointer[0]volatile unsigned char IRReceiveEffective=0; //IR信号接收有效当程序响应接收以后请马上清零这样才会继续接收下一IR码volatile unsigned char IRReceiveCurrentBit=0; //IR信号当前接收位0时表示第0位即同步码(4.5ms高电平)volatile unsigned int Pulse_length=0; //捕获的脉冲宽度volatile unsigned char ICP_Parity=0; //捕获中断奇偶次计数1时为偶次并在此时判断脉宽volatile unsigned char Received_Key_Temp; //红外接收操作键缓存const unsigned char String[]={"You Have Press Key : "};/*----------------------串口定义-------------------*/unsigned char SetPrintfConvertMode=0; //使用printf作其他转换,并非输出到UARTvoid Uart_Init(void);int System_putchar(char c, FILE *stream);int System_getchar(FILE *stream);FILE mystd = FDEV_SETUP_STREAM(System_putchar,System_getchar,_FDEV_SETUP_RW);/*----------------------常用函数定义------------------*/void delay_nms(unsigned int ms) //N ms延时函数{for(i=0;i<ms;i++)_delay_loop_2(FREQ*250);}/*----------------------系统初始化函数定义------------------*/void IO_INIT(void){PORTB|=_BV(P0); //设置ICP引脚内部上拉经过试验验证,上拉会提高红外接收灵敏度}ISR(TIMER1_COMPA_vect){IRReceiveCurrentBit=0;//重置IR接收位为第0位,为下次接收做准备TIMSK&=~_BV(OCIE1A); //关闭溢出中断TCCR1B|=_BV(ICES1); //设置输入捕获上升沿有效ICP_Parity=0;Stop_T1;CLR_IR_LED;}ISR(TIMER1_CAPT_vect){if(!IRReceiveEffective){if(ICP_Parity==0){ICP_Parity++;TIMSK|=_BV(OCIE1A);TCCR1B&=~_BV(ICES1); //设置输入捕获下降沿有效Start_T1 ;}else{Stop_T1;ICP_Parity=0;TCCR1B|=_BV(ICES1);//设置输入捕获上升沿有效Pulse_length=ICR1;if(IRReceiveCurrentBit==0){if(Pulse_length>=3500&&Pulse_length<5500)// 如果是引导码(4.5ms) 进入下一个bit的读取IRReceiveCurrentBit++;}else if(IRReceiveCurrentBit<33) //接收32位数据{IRcode>>=1;if(Pulse_length<1900&&Pulse_length>1400) //判断是否为1 ( 1.685 ms) IRcode|=0x80000000;IRReceiveCurrentBit++;if(IRReceiveCurrentBit==33){IRReceiveCurrentBit=0; //重置IR接收位为第0位,为下次接收做准备if(IRcodePointer[0]==(unsignedchar)(~IRcodePointer[1])&&IRcodePointer[2]==(unsignedchar)(~IRcodePointer[3])){SET_IR_LED; //开启IR信号指示灯IRReceiveEffective=1; //数据有效}delay_nms(5); //因为32位数据后面还有一个信号上跳变,所以要适当延时,延时0.65ms以上即可}}}}}/////////////////////////////////////////////////////////////////int main(void){wdt_disable();IO_INIT();Uart_Init();TCCR1B=_BV(WGM12)|_BV(CS11);//采用8分频这样的话TCNT1的计数时基为1usOCR1A=8000; //TCNT1 计数上限设置IR接收超时这里设置8msTIMSK|=_BV(TICIE1);//开启输入捕获中断TCCR1B|=_BV(ICES1);//输入捕获上升沿有效EN_IR_LED; //IR信号指示灯允许CLR_IR_LED; //关闭IR信号指示灯IRcodePointer=&IRcode;sei();while(1){if(IRReceiveEffective){Received_Key_Temp=IRcodePointer[2];//把接收到的操作键放入缓存IRReceiveEffective=0; //允许下一次接收switch(Received_Key_Temp){case Key_1 : printf("\n%sKey_1",String);break;case Key_2 : printf("\n%sKey_2",String);break;case Key_3 : printf("\n%sKey_3",String);break;case Key_4 : printf("\n%sKey_4",String);break;case Key_5 : printf("\n%sKey_5",String);break;case Key_6 : printf("\n%sKey_6",String);break;case Key_7 : printf("\n%sKey_7",String);break;case Key_8 : printf("\n%sKey_8",String);break;case Key_9 : printf("\n%sKey_9",String);break;case Key_0 : printf("\n%sKey_0",String);break;case Menu : printf("\n%sMenu",String);break;case Menu_up : printf("\n%sMenu_up",String);break;case Menu_down : printf("\n%sMenu_down",String);break;case Menu_left : printf("\n%sMenu_left",String);break;case Menu_right : printf("\n%sMenu_right",String);break;case Menu_ok : printf("\n%sMenu_ok",String);break;case Channel_up : printf("\n%sChannel+",String);break;case Channel_down : printf("\n%sChannel-",String);break;case Sound_up : printf("\n%sSound+",String);break;case Sound_down : printf("\n%sSound-",String);break;case Open_Close : printf("\n%sOpen_Close",String);break;case Mute : printf("\n%sMute",String);break;case Standard : printf("\n%sStandard",String);break;case Return : printf("\n%sReturn",String);break;case Times : printf("\n%sTimes",String);break;//case Screen : printf("\n%sScreen",String);break;//Screen 与menu_ok 值相同case Audio : printf("\n%sAudio",String);break;case NICAM : printf("\n%sNICAM" ,String);break;case TV_Vedio : printf("\n%sTV_Vedio",String);break;case Sleep : printf("\n%sSleep",String);break;case Pic_in_pic : printf("\n%sPic_in_pic",String);break;default:printf("\n%sOther Key 0x%x",String,Received_Key_Temp);break;}CLR_IR_LED; //处理完数据以后关闭IR信号指示灯}}}/*----------------------串口函数实体------------------*/void Uart_Init(void){UCSRB=_BV(RXEN)|_BV(TXEN);UBRRL=25; //8M 19200stdout=&mystd;stdin=&mystd;}int System_putchar(char c, FILE *stream){if(SetPrintfConvertMode==1){}else{if (c == '\n')System_putchar('\r', stream);loop_until_bit_is_set(UCSRA, UDRE);UDR = c;}return 0;}int System_getchar( FILE *stream){loop_until_bit_is_set(UCSRA,RXC);return UDR;}/////////////////////////////////程序结束////////////////////////////。
红外遥控解码程序设计——————基于uPD6121红外编码制式红外传感系统是目前应用最为广泛的遥控系统,一个红外遥控系统可分为发射和接收两部分组成,发射端称之为红外遥控器,一般由矩阵键盘,红外编码调制芯片和红外发射管组成;接收端用一体化红外接收头即可,这个东东内置光电放大器和解调部分,信号接收之后一般很微弱须放大后才可解码,为有效发射出去得先托付在载波上所以需经历调制、解调的过程,其实对于发射部分主要工作在于编码,而对于编码方式只有几种主流方式,而目前国内大部分均为uPD6121编码方式(日本NEC公司搞出来的。
),所以我们只须弄清楚这种编码的时序,即可写出万能的红外解码程序,只要是基于这种编码方式的遥控器(家里的电视、空调、电扇遥控器)都可以用该程序来解码(这点也充分证明了C语言的高移植性啊。
)这种编码的格式其实很简单,开头是一个引导码,人家芯片在编码时将其设计成9ms的高电平和4.5ms的低电平,也就是说你必须跳过这段引导码之后才会接收到数据,第一个问题来了:为什么要加这段引导码?因为红外传感是非常容易受到干扰的,如果直接传送数据很可能并非发送端的信号,很可能来自其他辐射,后面设计程序时会遇到这个问题。
所以我们在写程序时在引导码时可以加入检测代码,如果是引导码则继续接收,否则跳出。
第二个问题就是:接收数据时我们用外部中断接收,这是考虑到CPU 的执行效率,如果你在主函数里接收数据,就好比CPU一直在问:你接收到数据没?你接收到没?..很明显不靠谱,和串口通信一样,接收数据用中断这是经验,有利于单片机的执行效率。
第三个要注意的就是红外接收端和编码发送的数据是反向的!这点很重要,我看很多资料没有写明这点,让很多童鞋疑惑不解,也就是说引导码编码时确实是9ms高电平和4.5ms 的低电平,但是到了接收端是9ms的低电平和4.5ms的高电平,所以我们在解码时就得注意引导码高电平出现的顺序。
对于编码格式,引导码后接了4个字节的数据,前两个字节为用户码和用户反码,简单点说就是器件地址;后两字节为操作码和操作反码,就是我们真正需要的数据。
单片机STM32F103C8T6的红外遥控器解码系统设计一、本文概述本文旨在详细阐述基于STM32F103C8T6单片机的红外遥控器解码系统的设计和实现过程。
随着科技的不断进步和智能化设备的普及,红外遥控器作为一种常见的遥控设备,已经广泛应用于家电、安防、玩具等多个领域。
然而,红外遥控器发出的红外信号往往需要通过解码器才能被设备正确识别和执行,因此,设计一款高效、稳定、可靠的红外遥控器解码系统具有重要意义。
本文将首先介绍红外遥控器的基本原理和信号特点,然后详细阐述STM32F103C8T6单片机的性能特点和在红外遥控器解码系统中的应用优势。
接着,将详细介绍红外遥控器解码系统的硬件设计,包括红外接收头的选择、电路设计和PCB制作等。
在软件设计部分,将详细阐述如何通过STM32F103C8T6单片机的编程实现红外信号的接收、解码和处理,以及如何将解码后的数据通过串口或其他通信方式发送给主控制器。
本文还将对红外遥控器解码系统的性能进行测试和分析,包括信号接收距离、解码速度和稳定性等方面的测试。
将总结本文的主要工作和创新点,并对未来的研究方向进行展望。
通过本文的研究和实现,旨在为红外遥控器解码系统的设计提供一种新的思路和方法,同时也为相关领域的研究人员提供有益的参考和借鉴。
二、红外遥控器基础知识红外遥控器是一种常见的无线遥控设备,它利用红外光作为信息载体,通过发射和接收红外光信号实现对设备的远程控制。
这种遥控方式因其简单、低成本和无需视线连接等优点,在各类消费电子产品中得到了广泛应用,如电视机、空调、音响等。
红外遥控器的工作原理主要基于红外辐射和光电器件的检测。
遥控器内部通常包含一个或多个红外发射管,当按下按键时,发射管会发射出特定频率和编码的红外光信号。
接收端则配备有红外接收头,该接收头内部有一个光敏元件(如硅光敏三极管或光敏二极管),用于检测红外光信号并将其转换为电信号。
为了区分不同的按键操作,红外遥控器通常采用特定的编码方式对按键信号进行编码。
红外遥控器软件解码及其应用随着现代科技的不断发展,红外遥控器已经成为人们日常生活中的必备工具之一。
不过,很多人并不了解红外遥控器的工作原理以及它是如何通过软件解码来实现遥控效果的。
本文将详细介绍红外遥控器软件解码的相关知识,以及其在实际应用中的作用。
一、红外遥控器的工作原理首先,我们需要了解红外遥控器的工作原理。
简单来说,红外遥控器是一种利用红外线光谱来传输指令的设备,通过在发射端发送编码的红外信号,再在接收端解码后执行相应的指令。
通常,红外遥控器由发射部分与接收部分两个部分组成。
发射部分由红外LED发射器构成,它会通过红外发射现象来发送编码的红外信号。
在接收端,红外接收器则会接收到这些信号,并将其转换成电信号进行解码。
之后,解码器会解析出信号的编码含义,然后执行相应的指令。
这就是红外遥控器的基本工作原理。
二、红外遥控器软件解码的实现在红外遥控器的工作中,软件解码起到了重要的作用。
所谓软件解码,就是在终端设备中运行的一种程序,能够将遥控器发射的红外编码转换成可读的指令。
而这些指令就可以用于控制各种家电、设备等。
软件解码的实现主要有两种方式。
第一种是使用硬件解码器,这需要在终端设备上安装一个专门的硬件解码器,用于解析红外信号,并输出相应的指令。
第二种方法则是使用软件解码器,这需要在终端设备上安装一个软件程序,用于解析红外信号并输出指令。
在软件解码的实现中,最常见的是使用赛贝尔红外编解码库。
这个库已经成为了广泛使用的一种红外编解码方案。
它可以用于各种嵌入式设备、物联网设备、手机、电视机顶盒等多种应用场景中。
三、红外遥控器软件解码的应用目前,红外遥控器软件解码已广泛应用于各种智能家居、物联网设备、工控设备等领域。
下面列举一些具体的应用案例:1、智能家居:通过使用红外遥控器软件解码,可以实现对家中的各种电器、设备的遥控控制。
如电视、空调、照明设备等。
2、物联网设备:红外遥控器软件解码还可以用于物联网设备中,如智能家居中的智能门锁、智能家电等。
红外遥控模块原理
红外遥控模块原理
红外遥控模块是一种常见的电子元件,它可以将电信号转换为红外信号,从而实现对电器的遥控操作。
红外遥控模块的原理是基于红外线的传输和接收。
红外线是一种电磁波,其波长在可见光波之下,无法被肉眼直接观察到。
红外线的频率范围在300GHz至400THz之间,其波长在
0.75μm至1000μm之间。
红外线可以穿透一些物体,但不能穿透金属和水。
红外遥控模块的发送端包括一个红外发射二极管和一个驱动电路。
当驱动电路接收到控制信号时,会将信号转换为电流,然后通过红外发射二极管将电流转换为红外信号,从而实现对电器的遥控操作。
红外遥控模块的接收端包括一个红外接收二极管和一个解码电路。
当红外信号被发送端发出后,会被红外接收二极管接收,并将其转换为电信号。
然后,解码电路会将电信号解码为控制信号,从而实现对电器的遥控操作。
红外遥控模块的优点是操作简单、成本低廉、可靠性高、适用范围广。
它广泛应用于电视、空调、音响等家电产品中,为人们的生活带来了
极大的便利。
总之,红外遥控模块是一种基于红外线传输和接收的电子元件,其原
理是将电信号转换为红外信号,从而实现对电器的遥控操作。
它的优
点是操作简单、成本低廉、可靠性高、适用范围广,是现代家电产品
中不可或缺的一部分。
RC5红外遥控解码程序 A VR单片机main.c,/************************************************************ * Program: AVRGCC - RC5 Test* Comments: RC5 decoder* target mcu: 8515* WEB: ************************************************************/ #include <avr/io.h>#include <interrupt.h>#include <avr/signal.h>#include "lcd.h"unsigned int heartbeat=0;// RC5 variables & definitions#define PRSC1_SELECT 2 // timer CLK/8#define TRUE 1#define FALSE 0#define IRDet bit_is_set(PIND,PD2)volatile unsigned char RC5RxAddress, RC5RxCommand;volatile unsigned char RC5Avail=0, RC5Repeat, RC5PhaseErr;void delay(unsigned int p){unsigned int i;unsigned char j;for(i=0;i<p;i++)for (j=0;j<100;j++);}/* signal handler for timer1 overflow interrupt */SIGNAL(SIG_OVERFLOW1){static unsigned char RC5BitCnt=0;static unsigned int RC5Data;static unsigned char OldValue;static unsigned char ControlBit;// Load Timer again...outp(0xFC, TCNT1H); // set TCNT1 // 889usoutp(0x87, TCNT1L); // set TCNT1if (RC5BitCnt==0) {RC5Data=0;OldValue=IRDet;RC5PhaseErr=FALSE;}if (RC5BitCnt<24) { // sample 24 bitsif (RC5BitCnt & 0x01) {if (OldValue!=IRDet) { // check for Biphase errorRC5Data <<= 1; // next bit;if (IRDet) RC5Data &= 0xFFFE; else RC5Data |= 0x0001;} else RC5PhaseErr=TRUE; // biphase error}RC5BitCnt++;OldValue=IRDet; // remember signal level} else { // if >24 then finishoutp(0 , TCCR1B); // stop timer 1RC5BitCnt=0; // prepare for next timeif (!RC5PhaseErr && !RC5Avail) {RC5Repeat=ControlBit==((RC5Data & 0x0800)==0x0800); // if new controlbit=old then RC5Repeat=1 ControlBit=((RC5Data & 0x0800)==0x0800); // new controlbitRC5RxAddress=(unsigned char)((RC5Data & 0x07C0)>>6);RC5RxCommand=(unsigned char)(RC5Data & 0x003F);RC5Avail=TRUE; // RC5 code is vailable...}RC5PhaseErr=FALSE;outp(0x40, GIMSK);}}/* signal handler for external interrupt int0 */SIGNAL(SIG_INTERRUPT0){outp(0x00, GIMSK); // disable external int0outp(0xF3, TCNT1H); // set TCNT1 // 3111 usoutp(0xD9, TCNT1L); // set TCNT1outp(PRSC1_SELECT, TCCR1B); // start timer1}/* initialize RC5 decoder */void RC5_init(void){cbi(DDRD,PD2);sbi(PORTD,PD2);outp((1<<ISC01), MCUCR); // raise int0 on falling edgeoutp(0x40, GIMSK); // enable external int0outp(0x80, TIMSK); // enable timer1 Overflow interruptsoutp(0x00, TCCR1A); // disable PWM and stuffoutp(0x00, TCCR1B);outp(0xF3, TCNT1H); // set TCNT1 // 3111 usoutp(0xD9, TCNT1L); // set TCNT1}/* main routine for testing */int main(void){sei(); // enable interruptsRC5_init();lcd_init();lcd_control(1,0,0);lcd_putstr("RC5 decoder");lcd_goto(0x49);lcd_putstr("PErr=");while(1){lcd_goto(0x0E);printhex(heartbeat++); // heart beat :)if (RC5Avail) { // display new RC5 datalcd_goto(0x40);printhex(RC5Repeat);lcd_putch(' ');printhex(RC5RxAddress);lcd_putch(' ');printhex(RC5RxCommand);RC5Avail=FALSE; // ready to get new one}lcd_goto(0x4E);printhex(RC5PhaseErr); // error checkdelay(1000);}}lcd.c/*********************************************************** * Program: LCD driver* Created: 28.8.99 21:32* Comments: HITACHI LCD driver (4bit mode) & print stuff* target mcu: 8515* WEB: ************************************************************/ #include "lcd.h"void lcd_delay(unsigned int p){unsigned int i;byte j;for(i=0;i<p;i++)for (j=0;j<10;j++);}void toggle_E(){outp(inp(PORTA) | 0x20,PORTA); // E=1outp(inp(PORTA) & 0xDF,PORTA); // E=0}/*-----------------27.5.99 20:30--------------------* Display initialization*--------------------------------------------------*/void lcd_init(void){outp(0xFF,DDRA);lcd_delay(10000);outp(0x03,PORTA); toggle_E(); lcd_delay(500);outp(0x03,PORTA); toggle_E(); lcd_delay(100);outp(0x03,PORTA); toggle_E(); lcd_delay(100);outp(0x02,PORTA); toggle_E(); lcd_delay(100);outp(0x02,PORTA); toggle_E();outp(0x08,PORTA); toggle_E(); lcd_delay(100);outp(0x00,PORTA); toggle_E();outp(0x0F,PORTA); toggle_E(); lcd_delay(100);outp(0x00,PORTA); toggle_E();outp(0x06,PORTA); toggle_E(); lcd_delay(100);lcd_cls();}/*-----------------27.5.99 20:33--------------------* Clear display*--------------------------------------------------*/void lcd_cls(){outp(0x00,PORTA); toggle_E();outp(0x01,PORTA); toggle_E();lcd_delay(1000);}/*-----------------27.5.99 20:33--------------------* Home position*--------------------------------------------------*/void lcd_home(){outp(0x00,PORTA); toggle_E();outp(0x02,PORTA); toggle_E();lcd_delay(1000);}/*-----------------27.5.99 20:33--------------------* LCD & Cursor control (Blinking, ON/OFF,...)*--------------------------------------------------*/void lcd_control(byte disonoff, byte curonoff, byte curblink) { byte temp;outp(0x00,PORTA);toggle_E();temp=0x08;if (disonoff==1) temp|=0x04;if (curonoff==1) temp|=0x02;if (curblink==1) temp|=0x01;outp(temp,PORTA);toggle_E();lcd_delay(100);}/*-----------------27.5.99 20:31--------------------* Goto position (0x00 - 1.line, 1.col)* (0x40 - 2.line, 1.col)*--------------------------------------------------*/void lcd_goto(byte mesto){byte temp;temp=0x08;temp|=mesto>>4;outp(temp,PORTA);toggle_E();outp((mesto & 0x0F),PORTA);toggle_E();lcd_delay(100);}/*-----------------27.5.99 20:31-------------------- * Put character on LCD*--------------------------------------------------*/ void lcd_putch(byte data){ byte temp;temp=data>>4;temp=temp | 0x10;outp(temp,PORTA);toggle_E();temp=data & 0x0F;temp=temp | 0x10;outp(temp,PORTA);toggle_E();lcd_delay(100);}/*-----------------27.5.99 20:30-------------------- * Display null terminated string*--------------------------------------------------*/ void lcd_putstr(byte *data){while(*data) {lcd_putch(*data);data++;}}/*-----------------31.8.99 20:29-------------------- * Display 8bit bin value* printbin(0xAA,'0','1') -> 10101010* printbin(0xAA,'_','*') -> *_*_*_*_*--------------------------------------------------*/ void printbin(byte x, byte ch0, byte ch1) {byte i;for (i=128;i>0;i>>=1){if ((x&i)==0) lcd_putch(ch0);else lcd_putch(ch1);}}/*-----------------1.6.99 16:39---------------------* Display byte in hex (8bit)*--------------------------------------------------*/void printhex(byte i){byte hi,lo;hi=i&0xF0; // High nibblehi=hi>>4;hi+='0';if (hi>'9')hi+=7;lo=(i&0x0F)+'0'; // Low nibbleif (lo>'9')lo=lo+7;lcd_putch(hi); lcd_putch(lo);}/*-----------------31.08.99 18:34-------------------* Display 0..65535 with or without leading zeroes* printdec(12345,6,'0') -> 012345* printdec(12345,5,'') -> 12345* printdec(12345,6,' ') -> 12345*--------------------------------------------------*/void printdec(unsigned int x, unsigned char n, unsigned char fillch) {unsigned char i;unsigned char s[10];for (i = 0; i < n; i++) {s[n - i - 1] = '0' + (x % 10);x /= 10;}for (i=0; i<(n - 1); i++) {if (s[i] == '0') s[i] = fillch; else break;}for (i=0; i<n; i++) lcd_putch(s[i]);}/*-----------------31.5.99 18:18--------------------* Display unsigned long 0-4294967296 (32bit)*--------------------------------------------------*/void print10(unsigned long x){unsigned int y;if (x<4294967297ul){y=x/1000000000;lcd_putch(y+0x30);x-=(y*1000000000);y=x/100000000;lcd_putch(y+0x30);x-=(y*100000000);y=x/10000000;lcd_putch(y+0x30);x-=(y*10000000);y=x/1000000;lcd_putch(y+0x30);x-=(y*1000000);y=x/100000;lcd_putch(y+0x30);x-=(y*100000);y=x/10000;lcd_putch(y+0x30);x-=(y*10000);y=x/1000;lcd_putch(y+0x30);x-=(y*1000);y=x/100;lcd_putch(y+0x30);x-=(y*100);y=x/10;lcd_putch(y+0x30);x-=(y*10);lcd_putch(x+0x30);}else lcd_putstr("Err");}/*-----------------28.08.99 22:49-------------------* Simple printf function (no fp, and strings),* but it works for signed numbers*--------------------------------------------------*/int printf(const char *format, ...) {static const char hex[] = "0123456789ABCDEF";char format_flag;unsigned int u_val, div_val, base;//char *ptr;va_list ap;va_start (ap, format);for (;;) {while ((format_flag = *format++) != '%') {if (!format_flag) {va_end (ap);return (0);}lcd_putch (format_flag);}switch (format_flag = *format++) {case 'c': format_flag = va_arg(ap,int);default: lcd_putch(format_flag); continue;case 'd': base = 10; div_val = 10000; goto CONVERSION_LOOP; case 'x': base = 16; div_val = 0x10;CONVERSION_LOOP:u_val = va_arg(ap,int);if (format_flag == 'd') {if (((int)u_val) < 0) {u_val = - u_val;lcd_putch ('-');}while (div_val > 1 && div_val > u_val) div_val /= 10; }do {lcd_putch (hex[u_val / div_val]);u_val %= div_val;div_val /= base;} while (div_val);}}}。
红外遥控解码程序红外接收头的型号有很多HS0038 VS838等功能⼤致相同,只是引脚封装不同。
红外接收有⼏种统⼀的编码⽅式,采样哪种编码⽅式取决于遥控器使⽤的芯⽚,接收头收到的都是⼀样的。
电视遥控器使⽤的是专⽤集成发射芯⽚来实现遥控码的发射,如东芝TC9012,飞利浦AA3010T等,通常彩电遥控信号的发射,就是将某个按键所对应的控制指令和系统码(由0和1组成的序列),调制在38KHz的载波上,然后经放⼤、驱动红外发射管将信号发射出去。
不同公司的遥控芯⽚,采样的遥控码格式也不⼀样,较普遍的有两种,⼀种NEC标准,⼀种是PHILIPS标准。
NEC标准:遥控载波的频率为38KHz(占空⽐1:3)当某个键按下时,系统⾸先发射⼀个完整的全码,如果按键超过108ms仍未松开,接下来发射的代码(连发代码)将由起始码(9ms)和结束码(2.5ms)组成。
⼀个完整的全码 = 引导码 +⽤户码 +⽤户码 + 数据码 + 数据码 + 数据反码。
其中,引导码⾼电平9ms,低电平4.5ms;系统码8位,数据码8位,共32位;其中前16位为⽤户识别码,能区别不同的红外遥控设备,以防⽌不同的机种遥控码互相⼲扰。
后16位为8位的操作码和8位的操作反码,⽤于核对数据是否接收准确。
收端根据数据码做出应该执⾏上⾯动作的判断。
连发代码是在持续按键时发送的码。
它告知接收端。
某键是在被连续的按着。
NEC标准下的发射码表⽰发射数据0时⽤”0.56ms⾼电平 + 0.565ms低电平 = 1.125ms”表⽰;数据1⽤”⾼电平0.56ms + 1.69ms = 2.25ms”表⽰。
遥控器发射信号:需要注意的是:当⼀体化接收头收到38kHz红外信号时,输出端输出低电平,否则为⾼电平。
所以⼀体化接收头输出的波形和发射波形是反向的PHILIPS标准:载波频率38KHz:没有筒,点按键时,控制码1和0之间切换,若持续按键,则控制码不变。
⼀个全码 = 起始码’11’ +控制码 + ⽤户码 + ⽤户码数据0⽤“低电平1.778ms + ⾼电平1.778ms”表⽰;数据1⽤“⾼电平1.778ms + 低电平1.778ms”表⽰。
/item.htm?id=7693624806该模块采用5V电源供电,可以完成目前应用最广泛的多种红外遥控编码的解码,包括飞利浦(RC5)编码(典型编码芯片如SAA3010及兼容芯片如PT2210 等)和NEC编码(典型编码芯片如uPD6121,uPD6122, TC9012 )以及众多的兼容芯片型号,(如PT2221, PT2222, SC6121, SC6122,SC9012 等等),采用该模块,可以缩短开发时间,节约CPU 资源,降低总体成本。
特点●使用简单、可靠● 支持多种编码● 兼容SPI 及UART(波特率9600)的串行输出● 采用数字滤波技术,高抗干扰,无误码● 接收有效指示输出● 工业级温度范围储存温度-65至+150℃工作温度-40至+85℃任意接口对地电压-0.3至6V红外编码介绍目前应用于家电等领域的红外线遥控装置,并没有统一的国际标准,目前市场上所见的红外线遥控编码芯片,超过10 种之多,分别由飞利浦公司、NEC 公司、SONY 公司、东芝公司、三菱公司、JVC 公司等生产,使用的编码方式各不相同。
目前应用最广泛、兼容产品最多的,是飞利浦公司(RC5编码)的和NEC 公司的编码芯片。
本模块可以完成这两种格式编码的解码工作。
RC5 编码:RC5 编码由飞利浦公司推出,其编码芯片有SAA3010,SAA3006 等,是应用很广泛的一种编码方式。
RC5 编码采用双相位编码方式,用不同相位分别代表“0”和“1”。
传送每一位的时间固定为1.778mS。
每一个指令包括1.5bits 的起始位(2 个逻辑1),1 个翻转位,5 位系统码(地址码),以及6 位命令码(键码),因此,最多可以支持64 个键。
翻转位在每次有新的按键按下去的时候翻转一次,这里指的新按键,也包括同一个键抬起后再次按下的情况。
如果某个键持续按下,则编码芯片会不断地重复发送同样的数据。
翻转位保持不变。
而如果该键中途抬起后再次按下,则再次按下后所发送的数据中的翻转位发生翻转,其它数据保持不变。
NEC 编码:NEC 编码由NEC 公司推出,其典型编码芯片为uPD6121,uPD6122,除了NEC 公司的产品,市场上还有大量与之相兼容的产品,如PT2221, PT2222, SC6121, SC6122,SC9012 等等。
是应用最广泛的一种编码方式。
该编码方式采用脉冲位置编码方式,利用脉冲间的时间间隔来区分“0”和“1”。
每个指令包括32 位数据,包括16 位的用户码、以及8 位键数据码和键数据码的反码。
因为具有反码可以作为校验的依据,因此该种编码方式具有很低的误码率。
理论上该编码方式可以支持256 个键,实际的编码芯片一般可支持64 个键。
uPD1621 等芯片支持组合按键,即某些键码只有在特定的2 个键同时按下的情况下才会发出,这个功能对于类似录像机“录像”键等需要防止误操作的场合非常有用。
模块的输出接口ATC信号:模块的ACT 引脚作为接收有效指示输出,当模块芯片接收到有效的数据时,ACT 变为低电平。
对于RC5 和NEC 2种工作模式,ACT 信号的表现略有不同,这是由于两种编码制式的不同传输方式决定的。
下面分别介绍在两种工作模式下模块的输出情况:RC5 模式:RC5 的编码芯片在有持续按键的时候,会不断地重复发送相同的数据,因此,本模块也会不停地重复输出解码出的数据,而ACT 信号也会随着不停地跳变,每一个新的数据码到来时,都会输出一个低电平脉冲。
NEC 模式:与RC5 模式的遥控器不同,NEC 格式的遥控芯片在有按键持续按下的情况下,不是重复地发出数据码,而是仅在第一次时传送一次数据,此后只是每108ms 发送一次引导信号,表示按键还持续有效。
因此,本模块在接受这样的信号时,也只会在最开始输出一次数据,而按键的保持情况,是通过ACT 信号的持续低电平来表示的,如果ACT 一直持续保持低电平,则表示该按键一直有效,按键抬起后,ACT 也随之恢复高电平。
(见下图)如果用户需要判断遥控器的键是否被持续按下,对应RC5 模式和NEC 模式,应采用不同的方法,RC5 模式下,系统用翻转位来表示新的按键,用户可以将最后收到的键码数据中的翻转位(本模块芯片将翻转位置于键码数据的最高位BIT7)与上一次收到的数据中的翻转位相比较,如果两次翻转位相同,则表示是持续的按键,如果不同,则表示这是一个新的按键。
而对于NEC 模式,用户则可以通过监视ACT 信号来判断按键的情况,如果收到键码后,ACT 持续保持为低电平,则表示按键一直没有释放。
串行输出:模块串行数据输出使用三个引脚,分别用作SS(选通信号),CLK(时钟信号),DAT(串行数据)。
使用串行输出时,ACT 引脚电平也会发生变化, ACT 在数据开始输出前就跳变为低电平。
模块的串行输出,采用的是标准的3 线SPI 接口方式,不过,为了达到最大的兼容性,数据的传送速率(波特率)被特别设定为9600,因此,发出的数据也可以直接用于波特率为9600 的异步串行接口。
数据采用低位在前的方式。
输出时,SS 首先变为低电平,同时DAT 端也变为低电平,这个状态将保持104uS,这个时间正好是波特率9600 的异步串行口传送1 个BIT 所用的时间,如果接收数据方是UART,则DAT 保持低电平的这个104uS,相当于发送了1 个起始位(START BIT)。
随后第一个数据位在DAT 上输出,CLK 开始输出同步脉冲,每输出一位所用的时间为104uS,8 位数据的最后一位数据输出完成后,SS 恢复为高电平。
模块工作时,会将收到的用户码和按键键码一同输出,因此每次输出2-3 个字节,RC5 模式地址码只有5 位,因此输出2个字节,一个字节的地址码和一个字节的键码,地址码先输出。
NEC 模式有16 位用户码,因此将总共输出3 个字节,用户码高8 位在前,其次是用户码低8 位,最后是按键的键码。
下面用NEC 模式为例,说明其输出的波形:模块的应用方式1.与微处理器接口(1)、使用UART 方式很多的微处理器都提供片上的UART 接口,模块的串行输出兼容于“波特率9600,1 个起始位,1 个停止位,无奇偶校验位”的UART,使用的方式极其简单,只需要将模块的DAT引脚与微控制器的RX引脚相连即可。
这种接口方式只需要占用1 根口线,微处理器的数据接收可以由硬件完成,占用CPU 的资源很少。
(2)、使用SPI 方式有的微处理器,比如ATMEL 公司的AVR 系列等,具有片上的可以工作于从机模式的SPI 接口,这时也可以利用SPI 接口,和UART 方式类似,这种方式数据传输也由硬件完成,占用CPU 资源很少。
以AVR 芯片为例,将模块的DAT与单片机的MOSI 引脚相连,CLK 与SCK 相连,SS 与SS 相连,设置AVR 芯片的SPI 接口工作于“从机、上升沿为起始沿(Clock Polarity=LOW)、起始沿采样、低位数据在前”模式即可。
(3)、使用外部中断读取串行数据上面第三种方式占用的I/O 口比较多,如果希望减少I/O 的使用,可以采用外部中断读取串行数据的方式,这时,可以用SS 信号的下降沿或者CLK 信号的上升沿作为中断的触发条件。
使用SS 下降沿作为触发时,从中断触发到数据出现在DAT 引脚上,有104uS的时间,用户可以在中断处理程序中监视CLK 的状态,每次CLK 由低电平变为高电平,就读取一位数据。
因为每一位的时间都是104uS,加上开始时的104uS,整个中断处理程序(读取一个字节)需要耗时约900uS。
也可以采用CLK 的上升沿作为中断触发条件,每次中断服务程序只读取一位数据,这样可以减少一些读取数据的时间开销。
(4)、不使用中断的接口方式上面的几种方式都使用了硬件的串行接口或者是中断资源,有的低成本的微控制器没有这些资源,或者资源被其它程序占用,不能使用硬件接口和中断,则必须采取查询的方式。
查询方式的最大问题在于存在的丢失数据的可能性,因为程序除了查询模块状态外,还会有其他工作要做。
当程序正在执行其他任务,或者收到一个按键指令后进行处理尚未完成时,又有新的按键数据,则新来的数据就有可能因为未被CPU 察觉而丢失。
2. 与RS-232口相连模块的DAT输出经过简单的电平转换,就可以直接用于RS-232 接口,可以直接被PC接收,配合适当的软件(如串口调试助手等),可以完成PC的遥控控制及键码显示。
如通过MAX232电平转换后,在PC上通过配置好的串口调试助手,如下图,就能读出相应遥控器的按键编码。
模块的示例程序//模块的DAT端接51单片机RX端在LCD1602显示一款NEC编码遥控器数字0-9 #include<REG52.H>#include <LCD1602.H>#define uchar unsigned char#define uint unsigned int#define INBUF_LEN 3uchar inbuf1[INBUF_LEN]; unsigned char i=0;uchar c=0;uchar ir_value;sbit BZ=P3^5;//蜂鸣器bit read_flag= 0 ;uchar code a[10]={"0123456789"};//延时msvoid Delay1ms(uint count){uint i,j;for(i=0;i<count;i++)for(j=0;j<120;j++);}//串口初始化void init_serialcomm( void ) {TMOD=0x20;TH1=0xfd; //设置波特率为9600TL1=0xfd;SCON=0x50;TR1=1;ES=1;EA=1;}//串口接收3字节中断函数void Rcv_INT(void) interrupt 4 {if(RI){RI=0;inbuf1[i]=SBUF;i++;if(i==INBUF_LEN){i=0;read_flag=1;}}}//主函数void main(void){LCD_Initial();Delay1ms(50);GotoXY(0,0);Print("The 1602LCD IR");GotoXY(0,1);Print("GO: by YU");GotoXY(5,1);LCD_Write(LCD_DATA,a[c]);init_serialcomm(); //初始化串口while ( 1 ){Delay1ms(50);//延时50MS开始接收i=0; //忽略BC7210上电输出乱码if(read_flag) //如果取数标志已置位,就将读到的数进行辗转处理{read_flag =0; //取数标志清0if(inbuf1[0]==0x00&&inbuf1[1]==0xFF)//接收到的地址码高8位和低8位 {BZ=!BZ;Delay1ms(50);//蜂鸣器响一下表示接收到数据BZ=!BZ;ir_value=inbuf1[2];//接收到的1字节数据码switch(ir_value)//判断数据码对应遥控器键盘的数据{case 0x12:{c=0;break;}//注意:遥控器的地址码和数据码事先通过串口调//试助手在PC上读出,不同的遥控有不同的//编码,见上节与RS-232口相连的内容 case 0x09:{c=1;break;}case 0x1D:{c=2;break;}case 0x1F:{c=3;break;}case 0x0D:{c=4;break;}case 0x19:{c=5;break;}case 0x1B:{c=6;break;}case 0x11:{c=7;break;}case 0x15:{c=8;break;}case 0x17:{c=9;break;}default:{break;}}GotoXY(5,1);LCD_Write(LCD_DATA,a[c]);}}}}//以下是LCD1602.H文件#ifndef LCD_CHAR_1602_2005_4_9#define LCD_CHAR_1602_2005_4_9#include <intrins.h>//PortDefinitions**************************************************** sbit LcdRs = P1^0;sbit LcdRw = P1^1;sbit LcdEn = P1^2;sfr DBPort = 0x80; //P0=0x80,P1=0x90,P2=0xA0,P3=0xB0.数据端口//内部等待函数***************************************************** unsigned char LCD_Wait(void){LcdRs=0;LcdRw=1; _nop_();LcdEn=1; _nop_();while(DBPort&0x80);//在用Proteus仿真时,注意用屏蔽此语句,在调用//GotoXY()时,会进入死循环,//可能在写该控制字时,该模块没有返回写入完备命//令,即DBPort&0x80==0x80//实际硬件时打开此语句LcdEn=0;return DBPort;}//向LCD写入命令或数据****************************************#define LCD_COMMAND 0 // Command#define LCD_DATA 1 // Data#define LCD_CLEAR_SCREEN 0x01 // 清屏#define LCD_HOMING 0x02 // 光标返回原点void LCD_Write(bit style, unsigned char input){LcdEn=0;LcdRs=style;LcdRw=0; _nop_();DBPort=input; _nop_();//注意顺序LcdEn=1; _nop_();//注意顺序LcdEn=0; _nop_();LCD_Wait();}//设置显示模式***************************************************#define LCD_SHOW 0x04 //显示开#define LCD_HIDE 0x00 //显示关#define LCD_CURSOR 0x02 //显示光标#define LCD_NO_CURSOR 0x00 //无光标#define LCD_FLASH 0x01 //光标闪动#define LCD_NO_FLASH 0x00 //光标不闪动void LCD_SetDisplay(unsigned char DisplayMode){LCD_Write(LCD_COMMAND, 0x08|DisplayMode);}//设置输入模式****************************************************** #define LCD_AC_UP 0x02#define LCD_AC_DOWN 0x00 // default#define LCD_MOVE 0x01 // 画面可平移#define LCD_NO_MOVE 0x00 //defaultvoid LCD_SetInput(unsigned char InputMode){LCD_Write(LCD_COMMAND, 0x04|InputMode);}//移动光标或屏幕***************************************************** /*#define LCD_CURSOR 0x02#define LCD_SCREEN 0x08#define LCD_LEFT 0x00#define LCD_RIGHT 0x04void LCD_Move(unsigned char object, unsigned char direction){if(object==LCD_CURSOR)LCD_Write(LCD_COMMAND,0x10|direction);if(object==LCD_SCREEN)LCD_Write(LCD_COMMAND,0x18|direction);}*///初始化LCD********************************************************* void LCD_Initial(){LcdEn=0;LCD_Write(LCD_COMMAND,0x38); //8位数据端口,2行显示,5*7点阵LCD_Write(LCD_COMMAND,0x38);LCD_SetDisplay(LCD_SHOW|LCD_NO_CURSOR); //开启显示, 无光标LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏LCD_SetInput(LCD_AC_UP|LCD_NO_MOVE); //AC递增, 画面不动}//******************************************************************* void GotoXY(unsigned char x, unsigned char y){if(y==0)LCD_Write(LCD_COMMAND,0x80|x);if(y==1)LCD_Write(LCD_COMMAND,0x80|(x-0x40));}void Print(unsigned char *str){while(*str!='\0'){LCD_Write(LCD_DATA,*str);str++;}}/*void LCD_LoadChar(unsigned char user[8], unsigned char place){unsigned char i;LCD_Write(LCD_COMMAND,0x40|(place*8));for(i=0; i<8; i++)LCD_Write(LCD_DATA,user[i]);}*///******************************************************************* #endif以下是附加文档,不需要的朋友下载后删除,谢谢顶岗实习总结专题13篇第一篇:顶岗实习总结为了进一步巩固理论知识,将理论与实践有机地结合起来,按照学校的计划要求,本人进行了为期个月的顶岗实习。