基于stm32实现红外遥控信号接收解码的详细步骤

这是我智能车库项目的第二部分,想看超声波测距的,可以找找我上一章的博客,想看步进电机的,可以关注我,等我的下一篇博客。

写在前面的话

之所以要写这段话,也是为了给初学者解释一个我在不了解红外通讯之前忽视的一个问题。

不知道有没有人像我一样。简单的以为想在自己的项目中加个红外通讯功能,就直接买来红外发射管和接收头,想着自己能从头到尾的搞定发射和接收两个部分。结果想做红外发射的时候却发现。困难重重,以至于拖了很久都无法进行下去。

说一下我踩坑以后的一些总结:
1、红外的通讯分为发送和接收两个部分。
2、发送部分主要由红外发射二极管实现,想要自己制作的话涉及到按键、红外发射二极管、控制芯片、放大电路之类的部分
3、接收部分只需要一个集成好的红外接收管,

重点!初学者,除非自己需要研究遥控器的制作。如果仅仅只是想在项目中添加红外遥控的功能的话,发射部分,一块钱的遥控器就可以解决问题了。本篇文章的内容是关于如何在stm32上实现红外接收功能的,代码改编自普中科技的红外遥控源码。我依然会详细写出所有步骤,有疑问的可在下方留言。

关于红外线

一句话解释清楚即可,这个不重要。
人的可见光根据波长的不同,波长从长到短分为红、橙、黄、绿、青、蓝、紫,比红光波长还长一定量的不可见光就是红外线。

硬件部分

1、开发板是普中科技的PZ6808L-F4 (stm32F407ZG芯片)
2、红外遥控器一个(NEC编码方式,不懂的看下文)
3、红外接收头(这几种外观不同,使用方法都是一样的,将凸起的面正对自己,左边的是数据管脚,中间的是VCC,右边的是GND)
基于stm32实现红外遥控信号接收解码的详细步骤_第1张图片

红外通讯过程详解

原理

红外接收头在收到遥控器发射的红外信号时为低电平,在没有信号的时候为高电平。而每一次电平的高低变换。称为一个脉冲

红外脉冲码的概念(重点)

一段有规律的,多次的红外脉冲,称为脉冲码。(一定要理解什么是脉冲码)
多解释一下,这个很重要。红外线发射一段时间,再关闭一段时间。(这个时间都是控制在几毫秒以内)接收头在有红外信号的时候为低电平,没有红外信号的时候为高电平。这信号一个高低变换称为一个脉冲。多个脉冲组合起来,就是一段脉冲吗
我们就是通过对数据管脚得到的脉冲的判断,来实现红对红外遥控的脉冲码进行解码的。
重点难点全部在如何实现对红外信号的解码的。所以一定要清楚的认识什么是红外脉冲码。

NEC红外脉冲码详解

红外遥控器发射的脉冲码并不是随意发射的,常用的有两种规范的脉冲编码方式:
1、NEC码
2、PPM码

所以开发红外设备必备知识,你所使用的红外遥控器的编码方式。
我所使用的是NEC编码方式的遥控器,这里也只教大家更常见的NEC的编码方式。
NEC码有两部分构成:
1、位定义(每一位是如何代表0或1的)
2、数据格式。(每一位的0或1代表什么)

NEC码的位定义

上面说到红外接收头在收到遥控器发射的红外信号时为低电平,在没有信号的时候为高电平。而每一次电平的高低变换。称为一个脉冲。

而NEC码规定:
先上图,根据图解释
这是接收部分的时序图:接收部分,低电平代表有红外信号,高电平代表没有红外信号
基于stm32实现红外遥控信号接收解码的详细步骤_第2张图片
NEC码规定:接收到的脉冲信号,低电平时间固定为0.56毫秒,如果高电平时间为1.125-0.56=0.56毫秒,则这个脉冲代表0;
而低电平的时间为0.56毫秒,高电平为2.25-0.56=1.69毫秒时。这个脉冲代表1。(注意:实际使用时间会有误差,所以不用准备判断具体时间,只需要在一个范围里去判断高电平时间即可。)
例如:判断高电平时间在1.2到1.8毫秒之间,为位1,
高电平在0.2到1毫秒之间,为位0;

NEC码的数据格式

由多个0或去组合起来,就组成一段数据,对于数据格式,NEC码中有明确规定
NEC 遥控指令的数据格式为:引导码、地址码、地址反码、控制码、
控制反码。
上图:
在这里插入图片描述
引导码:由一个 9毫秒 的低电平和一个 4.5毫秒 的高电平组成的脉冲,
地址码、地址反码、控制码、控制反码均是8 位数据格式。按照低位在
前,高位在后的顺序发送。
我们程序中所要做的,就是要在接收到红外信号以后,读取出这一段数据码来,这就是红外接收信号的解码。得到这个码以后,就可以做一些控制程序了。接下来就是程序部分

具体代码实现

代码前的准备

1、红外接收头的数据管脚接到stm32芯片的PA8管脚(我用的芯片型号是stm32f407g)
2、一定要清楚的知道NEC的数据位和数据格式,一定要清楚,才能知道步骤,才能明白自己在代码中要做什么。
3、红外的接收用外部中断的方式。感应到有红外信号的时候开启中断,在中断函数里实现解码。
3、准备一个红外遥控器
遥控器参数:
(1)NEC的编码方式
(2)载波频率为38k/Hz(这个我文中没有介绍,因为也不需要配置之类的,而且大部分红外遥控都是这个频率,所以不用深究,使用常见的遥控即可。)
基于stm32实现红外遥控信号接收解码的详细步骤_第3张图片

具体代码

注:代码面向新手,我尽量吧所有的代码用简单易懂的话写到注释里。

首先在stm32f4的库函数模板工程中,向工程中新建两个红外接收的文件hongwai.c和hongwai.h并添加到工程中。
hongwai.h中的代码

#ifndef _hongwai_H
#define _hongwai_H

#include "system.h"////位带操作的文件

//全局变量
extern  u32 hw_jsm;//存放获取到的红外接收码
extern  u8 hw_jsbz;//接收完成标志

//函数声明
void Hwjs_Init(void);
u8 HW_jssj(void);
void EXTI9_5_IRQnHandler(void);

#endif

hongwai.c中的代码内容为:
1、红外初始化函数Hwjs_Init() 其中包括管脚的初始化、中断的初始化
2、读取GPIOA_8管脚高电平时间函数 HW_jssj(void)
3、外部中断发生时的解码函数EXTI9_5_IRQHandler(void)

# include "hongwai.h"
#include "SysTick.h"//时钟延时函数头文件

u32 hw_jsm;//存放获取到的红外接收码
u8 hw_jsbz;//接收完成标志

void Hwjs_Init()//红外基本配置初始化函数
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO结构体变量
	EXTI_InitTypeDef  EXTI_InitStructure;//定义外部中断结构体变量
	NVIC_InitTypeDef NVIC_InitStructure;//定义中断结构体变量
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能端口A时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//使能外部中断时钟
	
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource8);//将GPIOA管脚映射到中断上
	
	//GPIO初始化
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //输入模式
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;//管脚设置A8
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化结构体
	
	EXTI_ClearITPendingBit(EXTI_Line8);//清除外部中断8的中断标志
	
	//外部中断初始化
	EXTI_InitStructure.EXTI_Line=EXTI_Line8;//外部中断线8
	EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//选择中断触发
	EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
	EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
	//中断初始化
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;//EXTI9_5中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;		//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		//使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}

//读取GPIOA_8管脚高电平时间函数,返回值为该管脚的高电平时间t t自加一次为20us
u8 HW_jssj(void)
{
	u8 t=0;//时间变量
	while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)==1)//判断为高电平则循环
	{
		t++;
		delay_us(20);
		if(t>250)//高电平时间过长,强制结束函数
		{
			return t;
		}
	}
	return t;
}

//外部中断8函数,用于对红外进行解码,并将解码后的数据存入全局变量hw_jsm
void EXTI9_5_IRQHandler(void)
{
	
	u8 Tim=0;//时间变量
	u8 ok=0;//判断数据是否有效的变量
	u8 DATA=0;//存储接收数据的值
	u8 Num=0;//用于判断是否接收完32位
	while(1)
	{
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)==1)//高电平到来
		{
			Tim=HW_jssj();//获取高电平
			if(Tim>=250)break;//如果高电平时间超时
			if(Tim>=200&&Tim<250)//如果高电平在4ms和5ms毫秒的有效时间之间
			{
				ok=1;
			}
			else if(Tim>=60&&Tim<90)//高电平在1.2到1.8毫秒之间
			{
				DATA=1;
			}else if(Tim>=10&&Tim<50)//高电平在0.2到1毫秒之间
			{
				DATA=0;
			}
			
			if(ok==1)//如果成功接收到引导码,则开始存放获取到的数据
			{
				//二进制按位操作,将DATA读取到的中读取的值存入
				hw_jsm<<=1;
				hw_jsm+=DATA;
				if(Num>=32)//判断是否接收完32位
				{
					hw_jsbz=1;//接收完成标志置一
					break;
				}
			}
			Num++;//每接收完一位累加一次,加到32接收完毕
		}
	}
	EXTI_ClearITPendingBit(EXTI_Line8);//清除外部中断8的中断标志
}


main()函数中的代码

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"//串口通讯头文件(需要将获取到的码通过串口输出到屏幕)
# include "hongwai.h"

int main()
{	
	u8 i=0;
	SysTick_Init(168);//延时函数初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
	LED_Init();//led灯控制函数初始化
	USART1_Init(9600);//串口初始化
	Hwjs_Init();//红外初始化
	
	
	
	while(1)//发生中断以后hw_jsm会自动保存红外的编码
	{
		if(hw_jsbz==1)//如果有接收到红外
		{
			hw_jsbz=0;//清除接收判断标志,以便下一次接收
			printf("红外接收码  %0.8X\r\n",hw_jsm);
			hw_jsm=0;//清除接收码内容,以便下一次接收
		}
		i++;
		if(i%20==0)
		{
			led1=!led1;
		}
		
		
		delay_ms(10);//延时
			
	}
}

结果演示

基于stm32实现红外遥控信号接收解码的详细步骤_第4张图片
还测试了一下,自己家的电视遥控器也可以哦,编码CD开头的就是电视遥控器的编码。

基于stm32实现红外遥控信号接收解码的详细步骤_第5张图片

结尾

获取到编码以后就可以实现红外遥控控制了。
以上就是红外接收的全部内容了,红外发射部分并没有涉及,红外通讯这部分比较复杂,需要理解好整个解码的过程步骤,否则很容易出现问题。代码我都尽量所有注释写上,还是遇到问题,或者想要源码的可以下方留言。觉得有用可以点赞支持,想观看步进电机的可以关注我,后续会写。谢谢观看!

你可能感兴趣的:(嵌入式,stm32)