红外解码--基于1838红外接收头

前言

很早一段时间就想把红外解码的思路及代码写到博客上面,但是因为拖延症拖延到现在。
作者是使用的野火的指南针开发板(野火打钱),遥控器也使用的是野火店里面卖的。此处应该收广告费
本文仅介绍解码原理 ,因为发射很简单,就控制一个IO拉高拉低就行了,或者使用pwm等等。当然了如果解码你都会写了,发射那肯定是手到擒来。

1 解码原理

解码原理其实很简单,就是检测一个IO的高低电平持续时间就行了。当然了,红外的时序是有要求的,比如说起始信号、结束信号、数据码、持续信号等。这里的数据码包括系统识别码和操作码。
这里直接贴上野火的讲解
/*
遥控码由三部分组成
1、leader code 9ms的高电平 + 4.5ms 的低电平
2、系统识别码 区别不同的红外遥控设备
3、操作码 8bit操作码和8bit的操作反码组成

0和1均以0.56ms的低电平开始(实际测量是500us的样子),不同的是后面出现的高电平,
如果高电平是0.56ms(实际测量是500us的样子),则表示0,如果高电平是1.68ms(0.56*3=1.68)则表示1

结束码
高电平超过40ms,然后出现9ms的低电平
连发码 2.1ms的高电平
*/

2 思路讲解

本文这里原理讲解比较简单,看不懂的可以自行百度。这不是本文讲解的重点。
作者使用的是定时器加外部中断的方式进行解码。当然还有还有 别的方式可以进行解码,这个都无所谓。
首先的思路是计算IO的高低电平时间,那么定时器当然就少不了

2.1 定时器配置

从解码原理那里可以看到高电平的持续时间范围为0.56ms到大于40ms。
那么我们开始配置定时器了,作者使用的stm32f103频率位72MHz,使用的定时器TIM3(当然你也可以选一个你自己喜欢的定时器)。那么我们配置定时器记一个数的时间位0.01ms,0.01ms对应的是100kHz,定时器的分频系数 = 72M/100K = 720。这个时候我们定时器计数只要超过40ms/0.01ms = 4000即可,这里作者设置为5000。当然了,定时器中断就不需要开了,因为我们用到的仅仅是计时而已。代码如下:

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

TIM_TimeBaseStructure.TIM_Period = (5000-1);
TIM_TimeBaseStructure.TIM_Prescaler = (720-1);//0.01ms   50ms
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

TIM_Cmd(TIM3, ENABLE);

2.2 IO配置

IO的话,我们需要用到中断、输入模式。野火红外接收原理图如下
在这里插入图片描述
这里使用的IO是PE5,当然了使用哪个IO口都可以,仅仅是和你自己的板子配合起来使用而已。
这里我们配置IO模式为浮空上拉模式,中断触发模式配置为双边沿触发模式。
因为IO配置位输入模式了,速率是不需要的,所以那一行代码可有可无。
代码如下:

GPIO_InitTypeDef         GPIO_InitStructure;
NVIC_InitTypeDef         NVIC_InitStructure;
EXTI_InitTypeDef         EXTI_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO, ENABLE);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource5);
EXTI_InitStructure.EXTI_Line = EXTI_Line5;	
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);

2.3 按键中断解码

对IO、TIM的配置可以看到很简单,这里开始讲解中断服务函数里面的内容了。
从最开始的内容我们可以知道红外解码最主要的数据有四个–系统识别码(8bit)+系统识别码反码(8bit)+操作码(8bit)+操作码反码(8bit)。这里我们直接用一个32bit的数据进行存储红外接收到的数据,而且通过分析红外的原理我们可以发现仅仅计算高电平的时间我们就可以完成解码的操作,当然了作者这里是进行了偷懒操作,不提倡大家学习。
高电平时间计算方式位在io上升沿时清零定时器的计数值,在下降沿时记录定时器计数值即可。
再看下面代码时,可以先不看InfraredData结构体的代码内容以及#if、#endif的内容。

void EXTI9_5_IRQHandler(void)
{
	static uint32_t  irdata = 0;
#if   !Continuous
	static _Bool start = False;
#endif
	if(EXTI_GetITStatus(EXTI_Line5))
	{
		EXTI_ClearITPendingBit(EXTI_Line5);
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_5))
		{
			/* 上升沿 */
			TIM_SetCounter(TIM3,0);
			InfraredHightime = 0;
		}
		else
		{
			/* 下降沿 */
			InfraredHightime = TIM_GetCounter(TIM3);
			if(InfraredHightime>400 && InfraredHightime<500)
			{
#if   !Continuous				
				start = True;
#endif				
				irdata = 0;
			}
#if   !Continuous
			else if(start)
			{
				if(0)
				{}
#endif
				else if(InfraredHightime>40 && InfraredHightime<72)
				{
					irdata <<= 1;
					irdata |= 0;
				}
				else if(InfraredHightime>150 && InfraredHightime<186)
				{
					irdata <<= 1;
					irdata |= 1;
				}
				else if((InfraredHightime>4000) || (InfraredHightime<220))
				{			
#if   !Continuous
					start = False;
#endif
						InfraredData.sid = irdata>>24;
						InfraredData.nsid = irdata>>16;
						InfraredData.opcode = irdata>>8;
						InfraredData.nopcode = irdata>>0;
						InfraredData.ismark = True;
				}
#if   !Continuous
			}
#endif	
		}
	}
}

可以看到作者是在下降沿的中断里才开始处理,代码具体内容就不进行讲解了,读者自行观看即可。
InfraredData结构体内容如下
ismark代表的是解码完成,也就是当前结构体的数据有效。
宏Continuous控制的是支持连续解码还是必须松开才能进行下次解码。

typedef struct
{
	uint8_t sid;//System identification code
	uint8_t nsid;//System identification code inverse code
	uint8_t opcode;//operation code
	uint8_t nopcode;//operation code inverse code
	_Bool ismark;//Infrared switching mark
}infrared_t;

完整代码如下

infrared.c

#include "infrared.h"

infrared_t InfraredData;
static uint16_t InfraredHightime = 0;

static void InfraredDataInit(void)
{
	InfraredData.ismark = False;
	InfraredData.opcode = 0;
	InfraredData.nopcode = 0;
	InfraredData.sid = 0;
	InfraredData.nsid = 0;
}
void InfraredInit(void)
{
	GPIO_InitTypeDef         GPIO_InitStructure;
	NVIC_InitTypeDef         NVIC_InitStructure;
	EXTI_InitTypeDef         EXTI_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOE, &GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource5);
	EXTI_InitStructure.EXTI_Line = EXTI_Line5;	
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	TIM_TimeBaseStructure.TIM_Period = (5000-1);
	TIM_TimeBaseStructure.TIM_Prescaler = (720-1);//0.01ms   50ms
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

	TIM_Cmd(TIM3, ENABLE);
	InfraredDataInit();
}

void EXTI9_5_IRQHandler(void)
{
	static uint32_t  irdata = 0;
#if   !Continuous
	static _Bool start = False;
#endif
	if(EXTI_GetITStatus(EXTI_Line5))
	{
		EXTI_ClearITPendingBit(EXTI_Line5);
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_5))
		{
			/* 上升沿 */
			TIM_SetCounter(TIM3,0);
			InfraredHightime = 0;
		}
		else
		{
			/* 下降沿 */
			InfraredHightime = TIM_GetCounter(TIM3);
			if(InfraredHightime>400 && InfraredHightime<500)
			{
#if   !Continuous				
				start = True;
#endif				
				irdata = 0;
			}
#if   !Continuous
			else if(start)
			{
				if(0)
				{}
#endif
				else if(InfraredHightime>40 && InfraredHightime<72)
				{
					irdata <<= 1;
					irdata |= 0;
				}
				else if(InfraredHightime>150 && InfraredHightime<186)
				{
					irdata <<= 1;
					irdata |= 1;
				}
				else if((InfraredHightime>4000) || (InfraredHightime<220))
				{			
#if   !Continuous
					start = False;
#endif
						InfraredData.sid = irdata>>24;
						InfraredData.nsid = irdata>>16;
						InfraredData.opcode = irdata>>8;
						InfraredData.nopcode = irdata>>0;
						InfraredData.ismark = True;
				}
#if   !Continuous
			}
#endif	
		}
	}
}

infrared.h

#ifndef   __INFRARED_H
#define   __INFRARED_H

#include "stm32f10x.h"

#define   False    0
#define   True     1

#define   Continuous    False

typedef struct
{
	uint8_t sid;//System identification code
	uint8_t nsid;//System identification code inverse code
	uint8_t opcode;//operation code
	uint8_t nopcode;//operation code inverse code
	_Bool ismark;//Infrared switching mark
}infrared_t;

extern infrared_t InfraredData;

void InfraredInit(void);

#endif

main.c

#include "stm32f10x.h"
#include "infrared.h"
#include "usart.h"

uint16_t Systime;
void EstimateOpcode(uint8_t opcode);
int main(void)
{
	//SysTick_Config(72000000 / 1000);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	UsartInit(115200);
	InfraredInit();
	printf("红外测试程序\r\n");
  while (1)
  {
	  if(InfraredData.ismark)
		{
			InfraredData.ismark = False;			
			EstimateOpcode(InfraredData.opcode);
			printf("读取的值%.2x\r\n",InfraredData.opcode);
		}
  }
}
void EstimateOpcode(uint8_t opcode)
{
	switch(InfraredData.opcode)
	{
		case 162:
			printf("电源\r\n");
			break;
		case 226:
			printf("menu\r\n");
			break;
		case 34:
			printf("test\r\n");
			break;
		case 2:
			printf("+\r\n");
			break;
		case 194:
			printf("return\r\n");
			break;
		case 224:
			printf("|<<\r\n");
			break;
		case 168:
			printf(">\r\n");
			break;
		case 144:
			printf(">>|\r\n");
			break;
		case 104:
			printf("0\r\n");
			break;
		case 152:
			printf("-\r\n");
			break;
		case 176:
			printf("c\r\n");
			break;
		case 48:
			printf("1\r\n");
			break;
		case 24:
			printf("2\r\n");
			break;
		case 122:
			printf("3\r\n");
			break;
		case 16:
			printf("4\r\n");
			break;
		case 56:
			printf("5\r\n");
			break;
		case 90:
			printf("6\r\n");
			break;
		case 66:
			printf("7\r\n");
			break;
		case 74:
			printf("8\r\n");
			break;
		case 82:
			printf("9\r\n");
			break;
		default:
			printf("unknown\r\n");
			break;
	}
}

结语

关于解码作者还想到一种通过定时器输入捕获的方式进行解码,等作者拖延症结束了编写完再发上来吧。
特别说明,使用的遥控器不同,操作码可能就不一样以及高电平持续时间可能会有误差,这个需要自己自行测试即可。

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Arduino红外接收解码转发一体是一种功能强大的设备,它可以接收红外信号并解码,然后将解码后的信号转发到其他设备。 首先,Arduino红外接收模块可以接收红外线传输的信号。它能够感应到红外线的发射器发出的信号,并将其接收到。 其次,这个模块还具有解码功能。它可以解码接收到的红外信号,将其转换成数字或其他可识别的格式。这个功能对于控制其它设备非常有用,例如控制电视机、空调等。 最后,Arduino红外接收解码转发一体还可以将解码后的信号转发到其他设备。它可以通过输出接口将解码后的信号传递给其他设备,进而实现远程控制或信息传递的功能。 总结来说,Arduino红外接收解码转发一体设备是一种可编程的电子模块,具备接收红外信号、解码信号和转发信号的功能。它可以用于很多领域,例如智能家居、遥控器、无线通信等。这种设备的使用极大地提升了红外控制的便捷性和可扩展性。 ### 回答2: Arduino 红外接收解码转发一体是指通过使用Arduino开发板和红外接收模块实现对红外信号的接收解码和转发功能的集成设计。 首先, 需要连接红外接收模块到Arduino的数字IO引脚上。接收模块能够接收来自红外遥控器发送的红外信号,将接收到的信号转换为电信号输入到Arduino开发板上。 接着, Arduino通过编程使用红外库来解码接收到的信号。红外库通常包含了各种红外编码解码协议,例如NEC、Sony等。根据接收到的信号编码,可以通过红外库提供的函数来解码信号, 获取按下的按钮信息等。 最后, 当信号被解码之后,可以通过编程来控制其他设备的状态转换或执行相应的动作。比如,可以通过Arduino的数字IO引脚来控制LED的开关、驱动电机、改变显示屏等。 整个过程中,Arduino的编程起到了关键的作用。我们需要编写代码来控制红外接收模块的引脚接收信号,使用红外库来解码信号,并根据解码结果控制其他设备的状态转换。 通过这种方式,我们可以实现红外信号的接收解码和转发功能的一体化设计。这种集成设计可以广泛应用于遥控器、家庭自动化、智能家居等领域,为我们的生活带来更多的便利性和智能化。 ### 回答3: Arduino红外接收解码转发一体是指在Arduino开发板上集成了红外接收解码和转发功能的一种设计。通常情况下,利用红外接收模块可以接收解码来自红外遥控器发送的信号,而红外发射模块可以将解码后的信号通过红外光线发送出去。 在Arduino上实现红外接收解码转发一体的过程,首先需要连接红外接收模块和红外发射模块到Arduino开发板上。红外接收模块通过数据线连接到Arduino的数字引脚,而红外发射模块则通过数字引脚连接到Arduino。 接下来,在Arduino的编程环境中,可以使用红外接收库和红外发射库来实现红外接收解码和转发的功能。通过调用相应的函数,可以读取红外遥控器发送的信号,同时对信号进行解码解码后的信号可以通过红外发射模块发送出去,实现转发的功能。 这样的设计可以在很多应用场合中发挥作用。例如,可以将其应用在智能家居系统中,通过红外接收模块接收来自遥控器的指令,然后解码并转发到其他设备,如电视、空调等,实现对其的控制。另外,还可以将其应用在自动化系统中,比如利用红外接收模块接收红外传感器发送的信号,然后解码并根据不同的信号进行相应的动作。 总之,Arduino红外接收解码转发一体的设计,在实际应用中具有很大的灵活性和可扩展性,可以方便地实现红外信号的接收解码和转发功能,并且可以根据具体的需求进行编程定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值