红外模块详解

和红外有关的模块有很多,比如红外循迹,红外感应,红外发射,红外接收,红外对射,红外编解码等等。

今天我们要介绍的是红外编解码模块,它最常见的应用就是我们家里的电视、空调,当我们按下遥控器上的按钮时,红外信号从遥控器上的红外编解码模块发射,操作电视音量增大,空调温度降低等等。

1. 源码下载及前置阅读

本文首发 良许嵌入式网 :https://www.lxlinux.net/e/ ,欢迎关注!

本文所涉及的源码及安装包如下(由于平台限制,请点击以下链接阅读原文下载):

https://www.lxlinux.net/e/stm32/infrared-sensor-tutorial.html

如果你是嵌入式开发小白,那么建议你先读读下面几篇文章。

  • 了解不同的下载程序方法,为你的嵌入式开发提供更多选择:【STM32下载程序的五种方法:https://www.lxlinux.net/e/stm32/five-ways-to-flash-program-to-stm32.html】
  • 手把手让你掌握MDK的使用方式和技巧,助你更高效地进行开发:【一文教你使用MDK开发工具:https://www.lxlinux.net/e/stm32/mdk-development-tool-tutorial.html】
  • 从零开始轻松掌握STM32开发的必备指南:【零基础快速上手STM32开发(手把手保姆级教程):https://www.lxlinux.net/e/stm32/stm32-quick-start-for-beginner.html】

前期教程,没看过的小伙伴可以先看下。

  • 嵌入式基本功,为后续学习打下坚实的基础:【STM32串口接收不定长数据(接收中断+超时判断):https://www.lxlinux.net/e/stm32/stm32-usart-receive-data-using-rxne-time-out.html】

2. 红外编解码模块介绍

2.1 型号介绍

红外编解码模块使用特定的红外协议来确保设备之间的通信准确性和兼容性。常见的红外编解码协议包括 NEC、RC5、RC6 等。

我们今天介绍的是 NEC 红外编解码模块,型号是 YS-IRTM。

  • 红外发射头: 用于发射红外信号,波长为 940nm,频率为 38k,协议为 NEC 编码的红外信号。

  • 红外接收头:用于接收 NEC 红外信号,进而单片机进行分析解码操作。

  • 红外头扩展:该接口为红外发射头的扩展,可以连接多个红外发射头(常称红外发射模块),用于安放到不同的位置,实现多方位控制。

2.2 工作参数及引脚介绍

默认波特率是 9600。

YS-IRTMSTM32
GNDGND
RXDA2(串口2)/B10(串口3)
TXDA3(串口2)/B11(串口3)
5V5V

3. 红外编解码原理

我们今天介绍的红外编解码模块采用 NEC 编码,由引导码、用户码高位、用户码低位、数据码、数据反码五部分组成。

NEC 编码格式如下:

  1. 使用 38kHz 的载波频率。

  2. 引导码间隔为 9ms+4.5ms,用于同步发送方和接收方的时钟。

  3. 用户编码用于识别设备类型,比如识别不同的遥控器。

  4. 通过脉冲串之间的时间间隔来实现信号的调制(PWM)。

    • 逻辑「0」由 0.56ms 的 38kHz 载波和 0.565ms 的无载波间隔组成,周期1.125ms。

    • 逻辑「1」由 0.56ms 的 38kHz 载波和 1.69ms 的无载波间隔组成,周期2.25ms。

  5. 结束位由 0.56ms 的 38kHz 载波组成。

学习完原理,就进行我们的实践吧。

4. 通信示意图

实现目标是我们有一个三色 LED 灯,三个灯各自有特定的信号,遥控器/手机发送红外信号,红外编解码模块收到数据,若含绿灯信号,绿灯亮;再次发送绿灯信号,绿灯灭,黄灯和红灯设定和效果一样。

5. 编程准备

我们知道,NEC 红外信号编码由 1 个 16 位用户码(分为高、低 8 位)、1 个 8 位数据码和 1 个 8 位数据码的反码组成。格式如下:

「用户码高位、用户码低位、数据码、数据反码」

我们在做解码操作时,只需要将遥控器对准红外接收头,按下需要解码的按键,即可通过串口调试助手查看到解码的结果,结果输出为「用户码高位+用户码低位+命令码」三位。

在做编码发送时发送「地址+操作位+数据位1+数据位2+数据位3」即可。

所以在正式开始前,我们需要知道我们的遥控器/手机会发出怎样的红外信号。

5.1 硬件准备与连接

准备所需要的硬件如下:

  • 红外编解码模块:YS-IRTM
  • 遥控器:红外遥控器
  • 串口:USB 转 TTL

我红外遥控器用的是正点原子的,不一定要用同款,甚至有的手机也可以当作红外遥控器用。

5.2 红外接收,查看编码

先将红外编解码模块与 USB 转 TTL 模块连接,插到电脑,用串口看看遥控器会发出怎样的编码。

接线如下:

YS-IRTMUSB 转 TTL
VCC5V
RXDTX
TXDRX
GNDGND

接好效果如下:

打开串口助手,选择你的串口号,波特率选择 9600;勾选显示接收时间,将换行输出,看的更清楚;勾选十六进制显示。

然后就可以按遥控器查看编码啦,以下是我的遥控器 1~9 的编码。我们选择 1 的 00 FF 16 为绿灯码,2 的 00 FF 19 为黄灯码,3 的 00 FF 10D 为红灯码。

5.3 红外发射

红外的发射指令格式如下:

地址操作位数据位1数据位2数据位3
A1(FA)XXXXXXXX
  • 地址:A1为默认地址(可改),FA 为通用地址 (不可改)。

  • 操作位:该位的数据用于代表当前的工作状态。

    • F1:红外发射状态
    • F2:进入修改串口通信地址状态
    • F3:进入修改波特率状态
  • 数据位:不同的操作位(工作状态)有不同的数据内容,具体可看下表。

操作位数据位1数据位2数据位3说明
F1用户码高位用户码低位命令码
F21-FF0000数据位1代表需要修改的地址值
F31-4000001 - 4800bps
02 - 9600bps
03 - 19200bps
04 - 57600bps

比如:

目的编码
发射 NEC 信号编码为 1C 2F 33A1 F1 1C 2F 33
修改串口通信地址为 0xA5A1 F2 A5 00 00
修改波特率为9600bps(对应序号2)A1 F3 02 00 00

我们发射信号后会收到如下结果:

编码意义
F1发射成功
F2串口地址修改成功
F3波特率设置成功
无返回指令接收错误、操作不成功、重启才有效

串口效果如下:

A1是串口通信默认地址,修改串口通信地址为A5后,再发送「A1 F1 00 FF 16」就收不到了,要发送「A5 F1 00 FF 16」才可以得到发射成功的「F1」。

6. 红外对射实验

我们来试试红外对射,两个红外编解码模块发送、接收。

本实验使用的硬件如下:

  • 两个红外编解码模块:YS-IRTM
  • 两个串口:USB 转 TTL

两对接线如下:

YS-IRTMUSB 转 TTL
5V5V
RXDTXD
TXDRXD
GNDGND

接好效果如下:

电脑打开两个串口调试助手,发送编码效果如下,红框和绿框各是一次发送结果。

红外对射的交互方式虽然简单,但是有很多应用场景。例如利用红外对射进行无线控制和交互,实现遥控车辆、飞行器、电子游戏等的操作和反馈。

7. 编程实战

7.1 硬件接线

本教程使用的硬件如下:

  • 单片机:STM32F103C8T6
  • 红外编解码模块:YS-IRTM
  • 遥控器:红外遥控器
  • 小灯:三色 LED 灯模块
  • 串口:USB 转 TTL
  • 烧录器:ST-LINK V2

接线如下:

YS-IRTMLEDSTM32USB 转 TTL
5V5V
RXDA2
TXDA3
GNDG
RA5
YA6
GA7
GNDG
A10TX
A9RX
GGND

烧录的时候接线如下表,如果不会烧录的话可以看我之前的文章【STM32下载程序的五种方法:https://www.lxlinux.net/e/stm32/five-ways-to-flash-program-to-stm32.html】。

ST-Link V2STM32
SWCLKSWCLK
SWDIOSWDIO
GNDGND
3.3V3V3

接好如下图:

7.2 串口接收数据

串口接收数据在【STM32串口接收不定长数据(接收中断+超时判断):https://www.lxlinux.net/e/stm32/stm32-usart-receive-data-using-rxne-time-out.html】有详细介绍,没看过的小伙伴可以看看。

UART_HandleTypeDef ys_uart_handle;uint8_t ys_uart_rx_buf[YS_RX_BUF_SIZE];
uint8_t ys_uart_tx_buf[YS_TX_BUF_SIZE];
uint16_t ys_uart_rx_len = 0;void ys_init(uint32_t baudrate)
{ys_uart_handle.Instance          = YS_INTERFACE;                 /* BT */ys_uart_handle.Init.BaudRate     = baudrate;                     /* 波特率 */ys_uart_handle.Init.WordLength   = UART_WORDLENGTH_8B;           /* 数据位 */ys_uart_handle.Init.StopBits     = UART_STOPBITS_1;              /* 停止位 */ys_uart_handle.Init.Parity       = UART_PARITY_NONE;             /* 校验位 */ys_uart_handle.Init.Mode         = UART_MODE_TX_RX;              /* 收发模式 */ys_uart_handle.Init.HwFlowCtl    = UART_HWCONTROL_NONE;          /* 无硬件流控 */ys_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16;         /* 过采样 */HAL_UART_Init(&ys_uart_handle);                                  /* 使能BT */
}void ys_rx_clear(void)
{memset(ys_uart_rx_buf, 0, sizeof(ys_uart_rx_buf));              //清空接收缓冲区ys_uart_rx_len = 0;                                             //接收计数器清零
}void YS_IRQHandler(void)
{uint8_t receive_data = 0;   if(__HAL_UART_GET_FLAG(&ys_uart_handle, UART_FLAG_RXNE) != RESET){      //获取接收RXNE标志位是否被置位if(ys_uart_rx_len >= sizeof(ys_uart_rx_buf))                        //如果接收的字符数大于接收缓冲区大小,ys_uart_rx_len = 0;                                             //则将接收计数器清零HAL_UART_Receive(&ys_uart_handle, &receive_data, 1, 1000);          //接收一个字符ys_uart_rx_buf[ys_uart_rx_len++] = receive_data;                    //将接收到的字符保存在接收缓冲区}if (__HAL_UART_GET_FLAG(&ys_uart_handle, UART_FLAG_IDLE) != RESET)      //获取接收空闲中断标志位是否被置位{int i = 0;printf("receive: \r\n");for(i = 0; i < ys_uart_rx_len; i++ )printf("%02X ", ys_uart_rx_buf[i]);                             //将接收到的数据打印出来printf("\r\n");control_led();ys_rx_clear();__HAL_UART_CLEAR_IDLEFLAG(&ys_uart_handle);                         //清除UART总线空闲中断}
}

7.3 LED初始化

LED 灯的代码简简单单,只要进行一下三个灯的初始化就行。

void led_init(void)
{GPIO_InitTypeDef gpio_init_struct;LED1_GPIO_CLK_ENABLE();                                 /* LED1时钟使能 */LED2_GPIO_CLK_ENABLE();                                 /* LED2时钟使能 */LED3_GPIO_CLK_ENABLE();                                 /* LED3时钟使能 */gpio_init_struct.Pin = LED1_GPIO_PIN;                   /* LED1引脚 */gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;            /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                    /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;          /* 高速 */HAL_GPIO_Init(LED1_GPIO_PORT, &gpio_init_struct);       /* 初始化LED1引脚 */gpio_init_struct.Pin = LED2_GPIO_PIN;                   /* LED2引脚 */HAL_GPIO_Init(LED2_GPIO_PORT, &gpio_init_struct);       /* 初始化LED2引脚 */gpio_init_struct.Pin = LED3_GPIO_PIN;                   /* LED3引脚 */HAL_GPIO_Init(LED3_GPIO_PORT, &gpio_init_struct);       /* 初始化LED3引脚 */LED1(0);                                                /* 关闭 LED1 */LED2(0);                                                /* 关闭 LED2 */LED3(0);                                                /* 关闭 LED3 */
}

LED 的 .h文件:

#ifndef _LED_H
#define _LED_H
#include "sys.h"/******************************************************************************************/
/* 引脚 定义 */#define LED1_GPIO_PORT                  GPIOA
#define LED1_GPIO_PIN                   GPIO_PIN_7
#define LED1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)             /* PA口时钟使能 */#define LED2_GPIO_PORT                  GPIOA
#define LED2_GPIO_PIN                   GPIO_PIN_6
#define LED2_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)             /* PA口时钟使能 */#define LED3_GPIO_PORT                  GPIOA
#define LED3_GPIO_PIN                   GPIO_PIN_5
#define LED3_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)             /* PB口时钟使能 *//******************************************************************************************/
/* LED端口定义 */
#define LED1(x)   do{ x ? \HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET); \}while(0)#define LED2(x)   do{ x ? \HAL_GPIO_WritePin(LED2_GPIO_PORT, LED2_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(LED2_GPIO_PORT, LED2_GPIO_PIN, GPIO_PIN_RESET); \}while(0)#define LED3(x)   do{ x ? \HAL_GPIO_WritePin(LED3_GPIO_PORT, LED3_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(LED3_GPIO_PORT, LED3_GPIO_PIN, GPIO_PIN_RESET); \}while(0)/* LED取反定义 */
#define LED1_TOGGLE()   do{ HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_GPIO_PIN); }while(0)        /* 翻转LED1 */
#define LED2_TOGGLE()   do{ HAL_GPIO_TogglePin(LED2_GPIO_PORT, LED2_GPIO_PIN); }while(0)        /* 翻转LED2 */
#define LED3_TOGGLE()   do{ HAL_GPIO_TogglePin(LED3_GPIO_PORT, LED3_GPIO_PIN); }while(0)        /* 翻转LED3 *//******************************************************************************************/
/* 外部接口函数*/
void led_init(void);                                                                            /* LED初始化 */#endif

7.4 LED控制

我的遥控器前两位都一样,只需要判断第三位是不是为绿/黄/红灯码即可。若前两位都不正确,那就不是我的遥控器发出的红外信号,不用再往下判断了。

void control_led(void)
{if(ys_uart_rx_buf[0] == 0x00 && ys_uart_rx_buf[1] == 0xFF)      //地址码正确{switch(ys_uart_rx_buf[2])                                     //判断数据码{case 0x16:                                                  //绿灯码LED1_TOGGLE();                                            //翻转LED1break;case 0x19:                                                  //黄灯码LED2_TOGGLE();                                            //翻转LED2break;case 0x0D:                                                  //红灯码LED3_TOGGLE();                                            //翻转LED3break;}}
}

7.5 主函数

主函数如下:

int main(void)
{HAL_Init();                                 /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟,72M */delay_init(72);                             /* 初始化延时函数 */usart_init(115200);                         /* 串口1波特率设为115200 */ys_init(9600);                              /* 串口2波特率设为9600 */led_init();printf("红外控制灯……\r\n");while(1){delay_ms(1000);}
}

7.6 运行过程

烧录后,打开串口,按下遥控器1、2、3,效果如下。

红外编解码模块(串口2)波特率是9600,串口调试助手接收的是单片机(串口1)的数据,波特率115200,大家不要弄混啦。

我们的三个小灯也打开了。(我的小绿灯不是很亮,用旧了,嘻嘻)

8. 总结

祝贺大家成功点灯!当然,除了控制灯的开关,红外编解码模块还可以应用于更广泛的场景,如家庭娱乐、医疗保健、工业自动化等等。随着技术的不断进步,红外技术将持续演进,并在更多领域发挥作用。希望本文能够为你提供了一个初步的了解,并激发你进一步深入研究和应用红外技术的兴趣。感谢各位看官,love and peace!

另外,想进大厂的同学,一定要好好学算法,这是面试必备的。这里准备了一份 BAT 大佬总结的 LeetCode 刷题宝典,很多人靠它们进了大厂。

刷题 | LeetCode算法刷题神器,看完 BAT 随你挑!

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

推荐阅读:

  • 程序员必备编程资料大全
  • 程序员必备软件资源

欢迎关注我的博客:良许嵌入式教程网,满满都是干货!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/452660.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手工方式安装19.22RU

使用手工方式打RU19.22 参考文档&#xff1a; Supplemental Readme - Grid Infrastructure Release Update 12.2.0.1.x / 18c /19c (Doc ID 2246888.1) 操作步骤&#xff1a; 1 Stop the CRS managed resources running from DB homes. 2 Run the pre root script. 3 Patch G…

不要在吉利银河E8、星纪元ES之间瞎选

文 | AUTO芯球 作者 | 李诞 吉利银河E8和星纪元ES这两款车要怎么选 这是什么问题&#xff1f; 你看着这价格 吉利银河E8 是17.58-22.88万元 星纪元es是19.88-33.98万元 你要用E8高配对比ES低配&#xff1f; 好&#xff01; 想买这两款车的朋友 看完我说的 再做决定也…

Xcode 15 及以上版本:libarclite 库缺少问题

参考链接&#xff1a;Xcode 15 libarclite 缺失问题_sdk does not contain libarclite at the path /ap-CSDN博客 报错: SDK does not contain libarclite at the path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarcl…

基于YOLOv7算法的高精度实时课堂场景下人脸检测系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法的高精度实时课堂场景下人脸检测系统可用于日常生活中检测与定位人脸&#xff0c;此系统可完成对输入图片、视频、文件夹以及摄像头方式的目标检测与识别&#xff0c;同时本系统还支持检测结果可视化与导出。本系统采用YOLOv7目标检测算法来训练…

QSlider使用笔记

最近做项目使用到QSlider滑动条控件&#xff0c;在使用过的过程中&#xff0c;发现一个问题就是点滑动条上的一个位置&#xff0c;滑块并没有移动到鼠标点击的位置&#xff0c;体验感很差&#xff0c;于是研究了下&#xff0c;让鼠标点击后滑块移动到鼠标点击的位置。 1、event…

ref和reactive, toRefs的使用

看尤雨溪说&#xff1a;为什么Vue3 中应该使用 Ref 而不是 Reactive&#xff1f; toRefs import { ref, toRefs } from vue;// 定义一个响应式对象 const state ref({count: 0,name: Vue });// 使用toRefs转换为响应式引用对象 const reactiveState toRefs(state);// 现在你…

二分查找------蓝桥杯

题目描述&#xff1a; 请实现无重复数字的升序数组的二分查找 给定一个元素升序的、无重复数字的整型数组 nums 和一个目标值 target&#xff0c;写一个函数搜索 nums 中的target&#xff0c;如果目标值存在返回下标 (下标从0 开始)&#xff0c;否则返回-1 数据范围: 0 < l…

【Linux系统化学习】进程等待

目录 进程等待 进程等待的必要性 进程等待的方法 wait方法 等待一个进程(阻塞等待&#xff09; waitpid方法 任意等待多个进程&#xff08;阻塞等待&#xff09; 父进程获取子进程的退出信息 非阻塞轮询等待 进程等待 进程等待的必要性 之前讲过&#xff0c;子进程退…

C++泛编程(3)

类模板基础 1.类模板的基本概念2.类模板的分文件编写3.类模板的嵌套 &#xff08;未完待续...&#xff09; 在往节内容中&#xff0c;我们详细介绍了函数模板&#xff0c;这节开始我们就来聊一聊类模板。C中&#xff0c;类的细节远比函数多&#xff0c;所以这个专题也会更复杂。…

Python实战:爬取小红书

有读者在公众号后台询问爬取小红书&#xff0c;今天他来了。 本文可以根据关键词&#xff0c;在小红书搜索相关笔记&#xff0c;并保存为excel表格。 爬取的字段包括笔记标题、作者、笔记链接、作者主页地址、作者头像、点赞量。 一、先看效果 1、爬取搜索页 2、爬取结果保存到…

【蓝桥杯冲冲冲】动态规划学习 [NOIP2003 提高组] 加分二叉树

【蓝桥杯冲冲冲】动态规划学习 [NOIP2003 提高组] 加分二叉树 蓝桥杯备赛 | 洛谷做题打卡day24 文章目录 蓝桥杯备赛 | 洛谷做题打卡day24[NOIP2003 提高组] 加分二叉树题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示数据规模与约定思路 题解代码我的一些话 [NOI…

【鸿蒙】大模型对话应用(四):页面发起请求实现对话能力

Demo介绍 本demo对接阿里云和百度的大模型API&#xff0c;实现一个简单的对话应用。 DecEco Studio版本&#xff1a;DevEco Studio 3.1.1 Release HarmonyOS SDK版本&#xff1a;API9 关键点&#xff1a;ArkTS、ArkUI、UIAbility、网络http请求、列表布局、层叠布局 定义接…