红外遥控接收程序
- 格式:docx
- 大小:12.88 KB
- 文档页数:3
#include <AT89X51.H>#define uchar unsigned charsbit int0=P3^2;sbit k0=P2^0;sbit k1=P2^1;sbit k2=P2^1;sbit k3=P2^3;sbit k4=P2^4;sbit k5=P2^5;sbit k6=P2^6;sbit k7=P2^7;uchar temp=0x00;uchar temp1=0x00;void delay60ms(void) {unsigned char i,j;for(i=120;i>0;i--)for(j=248;j>0;j--);}void delay15min(void){unsigned char i,j,k;for(k=1500;k>0;k--)for(i=120;i>0;i--)for(j=248;j>0;j--);}void delay45min(void){unsigned char i;for(i=3;i>0;i--)delay15min();}void delay60min(void){unsigned char i;for(i=4;i>0;i--)delay15min();}void delay90min(void){unsigned char i;for(i=6;i>0;i--)delay15min();}void delay30min(void){unsigned char i;for(i=2;i>0;i--)delay15min();}void delay10ms (void){unsigned char i,j;for(i=20;i>0;i--)for(j=248;j>0;j--);}void dingshi(temp1){unsigned char count=0;while(1){ if(temp1==0){delay10ms();if(temp1==0){count++;if(count==5){count=0;}while(temp1==0);}switch(count){case 0:delay15min();break;case 1:delay30min();break;case 2:delay45min();break;case 3:delay60min();break;case 4:delay90min();break;}P2=0;}}}void panduan (temp){while(1){switch(temp){case 0x01: k0=0;case 0x02 :k1=0;case 0x03 :k3=0;case 0x04 :k4=0;case 0x05 :k5=0;case 0x06 :dingshi(temp);}}}void main(void){while(1)receive();{uchar i;for(i=0;i<8;i++){temp<<=1;if (int0!=0)temp=0x01;}for(i;i<16;i++){temp1<<=1;if (int0!=0)temp=0x01;}if(temp==0x47)delay60ms();if(temp==0x47){if(temp1==0x07)k7=0;else if(temp1==0x09)P2=0;elsepanduan(temp1);}}}//遥控器:M50462AP - JINXING - 30个按键//单片机:STC89C51RC//晶振:11.0592MHz//红外接收:1838/*--------------------------------------------------------------*/#include <reg52.H>/*--------------------------------------------------------------*///红外接口定义sbit IRDA = P1^4;unsigned char T_C; //50us计数次数46#define D_ERROR 5 //容错值sbit ser=P2^1; //595串行数据输入sbit srclk=P2^2; //移位时钟sbit rclk=P2^3; //锁存时钟unsigned char idata LED[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};//共阳极段码表说明void outbyte(unsigned char a,unsigned char b){ unsigned char j;for(j=0;j<8;j++) //位码移位串行输出{ if(a&0x80) ser=1; else ser=0; a=a<<1;srclk=0; //595移位脉冲srclk=1; }for(j=0;j<8;j++) //段码移位串行输出{ if(b&0x80) ser=1; else ser=0;b=b<<1;srclk=0; srclk=1; }rclk=0; //595锁存脉冲rclk=1; }void T0_init(void){ TMOD |= 0x02; TH0 = 0xd2;TL0 = 0xd2; IE |= 0x82;TR0 = 1;}void T0_intservice(void) interrupt 1{ T_C++; }void main(void){ unsigned char i, j;unsigned char IRDA_dat[2];T0_init();while(1){ for(j = 0; j < 2; j++){ while(IRDA); //1for(i = 0; i < 8; i++){ T_C = 0;while(!IRDA); //0 0.25mswhile(IRDA); //1 0.75ms-0/1.75ms-1if((T_C > (40 - D_ERROR)) && (T_C < (40 + D_ERROR))) {IRDA_dat[j] >>= 1; IRDA_dat[j] |= 0x80;} //1else if((T_C > (20 - D_ERROR)) && (T_C < (20 + D_ERROR))) {IRDA_dat[j] >>= 1;} //0 }if(j == 1) while(!IRDA);//0if(IRDA_dat[0] != 0x47) break; //错误处理,引导码是否正确引导码C0~C7由1110XX10组成}outbyte(0x00, ~IRDA_dat[1]);IRDA_dat[0] = 0; IRDA_dat[1] = 0;}}。
红外发送调用SendIRdata();while(over==0);地址储存在addr(可根据需要改成发送16位地址,此程序发送的是八位地址,第二地址是第一个的反码)中,hwdata,c,d,over,dat是全局unsigned char ,在等待红外发送完成while(over==0)语句,等待时间为几十ms,可在前面或while中可执行其他程序。
(等待期间不需要执行其他程序也可把while语句放入SendIRdata()末尾)void SendIRdata(unsigned char x){TH1=0xdc;//发送9ms的起始码TL1=0xd8;TR2=1;TR1=1;hwdata=x;over=0;//红外发送结束标志,为1完成}/**************定时器1中断处理***************/void timeint(void) interrupt 3{switch(c){case 0: //起始码4.5msTH1=0xee;TL1=0x6c;TR2=0;c=1;dat=addr;//发送十六位地址的前八位break;case 1:TH1=0xfd; //560us高电平TL1=0xd0;TR2=1;c=2;break;case 2:if(dat&0x01){ TH1=0xf9;TL1=0x5c;}//1.7ms低电平else{ TH1=0xfd;TL1=0xd0;}//560us低电平TR2=0;dat>>=1;d++;c=1;if(d==8)dat=~addr;//发送十六位地址的后八位if(d==16)dat=hwdata;//发送八位数据if(d==24)dat=~hwdata;//发送八位数据的反码if(d==33){over=1;TR1=0;TR2=0;d=0;c=0;}break;}}外中断0 接收,储存在dat[3]全局变量中,hu,time1,time2,h,b,是unsigned char型全局变量,time是unsigned intvoid extern0() interrupt 0 //中断程序{if(hu==0){TL1=0;TH1=0;TR1=1;hu=1;}else{TR1=0;time1=TH1;time2=TL1;TL1=0;TH1=0;TR1=1;time=time1*256+time2;if(start==0){if((14000>time)&&(time>13000))start=1;}else{//if((time>2100)&&(2400>time))//{dat[h]>>=1; dat[h]=dat[h]|0x80;}//else//if((time>1000)&&(1250>time))//dat[h]>>=1;dat[h]>>=1;if((time>2100)&&(2400>time))dat[h]=dat[h]|0x80;b++;if(b>7){ b=0;h++;if(h>3){h=0;start=0;hu=0;if(dat[0]!=~dat[1]|| dat[2]!=~dat[3])dat[2]=0;}}}}}。
1 引言近年来随着计算机在社会各领域的渗透,单片机的应用正在不断地走向深入,同时也带动传统的控制、检测等工作日益更新。
传统的遥控器大多采用无线电遥控技术,随着科技的进步,红外线遥控技术的进一步成熟,红外遥控也逐步成为了一种被广泛应用的通信和遥控手段。
为了方便实用,传统的家庭电器逐渐采用红外线遥控。
工业设备中,在高压、辐射、有毒气体、粉尘等有害环境下,采用红外线遥控不仅完全可靠而且能有效地隔离电气干扰。
红外遥控的特点是不影响周边环境、不干扰其它电器设备。
由于其无法穿透墙壁,故不同房间的家用电器可使用通用的遥控器而不会产生相互干扰;电路调试简单,只要按给定电路连接无误,一般不需任何调试即可投入工作;编解码容易,可进行多路遥控。
红外遥控虽然被广泛应用,但各产商的遥控器不能相互兼容。
当今市场上的红外线遥控装置一般采用专用的遥控编码及解码集成电路,但编程灵活性较低,且产品多相互绑定,不能复用,故应用范围有限。
而本文采用单片机进行遥控系统的应用设计,遥控装置将同时具有编程灵活、控制范围广、体积小、功耗低、功能强、成本低、可靠性高等特点,因此采用单片机的红外遥控技术具有广阔的发展前景。
2 概述2.1 基于单片机的红外遥控系统概述当今社会科学技术的发展与日俱增,人们生活水平也是日益提高,为了减少人们的工作量,所以对各种家用电器、电子器件的非人工控制的要求越来越高,针对这种情况,设计出一种集成度比较高的控制体系是必然的。
现代科技的飞速发展在许多危险、不可近场合也对远程控制提出了越来越高的要求。
单片机是指一个集成在一块芯片上的完整计算机系统。
尽管他的大部分功能集成在一块小芯片上,但是它具有一个完整计算机所需要的大部分部件:CPU、内存、内部和外部总线系统,目前大部分还会具有外存。
同时集成诸如通讯接口、定时器,实时时钟等外围设备。
而现在最强大的单片机系统甚至可以将声音、图像、网络、复杂的输入输出系统集成在一块芯片上。
//STC89C52RC//11.0592MHZ#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define TH0_V ALUE 0xc5#define TL0_V ALUE 0xc5 // 定时器计数值#define ANT P2^4 //红外IO口,可任意一个IO//系统变量定义区============================================================volatile unsigned char irr_b=0,s_s=0;//irr_b接收状态指示,s_s显示许可volatile signed long da=0; //32位数据码volatile unsigned char wb=0, a=0; //wb为接收到的位数,a为接收到信号高低电平判断依据volatile unsigned int js=0; //定时器计数volatile unsigned char a1=1,a2=1; //上升沿处理变量void timer_init(void){ET0=0;TMOD=0x02;TCON=0x10;TL0=TL0_VALUE;TH0=TH0_V ALUE;ET0=1;}void timer_start(){TR0=1;EA=1;}void timer0_interrupt(void) interrupt 1 //大约63us中断一次{js++;//判断下降a2=ANT;if (a1>a2){if(irr_b==0) //第一个中断{irr_b=1; //状态为:开始接收js=0;}else if(irr_b==1) //第二个以后的中断{a=js; //读取定时器的值if((170<a)&&(a<240)) //判断是引导,还是数据10.7ms-15.7ms 引导码长13.5ms{wb=0; //数据计数清零da=0; //数据清零js=0; //定时器清零}else //数据{if((8<a)&&(a<25)) //0.5ms-1.57ms 低电平长1.125ms{wb++;js=0;da=(da<<1) ;}else{if((25<a)&&(a<45)) //1.57ms-2.8ms 高电平长2.25ms{wb++;js=0;da=(da<<1) +1 ;}}if(wb>=32) //数据长度够32位{irr_b=0; //状态为停止接收wb=0; //数据计数清零s_s=1; //打开显示许可}}}}a1=a2; //a为两个下降沿之间的时间}void program(void){uchar ds=0,d1;while(1){ds=js;if(ds>250) //定时器超时,接收复位{js=0;irr_b=0;da=0;wb=0;s_s=0;}if(s_s==1) //显示开关打开,开始显示{TR0=0; //关闭全局中断//显示设备码d1=da>>8;d1=da; //把long型的da强制转换为char型的d1switch(d1){case 0xff:P2=0xff;uart_tx(255);break; //停止,灯全灭case 0x9f:P2=0xfe;uart_tx(191);break; //正转,对应的灯亮case 0x5f:P2=0xfd;uart_tx(239);break; //反转,对应的灯亮case 0xaf:P2=0xfb;uart_tx(251);break; //加速,对应的灯亮case 0x6f:P2=0xf7;uart_tx(254);break; //减速,对应的灯亮default:break; }s_s=0; //关闭显示开关TR0=1; //开全局中断}}}void delay_ms(unsigned int i){unsigned int j;while(i--){for(j=0;j<75;j++);}}void uart_init(){TMOD|=0X20; //只把M1置为1,其余位不变,默认为0TH1=0XFD;TL1=0XFD;SCON=0X50; // 设定串行口工作方式PCON&=0XEF; // 波特率不倍增,只把倍增位置0,其他位保持不变,默认为0TR1=1;}void uart_tx(unsigned char txd){SBUF=txd;while(!TI);TI=0;}void uart_cn(unsigned char *cn,unsigned char cn_nub){unsigned char i;for(i=0;i<(cn_nub);i++){uart_tx(cn[i]); //发送数据i_nop_();_nop_();_nop_();_nop_();_nop_(); //无实际意义,后移cpu指针,使指令按字对齐,减少取指令时的内存访问次数}}void main(){timer_init();timer_start();uart_init();EA=1;P2=0xf0;delay_ms(10);program();}。
5104红外接收程序//cmd_state 起始码、用户码、指令码所处的状态标志//cmd_data 指令码7位数据存储器//cmd_start 起始码接收完毕标志//cmd_admin 用户码接收完毕标志//cmd_bit 端口中断或定时器溢出中断接收到的一位数据,该数据有三种状态:1、0、错误static volatile uchar cmd_state,cmd_data;static volatile bit cmd_start,cmd_admin;void IntCmd(){if(!cmd_start) //若起始码未接收到,则先持续处理起始码{if(cmd_bit==1){switch (cmd_state){case 1:cmd_state=2;break; //1 1case 2:cmd_state=2;break; //1 1 1时,舍弃第一个接收到的1 default:cmd_state=1;break; //1 否则,认为是起始码的第一个bit }}else if(cmd_bit==0){switch (cmd_state){case 2:cmd_state=3;break; //1 1 0 正确的起始码default:cmd_state=0;break; //?? ?? ?? ??(全部字节不对,)}}else cmd_state=0; //若接收到的是错误位,则清除起始码的侦测记录if(cmd_state==3) //得到完整的起始码{cmd_state=0;cmd_admin=0;cmd_start=1;}}else{if(!cmd_admin){if(cmd_bit==1){if(cmd_state==1){cmd_state=0;cmd_data=0;cmd_admin=1;}else cmd_state=1;}else //若用户码出现0或者错误位,则重置起始码{cmd_state=0;cmd_start=0;}}else{if(cmd_bit==1||cmd_bit==0){cmd_data=(cmd_data<<1)|cmd_bit;cmd_state++;if(cmd_state==7){cmd_state=0;cmd_start=0;cmd_admin=0;switch (cmd_data){case 0X01:Key1=1;break; //第1个键按下每个按键可以用按键时间来替换,当倒计时为0时,自动清除按键标志。
基于STM32F1HAL库的红外解码程序,核心思想是通过外部下降沿中断记录相邻两个下降沿的时间,记录的数据存入数组,再根据数据判断是0还是1,获得NEC协议的4个码。
程序使用PG15作为中断输入,使用基本定时器7定时,相比在中断里面等待的方式节省了CPU时间,提高了效率,也方便移植到其他型号的MCU上。
程序没有处理连发的问题,感兴趣的可以尝试修改。
.c文件#include"bsp_ir.h"//irdata[33]存储相邻下降沿的cnt计数值uint8_tirdata[33],cnt=0,IR_OK=0;TIM_HandleTypeDefir_timx;voidIR_Init(void){GPIO_InitTypeDefGPIO_InitStruct;IR_GPIO_CLK_ENABLE;GPIO_InitStruct.Pin=IR_GPIO_PIN;GPIO_InitStruct.Mode=GPIO_MODE_IT_FALLING;//下降沿中断GPIO_InitStruct.Pull=GPIO_PULLUP;//上拉HAL_GPIO_Init(IR_GPIO_PORT,&GPIO_InitStruct);HAL_NVIC_SetPriority(IR_EXTI_IRQn,1,1);HAL_NVIC_EnableIRQ(IR_EXTI_IRQn);IR_TIMx_Init(249,71);}//Tout=(arr+1)*(psc+1)/sck//设计Tout=250us,psc=71,arr=249,sck=72MHzvoidIR_TIMx_Init(uint16_tarr,uint16_tpsc){ir_timx.Instance=IR_TIMx;ir_=psc;ir_=TIM_COUNTERMODE_UP;ir_=arr;ir_=TIM_CLOCKDIVISION_DIV1;ir_=TIM_AUTORELOAD_PRELOAD_DISABLE;IR_TIMx_RCC_CLK_ENABLE();HAL_NVIC_SetPriority(IR_TIMx_IRQn,1,0);HAL_NVIC_EnableIRQ(IR_TIMx_IRQn);HAL_TIM_Base_Init(&ir_timx);__HAL_TIM_CLEAR_FLAG(&ir_timx,TIM_FLAG_UPDATE);HAL_TIM_Base_Start_IT(&ir_timx);}//定时器中断服务函数voidIR_TIMx_IRQHandler(void){HAL_TIM_IRQHandler(&ir_timx);}//定时器更新中断回调函数voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim) {if(htim->Instance==IR_TIMx){cnt++;}}//外部中断服务函数//根据霖锋老师89C51篇关于红外接收的程序修改voidIR_EXTI_IRQHandler(void){staticuint8_tuCounter;staticuint8_tStartflag=0;//开始接收标志HAL_GPIO_EXTI_IRQHandler(IR_GPIO_PIN);if(!Startflag){Startflag=1;cnt=0;}elseif(Startflag){if((cnt<60)&&(cnt>40))//引导码检测(9+4.5)/0.25=54 uCounter=0;irdata[uCounter]=cnt;//cnt存储了相邻两个下降沿的时间差cnt=0;uCounter++;if(uCounter==33)//接收完成{uCounter=0;IR_OK=1;Startflag=0;}}}//获得命令码//成功返回命令码,错误返回0uint8_tIR_GET_CODE(void){uint8_ti,j,k=1,value=0,ir_code[4];//ir_code[0]:用户码ir_code[1]:用户码反码ir_code[2]:命令码ir_code[3]:命令码反码if(IR_OK!=1)return0;else{IR_OK=0;for(i=0;i<4;i++){for(j=0;j<8;j++){value>>=1;//注释部分对应低位在前的情况if(irdata[k]>6) //0:1.125/0.25=4.5<6,1:2.25/0.125=9>6value|=0x80;k++;}ir_code[i]=value;}k=1;value=0;if(ir_code[2]+ir_code[3]==0xFF)//数据校验{returnir_code[2]; //返回的是命令码}elsereturn0;}}.h文件#ifndef_BSP_IR_H#define_BSP_IR_H#include"stm32f1xx_hal.h"//用PG15的EXTI中断来检测红外引脚电平跳变,基本定时器7用来计时//可根据自己需要修改#defineIR_TIMxTIM7#defineIR_TIMx_RCC_CLK_ENABLE()__HAL_RCC_TIM7_CLK_ENABLE()#defineIR_TIMx_IRQnTIM7_IRQn#defineIR_TIMx_IRQHandlerTIM7_IRQHandler#defineIR_GPIO_CLK_ENABLE __HAL_RCC_GPIOG_CLK_ENABLE()#defineIR_GPIO_PORTGPIOG#defineIR_GPIO_PINGPIO_PIN_15#defineIR_EXTI_IRQnEXTI15_10_IRQn#defineIR_EXTI_IRQHandlerEXTI15_10_IRQHandler//遥控器上按键的控制码,十进制,根据自己遥控器上的按键修改#definePOWER162#defineMODE98#defineSPEAK226#definePLAY34#definePREV2#defineNEXT194#defineEQ224#defineVOL_PLUS144#defineVOL_REDU168#defineRPT152#defineU_SD176#defineZERO104#defineONE48#defineTWO24#defineTHREE122#defineFOUR16#defineFIVE56#defineSIX90#defineSEVEN66#defineEIGHT74#defineNINE82voidIR_Init(void);voidIR_TIMx_Init(uint16_tarr,uint16_tpsc);uint8_tIR_GET_CODE(void);#endifMain函数中直接调用IR_GET_CODE函数即可获得命令码。
/*-----------------------------------------------名称:红外发射接收修改:无内容:*红外测试程序,用单片机通过发射管发射38K的调制频率码,由一体化接收并解码由发光管显示。
*正常情况下,由于反射和高灵敏度接收,LED4(P1.7)一直闪烁,可以用黑色纸片完全遮挡接收头使*之不能接收到发射管的信号,这是LED4熄灭。
说明功能性正常------------------------------------------------*/#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义sbit LED=P2^3; //红外发射sbit LED1=P0^1;bit Flag;void Init_Timer0(void){TMOD |= 0x01;TH0=0xf0; /* Init value */TL0=0x00;EA=1; /* interupt enable */ET0=1; /* enable timer0 interrupt */TR0=1;}/******************************************************************/ /* 定时器0初始化 *//******************************************************************/ void Timer0_isr(void) interrupt 1 using 1{TH0=0x0f; /* Init value */TL0=0x00;Flag=!Flag;}/******************************************************************/ /* 主函数 *//******************************************************************/ main(){unsigned int j;Init_Timer0(); //定时器初始化LED1=0;while(1){ //读取一体化接收头数值if(Flag){for(j=0;j<27;j++)//大约38KHz{LED=!LED; //发射管输出}}}}#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义sbit LED=P0^1;sbit IR=P2^3; //红外一体化接收sbit LED1=P0^2;sbit BUZZER=P2^5;void delayus(unsigned us){ unsigned int i,j;for(i=0;i<us;i++)for(j=0;j<101;j++);}main(){LED1=0;BUZZER=0;while(1){unsigned int a,b;b=0;for(a=0;a<22;a++){ if(IR==0)b=b+1;delayus(6);//对脉冲采样}if(b>5){LED=0;BUZZER=0;}else{LED=1;BUZZER=1;}//有障碍物灯灭、蜂鸣器响}}。
#include "remote.h"
UINT IrCode; //高8位为系统码,低八位为数据码
/*************************************************************************** *FUNCTION NAME: DelayIr
*CREATE DATE: 2012/6/7
*CREATED BY: XS
*FUNCTION: IR采样延时:0.14ms
*MODIFY DATE: 2012/6/7
*INPUT: 无
*
*RETURN: 无
***************************************************************************/ void DelayIr(UCHAR timer)
{
UCHAR i;
while(timer--)
{
for (i = 0; i<13; i++);
}
}
/*************************************************************************** *FUNCTION NAME: RemoteDecode
*CREATE DATE: 2012/6/7
*CREATED BY: XS
*FUNCTION: IR遥控解码
*MODIFY DATE: 2012/6/7
*INPUT: 无
*
*RETURN: 无
***************************************************************************/ void RemoteDecode(void)
{
UCHAR i,j,n = 0;
UCHAR irDat[4] = {0};
EX0 = 0;
DelayIr(1);
if (IRIN==1)
{
EX0 = 1;
return;
}
DelayIr(29);
if (IRIN==1)
{
EX0 = 1;
return;
}
while (!IRIN) //等IR变为高电平,跳过9ms的前导低电平信号。
{
DelayIr(2);
}
for (i=0;i<4;i++) //收集四组数据
{
for (j=0;j<8;j++) //每组数据有8位
{
while (IRIN) //等IR 变为低电平,跳过4.5ms的前导高电平信号。
{
DelayIr(2);
}
while (!IRIN) //等IR 变为高电平
{
DelayIr(2);
}
while (IRIN) //计算IR高电平时长
{
DelayIr(2);
n++;
if (n>=30) //0.14ms计数过长自动离开。
{
EX0 = 1;
return;
}
} //高电平计数完毕
irDat[i] = irDat[i] >> 1; //数据最高位在前
if (n>=8)
irDat[i] = irDat[i] | 0x80; //数据最高位补“1”
n = 0;
}
}
// if (irDat[2] != ~irDat[3]) //数据码与其反码比较
// {
// EX0 = 1;
// return;
// }
IrCode = (irDat[2]<<8) + irDat[3];
EX0 = 1;
}
/*************************************************************************** *FUNCTION NAME: ExitInt0
*CREATE DATE: 2012/6/8
*CREATED BY: XS
*FUNCTION: 红外遥控解码:NEC码:系统码+系统反码+数据码+数据反码
*MODIFY DATE: 2012/6/8
*INPUT: 无
*RETURN: 无
***************************************************************************/ void ExitInt0(void) interrupt 0
{
RemoteDecode();
}。