GPIO模拟时序控制外设4——红外发射管

前言

上一篇介绍了使用GPIO模拟时序实现I2C协议的功能,本文继续使用GPIO模拟的方式来实现一个平时生活中常用的模块——红外发射管的驱动,红外在家电的应用中十分广泛,空调、电视、投影等都是通过红外遥控来实现的。

红外发射管简介

红外发射管实物就是下图中左边的红框内的器件,右侧的是红外接收管。
在这里插入图片描述
大家拿到红外发射管后,第一反应可能就是这玩儿意和LED灯长得一模一样啊,其实,不光长得一样,其的工作原理也是一样,就是通过一定的规律给电平,点“亮”和熄灭红外发射管来产生红外光信号,这个红外光信号被接收管接受处理后,就会产生对应的电信号,然后用户接收和处理这个电信号用来控制不同的外设即可。只不过红外发射管的波长超过了我们肉眼可见的波段,我们平常事无法观察到的。如下图:我们肉眼可见的光波段就是380nm----760nm,而这个红外发射管的波长是940nm。
在这里插入图片描述
在这里插入图片描述
当然,如果实在是想看见点亮效果,也可以把周围的灯都关了,找一个比较黑的环境,用手机摄像头就可以看见红光。
在这里插入图片描述

NEC协议

上面提到了,红外发射管用的是一种特殊的方式进行数据发送,具体的发送格式需要参考红外接收管的芯片手册以及使用到的具体通信协议了,这里接收管使用的是HS0038,通信协议是NEC。

HS0038

先来看看HS0038的手册是怎么描述的,如下图所示,可以知道,当接收到的输入红外光是一个频率为38khz,占空比为50%,持续时间为500us-700us的PWM波形时,HS0038的输出端就会产生一个低电平,而当输入的红外光不是此规格的信号时,HS0038就会输出一个高电平。
在这里插入图片描述
来个实际波形分析一下:
如下图所示:D1是红外发射管发射出的光信号,D0是红外接收管根据输入信号产生的输出信号,可以看出,当D1的波形变成了PWM时,D0输出低电平,而D1输出不是PWM时,D0输出就是高电平。
在这里插入图片描述

NEC 的逻辑“1”与逻辑“0”

为啥我上面一直说的HS0038的输出是高低电平而不是逻辑0和逻辑1呢?
还记得之前驱动WS2812B与DHT11的时候,他们的逻辑0与逻辑1并不是简单的对应高低电平,这里也是如此,NEC协议中的逻辑0与逻辑1也不是简单的高低电平,而是有不同时间段的高低电平组合而成,其中:
逻辑“0”是由560us的低电平加560us的高电平组成,
逻辑“1”是由560us的低电平加1690us的高电平组成,
再结合下面的这个逻辑分析仪的图大家就可以看懂了,注意最下面绿色的解码,第一段低电平与第一段高电平组成了第一个逻辑0,
第二段低电平与第二段高电平又组成了一个逻辑0,
而第三段的低电平与第三段高电平组成的是逻辑1,
在这里插入图片描述
因为红外传输的工程中大部分设备都是支持NEC格式的,所以我们发射管端也要对应这个NEC码的时序做出调整,当需要输出逻辑1时,就要使用到下图的前半段时序,而输出逻辑“0”时,就需要使用到下图的后半段时序:
原文链接——http://t.csdn.cn/LoC2r
在这里插入图片描述
整个数据传输动态过程可以看下面的动图:
单片机控制开关管按照逻辑“0”与逻辑“1”的时序来控制红外发射管的点亮与关闭,而红外接收管接收到红外发射管的信号后就会输出对应的高低电平信息,使用MCU进行捕获处理这部分信号就可以了。
在这里插入图片描述

NEC的数据帧格式

再弄清楚了NEC协议的逻辑“0”与逻辑“1”后,就要知道其数据帧的具体格式了,为了进一步提高数据的稳定性,NEC码在传输的过程中对于数据帧也有着很高的要求,具体帧格式如下:
在这里插入图片描述
需要注意一点,前面的数据通信都是高位在前,高位先发,此处的NEC是低位在前,低位先发。

同步码头(引导码/起始码)、地址码(遥控ID)、地址反码、控制码(键值)、控制反码。
同步码、地址码(遥控ID)、地址反码、控制码(键值)、控制反码
同步码由一个 9ms 的低电平和一个 4.5ms 的高电平组成
如果接收到同步,说明有红外数据进来

同步码 + 8位地址码+ 8位地址码反码+ 8位控制码 + 8位控制码反码
红外接收每一次接收到数据都是32位

实际的数据:

帧头地址码地址码反码命令命令反码
9ms 的低电平+ 4.5ms 的高电平8位8位8位8位
9ms 的低电平+ 4.5ms 的高电平1011 01110100 10000110 01101001 1001

在这里插入图片描述
除此之外还有一个连续发送的数据帧格式,这里就不做介绍了,有需要的自己去研究一下吧。

编程思路

搞清楚了红外发射管与接收管的通信过程以及其数据帧的格式后,接下来就可以开始编程了,本文先解决红外发射管的代码,接收管的使用留到下一篇介绍GPIO复用功能的时候再说。

1. GPIO管脚

首先第一步,二话不说,直接看原理图,找到GPIO是PB7,前面分析了,在发送红外光的时候,需要发送一段频率为38khz,占空比位50%,持续时间长度为560us的PWM,来使得红外接收管输出低电平,一般来说最好的解决方案就是使用定时器来产生PWM来实现低电平,当时间到了后再将GPIO口拉低不输出PWM即可实现
这里选择PB7管脚是可以作为定时器4的通道2来使用的,但是有一个问题,在实际使用过程中定时器4另有它用;所以没法了,只能使用GPIO模拟的办法来实现红外发射管的功能了,这里就需要模拟出一段PWM波形,当然是使用推挽模式配合延时来实现。
在这里插入图片描述
对于PWM实现的方案,这里给大吉留几个链接,供大家参考。
STM32 NEC红外遥控器解码——
基于STM32f103c8t6的红外接收发送
除此之外还有几篇写的很好地博客也给大家贴在这
STM32入门开发: 制作红外线遥控器(智能居家-万能遥控器)
在这里插入图片描述
GPIO初始化代码:

/************************************************
函数功能:红外发送控制码
函数名:Infrared_Send_Init
函数形参:None
函数返回值:
备注:  PB7
**************************************************/
void Infrared_Send_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;                       // 定义一个GPIO_InitTypeDef类型的变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   // 允许GPIOB时钟
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;                  // GPIO_Pin_7
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;           // 通用推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;          // 50MHz速度
	GPIO_Init(GPIOB, &GPIO_InitStruct);
	
	GPIO_ResetBits(GPIOB, GPIO_Pin_7);                      //PB7拉低
}

找到实现方案后,就该具体执行了,对于这类数据帧比较复杂的通信方式,在模拟其时序的时候一定记得从下往上来写,先搞定各个部分,然后再拼接起来组成一整个时序。
整个数据帧无非就是以下几个内容组成,
1.同步头,2.逻辑“0”与逻辑“1”;而且逻辑0与逻辑1还可以进一步细分为低电平和高电平,也就是一个PWM,一个非PWM。那么接下来就一个一个的实现。

2. 模拟同步头

由于接收管的同步头是9ms的低电平加上4.5ms的高电平,那么根据转换方式可以知道,发射管的同步头是9ms的38khz、50%占空比的PWM加上4.5ms的低电平。
在这里插入图片描述
38khz的PWM,一个脉冲的时长为1/38 000=26.3us;
占空比50%,则输出高电平的时间:26.3/2=13.15us由于STM32F103C8T6的系统滴答延时最多支持到us级别,所以这里把小数点后的给省略,直接高低电平各自延时13us。
而9ms的PWM一共有9ms/26=346个。
于是代码就有了:

/************************************************
函数功能:红外发送同步头
函数名:NEC_IE_Start
函数形参:None
函数返回值:
备注:  
// ①引导码:载波发射9ms,不发射4.5ms
**************************************************/
//------------------------------------------------------------
void NEC_IE_Start(void)
{
	u16 i;
// 载波发射 9ms ≈ 26.3us * 346
	for(i=0;i<346;i++) 
	{
		PBout(7)=1;	// IE抬高,发射红外光
		Systick_Delay_us(13);	// 延时13us
		PBout(7)=0;;	// IE拉低,不发射红外光
		Systick_Delay_us(13);	// 延时13us
	}
	// 载波不发射 4.5ms ≈ 26.3us * 171
	for(i=0;i<171;i++)
	{
		PBout(7)=0;	// IE拉低,不发射红外光
		Systick_Delay_us(26);	// 延时26us
	}
}

3.发送逻辑“0”与逻辑“1”

逻辑“0”与逻辑“1”的共有部分是560us的PWM波形,不同之处在于后面的部分,
在这里插入图片描述
先看逻辑“1”,除了560us的PWM,它还需要2.25ms-560us=1690us的低电平,PWM还是参考上面的思路,于是发送逻辑“1”的代码就有了:

/************************************************
函数功能:红外发送逻辑“1”
函数名:NEC_IE_Send_one
函数形参:None
函数返回值:
备注:  
// NEC协议数据"1" = 载波发射0.56ms + 载波不发射1.68ms
**************************************************/
//-------------------------------------------------
void NEC_IE_Send_one(void)
{
	u8 i;
	// 载波发射0.56ms ≈ 26.3us * 21
	//-------------------------------
	for(i=0;i<22;i++)
	{
		//26.3us(载波发射周期)占空比50%
		//------------------------------------
		PBout(7)=1;    // IE抬高,发射红外光
		Systick_Delay_us(13);	// 延时13us
		
		PBout(7)=0;  // IE拉低,不发射红外光
		Systick_Delay_us(13);	// 延时13us
		//------------------------------------
	}
	
	// 载波不发射1.69ms ≈ 26us * 65
	//--------------------------------
	for(i=0;i<65;i++)
	{
		//26us(载波不发射周期)
		//------------------------------------
		PBout(7)=0;	// IE拉低,不发射红外光
		Systick_Delay_us(26);	// 延时26us
	}
}

同样的逻辑“0”的思路也差不多,直接给出代码:


/************************************************
函数功能:红外发送逻辑“0”
函数名:NEC_IE_Send_zero
函数形参:None
函数返回值:
备注:  
// NEC协议数据"0"= 载波发射0.56ms + 载波不发射0.56ms
**************************************************/
//-------------------------------------------------
void NEC_IE_Send_zero(void)     
{
	u8 i;
	
	// 载波发射0.56ms ≈ 26.3us * 21
	//-------------------------------
	for(i=0;i<22;i++)
	{
        //26.3us(载波发射周期)
		//------------------------------------
		PBout(7)=1;	// IE抬高,发射红外光
		Systick_Delay_us(13);	// 延时13us                       
											
		PBout(7)=0;	// IE拉低,不发射红外光
		Systick_Delay_us(13);	// 延时13us
		//------------------------------------
	}

	
	// 载波不发射0.56ms ≈ 26.3us * 21
	//-------------------------------
	for(i=0;i<21;i++)
	{
        //26.3us(载波不发射周期)
		//------------------------------------
		PBout(7)=0;	// IE拉低,不发射红外光
		Systick_Delay_us(26);	// 延时26us
		//------------------------------------
	}
}

发送一个字节数据

搞定了逻辑“0”与逻辑“1”之后,下一步自然是封装一个可以一次发送8个位也就是一字节的函数。这里需要注意的是低位先发。
在这里插入图片描述
于是代码如下:

/************************************************
函数功能:红外发送一个字节
函数名:NEC_IE_One_Data
函数形参:u8 IE_One_Data
函数返回值:
备注:  发送一个字节的数据,一次发8位,低位在前。
**************************************************/
//----------------------------------------------------------------------------------------------
void NEC_IE_One_Data(u8 IE_One_Data)
{
	u8 i;
	
	for(i=0;i<8;i++)
	{
		if( IE_One_Data & 0x01 )
			NEC_IE_Send_one();
		else
			NEC_IE_Send_zero();
			
		IE_One_Data>>=1;
	}
}

发送一帧数据

一帧数据格式在前面已经介绍了,这里根据帧格式配合上面的函数做一个组合就可以了。
代码如下:


/************************************************
函数功能:发送NEC 一帧数据
函数名:NEC_IE_code_message
函数形参:u8 IE_One_Data
函数返回值:
备注: 
// 将一帧数据调制为NEC协议规定的红外载波发射出去
// 一帧数据格式:低位在前,由低到高发送8位数据
// 这帧数据是:②8位用户码字节(8位) / ③8位用户码反码(8位) / ④8位数据码 / ⑤8位数据码的反码
**************************************************/
void NEC_IE_code_message(u8 user_code_8bit, u8 data_code_8bit)
{
	// ①引导码:载波发射9ms,不发射4.5ms
	NEC_IE_Start();
	//------------------------------------------------------------
	//------------------------------------------------------------
	// ②8位用户码	:8位数据
	NEC_IE_One_Data(user_code_8bit);
	
	// ③8位用户码的反码:8位数据
	NEC_IE_One_Data(~user_code_8bit);
	
	// ④8位数据码 :8位数据
	NEC_IE_One_Data(data_code_8bit);
	
	// ⑤8位数据码的反码:8位数据
	NEC_IE_One_Data(~data_code_8bit);
	//------------------------------------------------------------
	// ⑥结束码‘0’
	//--------------
	NEC_IE_Send_zero();
	//--------------
}

结束码

关于结束码,由于32位数据发送完毕后,不管最后一位的逻辑是0还是1,末尾都是PBout(7)=0; // IE拉低,不发射红外光;理论来说,这种情况不额外添加结束码是可行的;但是笔者尝试了一下,不再末尾加一个发送逻辑“0”的结束码的话,逻辑分析仪无法解析出数据,为了能够正常解析出数据还是在发送外32位数据后加上一句NEC_IE_Send_zero()。
需要注意,实际上的遥控器大部分是没有这个结束信号的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

而对于连续码的时序,如下图,有兴趣的话可以自己尝试,调通后可以投食一下,我想白嫖。
在这里插入图片描述
既然搞定了红外发送的基本用法,最大的想法自然是控制空调之类的设备了,但是需要注意,各个厂家的空调的协议不太一样,需要在上面代码的基础上进一步修改才行。
具体的介绍大家参考这些大佬的——
STM32入门开发: 制作红外线遥控器(智能居家-万能遥控器)
格力空调红外编码解析
STM32解析美的空调红外遥控器
格力空调红外编码
在这里插入图片描述

现象

这里笔者还没去倒腾空调的编码,只是实现了简单的功能,最后捕捉到的实际波形和解析出来数据如下:
在这里插入图片描述

总结

关于使用GPIO模拟时序驱动红外发射管的介绍就先记录到这,至于空调的控制,这个先鸽了,或者有做出来的可以踢我一下。文中如有不足欢迎批评指正。

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 红外接收管电路38kHz是一种常用于红外遥控技术的电路设计。该电路设计主要有两个部分,一个是红外接收管(IR Receiver),另一个是38kHz调制解调电路。 红外接收管是一种特殊的光电传感器,可以检测来自红外遥控器发送的红外光信号。它通常由一个红外光敏二极管和一个放大器组成。当红外光照射到红外光敏二极管上时,它会产生电流。放大器会增加这个电流信号的幅度,以便进一步处理。 38kHz调制解调电路的主要作用是按照一定频率对红外光信号进行调制和解调。在红外遥控中,通常使用38kHz的频率进行调制,以确保红外接收管只接收到特定频率的红外光信号。调制时,通过对红外光信号进行调制,可以使其带有特定频率的脉冲。解调时,通过识别特定频率的脉冲来还原原始的红外光信号。 整个电路的工作原理如下:当红外遥控器按下某个按钮时,遥控器中的红外发射器会向外发射一定频率的脉冲红外光信号。接收器中的红外接收管会接收到这个红外光信号,并将其转换为相应的电流信号。38kHz调制解调电路会识别出38kHz频率的脉冲,并解码出遥控器所发送的具体指令。然后,这个指令可以被传递到其他电路中,用于控制相应的设备。 红外接收管电路38kHz在家庭电器、汽车电子、安防系统等众多领域中得到广泛应用,为人们带来了便利。它充分利用了红外光的特性,通过合理的电路设计,实现了遥控技术的传输和控制功能。 ### 回答2: 红外接收管电路38kHz是一种用来接收红外信号的电路。它通常由红外接收管、滤波电路以及解码电路组成。 首先,红外接收管是一个能够接收红外信号并将其转化为电信号的器件。它是一种光电二极管,具有特定的红外辐射灵敏度。当红外信号入射到红外接收管中时,它会产生电压信号。 其次,滤波电路用于滤除红外接收管产生的电压信号中的干扰信号,保留所需的38kHz频率信号。一般情况下,这个滤波电路由一个带通滤波器组成,其中心频率设置为38kHz,带宽较窄以滤除其他频率干扰。 最后,解码电路接收经过滤波的38kHz信号并将其解码为数字信号。解码电路的设计可以根据具体的应用需求来选择,常见的解码方法包括脉宽调制(PWM)和脉冲位置调制(PPM)等。 红外接收管电路38kHz广泛应用于红外遥控器、红外传感器等领域。在红外遥控器中,通过发射38kHz的红外信号,接收端的红外接收管电路可以接收到这个信号并解码为相应的操作指令。在红外传感器中,红外接收管电路可以感知周围物体发射的红外信号,从而实现物体检测和反馈等功能。 总之,红外接收管电路38kHz是一种用于接收红外信号并解码的电路,其主要通过红外接收管、滤波电路和解码电路来实现。它在红外遥控、红外传感器等应用中起到了重要的作用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值