当前位置: 首页 > news >正文

衡山派开发板红外编解码模块驱动移植与NEC协议应用实战

衡山派开发板红外编解码模块驱动移植与NEC协议应用实战

最近在做一个智能家居项目,需要控制家里的空调和电视,红外遥控是最直接的方案。正好手头有衡山派开发板和一个红外编解码模块,今天就来分享一下如何把这个模块的驱动移植到衡山派开发板上,并实现NEC协议的红外信号收发。

这篇文章适合正在使用衡山派开发板做物联网或智能家居项目的朋友,我会手把手教你从驱动移植到实际应用的全过程。学完这篇教程,你就能用衡山派开发板通过串口控制红外模块,实现红外信号的接收和发射,轻松控制各种家电设备。

1. 红外模块基础认知

1.1 模块是什么?能做什么?

咱们先来认识一下这个红外编解码模块。它其实是一个集成了MCU、红外发射头和红外接收头的独立模块,通过串口与主控板(比如衡山派)通信。

这个模块最大的特点就是支持NEC格式的红外编码发射功能,可以控制市面上99%的NEC格式设备。像大部分电视机、机顶盒、DVD、电饭煲等家电,用的都是NEC协议。

NEC协议小知识:NEC是红外遥控中最常用的协议之一,它用脉冲宽度调制的方式编码数据。一个完整的NEC码包含用户码、用户码反码、命令码和命令码反码,总共32位。

模块的工作方式很简单:

  • 发射:通过串口发送指定的指令,模块就会发射对应的红外信号
  • 接收:模块接收到红外信号后,通过串口输出解码后的数据

你甚至可以用两个模块实现无线控制,一个当发射端,一个当接收端,中间不需要任何连线。

1.2 模块关键参数

在开始移植前,咱们先看看模块的基本参数,这些信息在硬件连接和代码配置时都会用到:

参数规格
工作电压5V
供电电流> 100mA
发射距离6-10米(根据环境光线和收发情况有差异)
接收距离6-10米(和发射设备的功率有关)
控制方式串口
管脚数量4 Pin(2.54mm间距排针)

模块的管脚定义很简单,就4个引脚:

  • VCC:接5V电源
  • GND:接地
  • TXD:模块的发送引脚,接开发板的RX
  • RXD:模块的接收引脚,接开发板的TX

2. 驱动移植完整流程

2.1 准备工作:获取驱动代码

首先需要下载驱动代码包。原始资料里提供了百度网盘链接,你也可以从衡山派官网的资料下载中心找到。

下载后,把驱动代码文件夹复制到你的工程目录下:

\luban-lite\application\rt-thread\helloworld\user-bsp\

如果你找不到user-bsp这个文件夹,说明你还没进行模块移植的前置操作。需要先按照衡山派官方手册的"必要操作"章节进行配置。

2.2 修改Kconfig文件

接下来要修改Kconfig文件,让系统知道我们要添加这个模块。

  1. 用VSCode打开工程中的Kconfig文件:

    application\rt-thread\helloworld\Kconfig
  2. 在文件的#endif前面添加下面这行代码:

    # 红外解码编码模块 source "application/rt-thread/helloworld/user-bsp/infrared-decoding-coding-module/Kconfig"

这个操作相当于告诉编译系统:"嘿,我这里有个红外模块的驱动,你编译的时候记得把它加进去。"

2.3 配置menuconfig

现在进入menuconfig进行配置。这里我分享一下我的操作习惯:

  1. 双击luban-lite文件夹下的win_env.bat脚本打开env工具

  2. 输入以下命令列出所有可用的默认配置:

    scons --list-def
  3. 选择衡山派开发板的默认配置d13x_JLC_rt-thread_helloworld

    scons --apply-def=7

    或者

    scons --apply-def=d13x_JLC_rt-thread_helloworld_defconfig

    这两个命令作用是一样的,一个是文件编号,一个是配置名称。

  4. 输入以下命令进入menuconfig菜单:

    scons --menuconfig
  5. 在menuconfig界面中,找到并选中Porting code using the LCKFB module

    • Y键选中
    • N键取消选中
    • 方向键左右调整最下面菜单的选项
    • 方向键上下调整列表的选项
    • 回车执行最下面菜单的选项
  6. 回车进入Porting code using the LCKFB module菜单

  7. 按方向键上下选中Using infrared decoding and encoding modules,然后按Y键。看到前面括号里出现一个*号,就表示选中成功了。

  8. 按方向键左右选中<Save>,然后一路回车退出即可。

2.4 编译与烧录

配置保存并退出menuconfig后,开始编译:

scons

如果你的电脑配置不错,可以用多核编译加快速度:

scons -j16

-j参数用来选择并行编译的核心数,我这里选择16核。大家可以根据自己电脑的CPU核心数来调整,核心越多编译越快。如果写的数量高于电脑本身,那么会自动按照最高可用的来执行。

编译完成后,会在\luban-lite\output\d13x_JLC_rt-thread_helloworld\images文件夹下生成一个d13x_JLC_v1.0.0.img镜像文件。

接下来就是烧录镜像到开发板,具体的烧录教程可以参考衡山派官方的镜像烧录教程。

3. 代码深度解析

3.1 核心驱动文件分析

驱动代码的核心在bsp_ir_decode_encode.c这个文件里。我带你看看几个关键函数,理解了这些,你就能完全掌握这个模块的使用。

首先是初始化函数INFRARED_Init()

int INFRARED_Init(void) { // 清空接收缓冲区 rt_memset(serial_recv_buff,0,sizeof(serial_recv_buff)); // 清空标志位 serial_recv_flag = 0; // 清空缓冲区长度计数器 serial_recv_length = 0; rt_kprintf("Try to open(%s)\n", SAMPLE_UART_NAME); // 获取串口设备 serial = rt_device_find(SAMPLE_UART_NAME); if (!serial) { LOG_E("find %s failed!\n", SAMPLE_UART_NAME); return -RT_ERROR; } // 初始化信号量 ret = rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO); if (ret != RT_EOK) { LOG_E("failed to rt_sem_init !\n"); return -RT_ERROR; } // 打开串口设备 ret = rt_device_open(serial, RT_DEVICE_FLAG_INT_RX); if (ret != RT_EOK) { LOG_E("open %s failed : %d !\n", SAMPLE_UART_NAME, ret); return -RT_ERROR; } // 设置接收回调函数 rt_device_set_rx_indicate(serial, uart_input); // 创建串口数据接收线程 serial_recv_thread = rt_thread_create("serial", serial_recv_thread_entry, RT_NULL, 1024*2, 15, 20); if (serial_recv_thread != RT_NULL) { // 启动线程 rt_thread_startup(serial_recv_thread); } else { rt_device_close(serial); LOG_E("Failed to [rt_thread_create] !!!"); return -RT_ERROR; } return RT_EOK; }

这个函数做了几件重要的事:

  1. 初始化各种变量和缓冲区
  2. 查找并打开UART3串口(模块默认用UART3)
  3. 创建信号量用于线程同步
  4. 创建一个专门的线程来接收串口数据

然后是红外发射函数INFRARED_Emit_CMD()

int INFRARED_Emit_CMD(uint8_t *cmd_buff, uint32_t len) { uint8_t send_buff[5] = {0}; // 必须赋初值 uint32_t time_out = 1000; // 超时时间,单位MS // 发送的数据长度是否正确 if( (len < 3) || (len > 3) ) return 100; send_buff[0] = device_addr; // 设备地址 send_buff[1] = Infrared_emission; // 操作位 send_buff[2] = cmd_buff[0]; // 数据位1 send_buff[3] = cmd_buff[1]; // 数据位2 send_buff[4] = cmd_buff[2]; // 数据位3 /* 先清除接收的数据 */ Clear_recv_buff(); /* 发送数据 */ serial_send_string(send_buff, 5); /* 等待响应数据 */ while( serial_recv_flag != 1 && time_out > 0 ) { time_out--; delay_ms(1); } /* 检查是否超时 */ if(!time_out) { LOG_E("[INFRARED_Emit_CMD]Waiting for response data has timed out !!"); return 1; // 超时未收到发射成功数据 } if(serial_recv_buff[0] != 0xF1) { LOG_E("[INFRARED_Emit_CMD]The data received is incorrect !!"); return 2; // 接收到的数据不是想要的数据 } /* 成功 */ return 0; }

这个函数有几个关键点需要注意:

  1. 发送的数据必须是3个字节,对应NEC协议的"用户码1+用户码2+命令码"
  2. 发送前会先清空接收缓冲区,避免旧数据干扰
  3. 有1秒的超时等待,防止程序卡死
  4. 模块会返回0xF1表示发射成功

最后是红外接收函数INFRARED_Recv_CMD()

int INFRARED_Recv_CMD(uint8_t *cmd_buff) { int i; /* 判断是否收到了数据 */ if((serial_recv_flag != 1) || (serial_recv_length == 0)) { /* 未收到 */ return 0; } /* 将数据转存到指针指向的地址中 */ for(i = 0; i < serial_recv_length; i++) { cmd_buff[i] = serial_recv_buff[i]; } /* 清除接收的数据、标志位和数据长度。 */ Clear_recv_buff(); return i; // 返回接收到的数据长度 }

这个函数很简单,就是检查是否有数据收到,有的话就复制到用户提供的缓冲区,然后返回数据长度。

3.2 通信协议详解

模块的串口通信协议需要特别注意,这是我调试时踩过的坑:

所有指令都是16进制格式,比如设备地址A1要写成0xA1。

模块有两个地址需要注意:

  • 默认地址:0xA1
  • 通用地址:0xFA(忘记了自己设置的地址时可以用这个)

每个指令发送完毕后,都有对应的返回信息。比如:

  • 发送红外信号数据:FA F1 E0 FD FD 回车,返回 F1 说明发送成功;返回其他说明发送失败
  • 发送修改通信地址:FA F2 A5 00 00 回车,返回 F2 说明修改成功
  • 发送修改波特率:FA F3 02 00 00 回车,返回 F3 说明修改成功

操作位的作用是表示当前指令用于实现什么功能,具体定义如下:

操作位功能说明
0xF1红外发射状态
0xF2修改设备地址
0xF3修改波特率

3.3 测试代码解析

测试文件test_infrared_decoding_coding_module.c定义了一个处理红外编解码模块的线程。这个线程的主要任务是循环接收红外编解码模块的数据,并将接收到的数据以十六进制格式打印到控制台。

线程入口函数逻辑:

  1. 打印一条消息表示线程开始运行
  2. 在一个无限循环中,首先尝试从红外编解码模块接收数据
  3. 定义一个整型变量count用于记录接收到的数据长度,并定义一个recv_buff缓冲区用于存储接收到的数据
  4. 调用INFRARED_Recv_CMD函数获取接收到的数据长度,并存储到recv_buff
  5. 检查接收到的数据长度是否超过缓冲区大小,如果超过则打印错误信息并限制数据长度
  6. 如果接收到数据,则将其以十六进制格式打印到控制台
  7. 每次循环结束时,线程会挂起一段时间,这里是100毫秒

此外,该文件还定义了两个命令test_infrared_decoding_coding_moduletest_exit_infrared_decoding_coding_module,它们分别用于启动和退出红外编解码模块线程。

4. 实际测试验证

4.1 硬件连接

测试前需要正确连接硬件:

  1. USB转TTL模块连接到衡山派开发板上
  2. 红外模块的TX接开发板的RX(UART3)
  3. 红外模块的RX接开发板的TX(UART3)
  4. 红外模块的VCC接5V,GND接GND

具体的串口调试教程可以参考:串口调试教程

串口波特率默认115200

4.2 运行测试

在串口终端中输入以下命令运行该模块的线程:

test_infrared_decoding_coding_module

输入的时候按下TAB键会进行命令补全!

模块上电效果:

我们使用红外遥控器进行控制,向红外编解码模块发送数据

这时候,用红外遥控器对着模块的接收头按下按键,你会在串口终端看到类似这样的输出:

Read CMD = a1 f1 e0 fd fd

这就是解码后的NEC红外码!格式是"用户码1+用户码2+命令码"三位。

4.3 发射测试

要发射红外信号,你需要在代码中调用INFRARED_Emit_CMD()函数。比如你想发射刚才接收到的那个码:

uint8_t ir_code[3] = {0xE0, 0xFD, 0xFD}; // 用户码1、用户码2、命令码 int ret = INFRARED_Emit_CMD(ir_code, 3); if(ret == 0) { rt_kprintf("红外发射成功!\n"); }

这样模块就会发射对应的红外信号,可以用来控制电视、空调等设备。

5. 常见问题与调试技巧

5.1 模块无响应怎么办?

如果模块完全没有反应,按以下步骤排查:

  1. 检查电源:模块需要5V供电,电流要大于100mA
  2. 检查串口连接:TX、RX是否接反了
  3. 检查波特率:默认是115200,如果修改过要对应上
  4. 检查设备地址:默认是0xA1,如果修改过要用新地址

5.2 接收数据乱码

如果接收到的数据不对:

  1. 环境干扰:红外接收容易受日光灯、太阳光干扰,尽量在暗环境下测试
  2. 距离问题:接收距离要在6-10米内,太远信号弱
  3. 遥控器电池:电池电量不足会导致发射功率不够

5.3 发射距离短

如果发射距离达不到预期:

  1. 发射头要对准:红外是直线传播,要对准接收设备
  2. 避免遮挡:中间不要有障碍物
  3. 检查发射头:有些模块的发射头有保护膜,记得撕掉

5.4 修改模块参数

如果你想修改模块的地址或波特率,可以使用提供的函数:

// 修改设备地址为0xB0 Modify_Serial_Addr_CMD(0xB0); // 修改波特率为9600 Modify_Baud_CMD(9600);

修改后记得保存,模块会记住设置,下次上电仍然有效。

这个红外模块我在好几个智能家居项目里都用过,稳定性很不错。最大的优点是省事——不用自己写红外编解码,串口一发一收就搞定。如果你要做红外相关的项目,这个模块绝对能帮你节省大量开发时间。

驱动代码和资料我都放在文章里了,按照步骤一步步来,肯定能调通。有什么问题可以在评论区交流,我看到都会回复。

http://www.jsqmd.com/news/492677/

相关文章:

  • 立创EDA开源项目:LED-编码器交互模块设计与8种显示模式详解
  • 批量逆地理编码实战:从Excel坐标到结构化地址(附完整代码)
  • Qwen-Ranker Pro入门必看:如何评估重排序效果——NDCG@5指标计算示例
  • 从均匀分布到参数估计:极大似然法实战解析
  • Java-语法基础1-[与C语言的异同]
  • Phi-3-vision-128k-instruct可部署方案:单卡3090/4090高效运行128K视觉模型
  • Navicat数据同步实战:从单向合并到双向协同
  • 实测分享:Ollama部署translategemma-27b-it图文翻译模型,效果惊艳
  • B003 找循环节 建图 ABC167D
  • CAN总线滤波秘籍:SJA1000的验收滤波器配置全解析(BasicCAN vs PeliCAN模式)
  • 短链接生成器架构解密:62 进制编码 + 分布式 ID,如何让 6 位字符支撑 568 亿个网址?
  • JetBrains IDE试用期管理工具:从痛点到解决方案的完整指南
  • Ollama部署Llama-3.2-3B避坑指南:常见问题与解决方案
  • 都在用 OpenClaw 跑 Skill,但你写的“技能”为什么总让 AI 频繁罢工?
  • uni.createInnerAudioContext音频播放全攻略:从基础使用到duration获取异常处理
  • 简单研究一下 shipfast 的收益排行榜上的 SaaS 网站都是干什么的(转)
  • 实时口罩检测-通用应用指南:智能考勤与公共卫生管理解决方案
  • 开箱即用:Hunyuan-MT 7B翻译镜像,原文输入→一键翻译→实时展示
  • 关于 Amazon Linux 2023 (AL2023) 默认情况下确实没有 /var/log/secure 文件的解决方法
  • Vivado 2024.2编译提速秘籍:实测32线程设置与16线程性能天花板
  • Spring AI + RAG 构建电商智能客服:从 PDF 文档解析到精准问答的全链路实战
  • gte-base-zh效果对比图谱:t-SNE+UMAP双视角展示中文语义空间结构
  • 酷狗音频转换器进阶指南:无损格式互转与批量处理技巧
  • 快速生成树协议 RSTP IEEE 802.1w
  • ANSYS APDL工具栏进阶玩法:用嵌套Toolbar实现多级菜单(2023版)
  • Grok3角色扮演功能实测:从家庭作业助手到18+模式,哪个最实用?
  • Stable Yogi Leather-Dress-Collection季节主题作品展:春夏秋冬皮革风尚
  • 【SLAM坐标系精讲】从像素到世界:四大坐标系与核心变换的实战解析
  • 第七章 回溯算法part03
  • 半导体器件物理基础:金半接触的能带理论与整流机制