Arduino 入门学习笔记(十八):INFRARED_RECEPTION 实验

Arduino 入门学习笔记(十八):INFRARED_RECEPTION 实验

开发板:正点原子ESP32S3
没有LCD屏可以用串口打印进行测试
例程源码在文章顶部可免费下载

1. 红外遥控介绍

1.1 红外遥控技术介绍

红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。 由于红外线遥控不具有像无线电遥控那样穿过障碍物去控制被控对象的能力,所以,在设计红外线遥控器时,不必要像无线电遥控器那样,每套(发射器和接收器)要有不同的遥控频率或编码(否则,就会隔墙控制或干扰邻居的家用电器),所以同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。这对于大批量生产以及在家用电器上普及红外线遥控提供了极大的方便。由于红外线为不可见光,因此对环境影响很小,再由红外光波动波长远小于无线电波的波长,所以红外线遥控不会影响其他家用电器,也不会影响临近的无线电设备。

1.2 红外器件特性

红外遥控的情景中,必定会有一个红外发射端和红外接收端。在本实验中,正点原子的红外遥控器作为红外发射端,红外接收端就是板载的红外接收器,实物图可以查看后面小节原理图部分。要使两者通信成功,收/发红外波长与载波频率需一致,在这里波长就是 940nm,载波频率就是 38kHz。
红外发射管也是属于二极管类,红外发射电路通常使用三极管控制红外发射器的导通或者截至, 在导通的时候,红外发射管会发射出红外光,反之,就不会发射出红外光。虽然我们用肉眼看不到红外光,但是我们借助手机摄像头就能看到红外光。但是红外接收管的特性是当接收到红外载波信号时, OUT 引脚输出低电平;假如没有接收到红外载波信号时, OUT 引脚输出高电平。
红外载波信号其实就是由一个个红外载波周期组成。在频率为 38KHz 下,红外载波周期约等于 26.3us(1s / 38KHz ≈ 26.3us)。在一个红外载波发射周期里,发射红外光时间 8.77us 和不发射红外光 17.53us,发射红外光的占空比一般为 1/3。相对的,整个周期内不发射红外光,就是载波不发射周期。在红外遥控器内已经把载波和不载波信号处理好,我们需要做的就是识别遥控器按键发射出的信号,信号也是遵循某种协议的。

1.3 红外编解码协议介绍

红外遥控的编码方式目前广泛使用的是: PWM(脉冲宽度调制) 的 NEC 协议和 Philips PPM(脉冲位置调制) 的 RC-5 协议的。开发板配套的遥控器使用的是 NEC 协议,其特征如下:

  1. 8 位地址和 8 位指令长度;
  2. 地址和命令 2 次传输(确保可靠性);
  3. PWM 脉冲位置调制,以发射红外载波的占空比代表“0”和“1”;
  4. 载波频率为 38Khz;
  5. 位时间为 1.125ms 或 2.25ms;
    在 NEC 协议中,如何为协议中的数据‘0’或者‘1’?这里分开红外接收器和红外发射器。
    红外发射器:
    发送协议数据‘0’ = 发射载波信号 560us + 不发射载波信号 560us
    发送协议数据‘1’ = 发射载波信号 560us + 不发射载波信号 1680us
    红外发射器的位定义如下图所示:
    在这里插入图片描述
    红外接收器:接收到协议数据‘0’ = 560us 低电平 + 560us 高电平
    接收到协议数据‘1’ = 560us 低电平 + 1680us 高电平
    红外接收器的位定义如下图所示:
    在这里插入图片描述

NEC 遥控指令的数据格式为:同步码头、地址码、地址反码、控制码、控制反码。同步码由一个 9ms 的低电平和一个 4.5ms 的高电平组成,地址码、地址反码、控制码、控制反码均是8 位数据格式。按照低位在前,高位在后的顺序发送。采用反码是为了增加传输的可靠性(可用于校验)。

1.4 IRremoteESP8266 库介绍

基于对红外编解码协议介绍,我们是可以通过识别 IO 的状态进而解码。但是在使用 Arduino开发时,更推荐使用别人写好的库,这里我们要使用的是“IRremoteESP8266”库。
IRremoteESP8266 库支持接收并解码红外遥控信号,也支持编码并发送红外信号。该库支持多种不同的红外协议,包括 NEC、 Sony、 RC5 和 RC6 等。
接下来,我们就来看一下如何下载 IRremoteESP8266 库包。
该库可以在 Arduino IDE 中库管理搜索到,具体下载操作如下图所示:
在这里插入图片描述
IRremoteESP8266 库提供有 28 个示例工程,最快速了解库使用方法莫过于查看示例工程了,大家可以自行查看学习,下载看现象。
若要使用 IRremoteESP8266 库的函数,需要先定义一个 IRrecv 对象,具体操作如下:

IRrecv irrecv(pin);

其中 pin 是连接到红外接收器输出引脚的数字引脚号。
此外,还需要定义一个用于存储接收红外按键值的变量,如下:

decode_results results;

接下来,介绍本例程用到 IRremoteESP8266 库的函数。
第一个函数: enableIRIn 函数,该函数功能是初始化红外解码,启动红外接收功能。

void IRrecv::enableIRIn(const bool pullup);

参数 pullup 为是否设置红外接收引脚上拉,默认可以不填该传参表示不用上拉。
无返回值。
第二个函数: decode 函数,该函数的功能是解码从红外遥控器接收到的信号,并将结果存储在一个 decode_results 类型的对象中。

bool IRrecv::decode(decode_results *result, irparams_t *save, uint8_t max_skip,
uint16_t noise_floor);

只需要关注参数 results 即可, results 为一个 decode_results 类的对象。
返回值:解码成功返回 1,失败返回 0。
第三个函数: resume 函数,该函数的功能是接收下一个编码。

void IRrecv::resume(void);

无返回值。
注意: resume 不可忽略,应与 decode 函数配对使用,否则,只能读取一个红外按键键值,而不再接收新的按键值。

2. 硬件设计

2.1 例程功能

在 LCD 上显示一些实验信息之后,即进入等待红外触发,如果接收到正确的红外信号,则解码,并在 LCD 上显示键值和所代表的意义。 LED 闪烁用于提示程序正在运行。

2.2 硬件资源

  • LED 灯
    LED-IO1
  • USART0
    U0TXD-IO43
    U0RXD-IO44
  • XL9555
    IIC_SDA-IO41
    IIC_SCL-IO42
  • SPILCD
    CS-IO21
    SCK-IO12
    SDA-IO11
    DC-IO40(在 P5 端口,使用跳线帽将 IO_SET 和 LCD_DC 相连)
    PWR- IO1_3(XL9555)
    RST- IO1_2(XL9555)
  • 红外接收头
    REMOTE_IN-IO2
  • 正点原子红外遥控器

2.3 原理图

红外接收头相关原理图,如下图所示:
在这里插入图片描述
需要注意: REMOTE_IN 和 SD 卡的片选引脚共用了 IO2,所以它们不可以同时使用,需要分时复用。
开发板配套的红外遥控器外观如图所示:
在这里插入图片描述
开发板上接收红外遥控器信号的红外管外观如图 所示。使用时需要遥控器有红外管的一端对准开发板上的红外管才能正确收到信号。
在这里插入图片描述

3. 软件设计

3.1 程序流程图

下面看看本实验的程序流程图:
在这里插入图片描述

3.2 程序解析

REMOTE 驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。 REMOTE 驱动源码包括两个文件: remote.cpp 和 remote.h。
下面我们先解析 remote.h 的程序。 对红外接收的引脚做了相关定义。

#define RMT_RX_PIN 2

我们选择使用 IO2 作为红外接收管的引脚。
下面我们再解析 remote.cpp 的程序,前面提及到需要定义红外接收对象以及接收红外数据的变量,代码如下:

IRrecv irrecv(RMT_RX_PIN);
decode_results results;

接下来,看一下红外接收初始化函数 remote_init,代码如下:

/**
* @brief 红外遥控初始化
* @param 无
* @retval 无
*/
void remote_init(void)
{
	irrecv.enableIRIn();
}

remote_init 函数主要调用 enableIRIn 函数初始化红外解码,启动红外接收。
接下来,介绍一下红外按键扫描函数 remote_scan,代码如下:

/**
* @brief 处理红外按键
* @param 无
* @retval 0:没有任何按键按下
* 其他:按下的按键键值
*/
uint8_t remote_scan(void)
{
	uint8_t rmt_data = 0; /* 红外遥控按键键值 */
	uint8_t remote_key = 0; /* 提取控制码 */
	uint32_t raw_data = 0; /* 原始数据 */
	if (irrecv.decode(&results)) /* 对红外数据进行解码 */
	{
		raw_data = results.value;
		remote_key = (uint8_t)(raw_data >> 8); /* 提取控制码 */
		if ((remote_key != 0xFF) && (remote_key != 0)) /* 证明已经获得有效键值 */
		{
			rmt_data = remote_key;
		}
		irrecv.resume(); /* 接收下一个值 */
		return rmt_data;
	}
	return 0;
}

该函数主要就是调用 decode 函数获取红外数据,然后进行解析,提取控制码,最终控制码作为返回值进行返回。
15_infrared_reception.ino 代码
在 15_infrared_reception.ino 里面编写如下代码:

#include "led.h"
#include "uart.h"
#include "xl9555.h"
#include "spilcd.h"
#include "remote.h"
uint8_t rmt_key;
char *str = "0";
/**
* @brief 当程序开始执行时,将调用 setup()函数,通常用来初始化变量、函数等
* @param 无
* @retval 无
*/
void setup()
{
	led_init(); /* LED 初始化 */
	uart_init(0, 115200); /* 串口 0 初始化 */
	xl9555_init(); /* IO 扩展芯片初始化 */
	lcd_init(); /* LCD 初始化 */
	remote_init(); /* 红外接收初始化 */
	lcd_show_string(30, 50, 200, 16, LCD_FONT_16, "ESP32-S3", RED);
	lcd_show_string(30, 70, 200, 16, LCD_FONT_16, "REMOTE TEST", RED);
	lcd_show_string(30, 90, 200, 16, LCD_FONT_16, "ATOM@ALIENTEK", RED);
	lcd_show_string(30, 110, 200, 16, LCD_FONT_16, "KEYVAL:", RED);
	lcd_show_string(30, 130, 200, 16, LCD_FONT_16, "SYMBOL:", RED);
}
/**
* @brief 循环函数,通常放程序的主体或者需要不断刷新的语句
* @param 无
* @retval 无
*/
void loop()
{
	rmt_key = remote_scan();
	if (rmt_key)
	{
		lcd_show_num(86, 110, rmt_key, 3, LCD_FONT_16, BLUE); /* 显示键值 */
		switch (rmt_key) /* 判断键值 */
		{
			case 0: str = "ERROR"; break;
			case 162: str = "POWER"; break;
			case 98: str = "UP"; break;
			case 2: str = "PLAY"; break;
			case 226: str = "ALIENTEK"; break;
			case 194: str = "RIGHT"; break;
			case 34: str = "LEFT"; break;
			case 224: str = "VOL-"; break;
			case 168: str = "DOWN"; break;
			case 144: str = "VOL+"; break;
			case 104: str = "1"; break;
			case 152: str = "2"; break;
			case 176: str = "3"; break;
			case 48: str = "4"; break;
			case 24: str = "5"; break;
			case 122: str = "6"; break;
			case 16: str = "7"; break;
			case 56: str = "8"; break;
			case 90: str = "9"; break;
			case 66: str = "0"; break;
			case 82: str = "DELETE"; break;
		}
	lcd_fill(86, 130, 116 + 8 * 8, 170 + 16, WHITE); /* 清楚之前的显示 */
	lcd_show_string(86, 130, 200, 16, LCD_FONT_16, str, BLUE); /* 显示标记 */
	}
	LED_TOGGLE();
	delay(500);
}

在 setup 函数中,调用 led_init 函数完成 LED 初始化, uart_init 函数完成串口初始化,调用xl9555_init 函数完成 XL9555 初始化,调用 lcd_init 函数完成 LCD 屏初始化,调用 remote_init函数完成红外解码初始化,然后 LCD 显示实验信息。
在 loop 函数中,间隔 500 毫秒调用 remote_scan 函数获取红外数据并进行解析,然后在 LCD进行显示。

4. 下载验证

第一次编译的时候需要稍等片刻, 下载代码后, 可以看到 LCD 显示如下图所示:
在这里插入图片描述
此时,我们通过遥控器按下不同的按键,则可以看到 LCD 上显示了不同按键的键值和对应遥控器上的符号,如下图所示:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值