基于TI MSPM0G3507的NEC红外编解码模块移植与串口通信实战最近在做一个智能家居的小项目需要用到红外遥控功能。市面上有很多现成的红外编解码模块用起来很方便但怎么把它接到咱们自己的MSPM0G3507开发板上让它们俩能“对话”呢今天我就来手把手带你走一遍这个移植过程。这个教程适合正在使用TI MSPM0系列MCU做项目的朋友特别是需要集成红外遥控或者想实现简单无线数据通信的。整个过程其实就是让咱们的开发板通过串口去控制一个外部的红外模块让它发射红外信号或者接收红外遥控器的信号。咱们不深究红外协议底层的时序重点放在串口通信和驱动移植上这样即使你是嵌入式新手跟着做也能搞定。1. 认识一下咱们的“外援”红外编解码模块在开始写代码之前得先了解咱们要用的工具。我选的这个红外模块本质上是一个“翻译官”。它是什么这个模块内部有一颗小MCU集成了红外发射头和接收头。它的工作就是把复杂的红外信号比如NEC协议那一长串的高低电平脉冲翻译成简单的串口数据或者反过来把咱们从串口发过去的简单指令变成标准的红外信号发射出去。它能干什么红外遥控可以控制市面上99%采用NEC格式的红外设备比如电视、空调、机顶盒、风扇等等。你只需要知道设备的遥控码。无线数据传输如果你有两个这样的模块一个当发射端一个当接收端就能实现简单的无线串口通信传输一些控制指令或者数据包。关键特性规格参数工作电压5V 注意MSPM0G3507开发板的IO通常是3.3V连接时需确认电平兼容性或使用电平转换模块供电电流 100mA 驱动红外发射管时需要较大电流确保你的电源能提供通信距离6-10米 实际距离受环境光线和发射功率影响控制接口串口UART引脚4个PinVCC, GND, TXD, RXD怎么获取资料模块的详细资料和驱动例程你可以通过下面的链接获取。我建议你先下载下来里面有数据手册和通信协议说明是咱们移植的基础。资料下载链接:https://pan.baidu.com/s/1idRcrVCxQ5zWLh59EFpi9g提取码:n8ud2. 模块怎么用串口协议是关键这个模块所有的奥秘都藏在它的串口通信协议里。咱们和模块的交互就是通过发送和接收特定格式的数据帧来完成的。2.1 数据帧格式模块通信采用固定的5字节十六进制数据帧。格式如下字节位置名称说明字节0帧头/地址模块的通信地址。默认是0xA1可以用指令修改。通用地址忘记时用是0xFA。字节1操作位告诉模块你要干什么发射、改地址、改波特率。字节2数据1具体操作的数据比如红外码的第一个字节。字节3数据2具体操作的数据比如红外码的第二个字节。字节4数据3具体操作的数据比如红外码的第三个字节。操作位定义0xF1: 红外发射命令0xF2: 修改模块通信地址0xF3: 修改模块串口波特率2.2 协议交互流程模块的设计很贴心每次你发送指令后它都会给你一个回应告诉你成功还是失败。举个例子发送红外信号假设我们要发射一组红外编码0xE0,0xFD,0xFD例如这是某个品牌空调的开机码。我们发送5字节:A1 F1 E0 FD FDA1: 使用默认地址呼叫模块。F1: 命令是“发射红外信号”。E0 FD FD: 要发射的红外编码数据。模块回应1字节:如果返回F1恭喜发射成功如果返回其他值说明发射失败。解码功能更简单模块的接收是自动的。你只需要用遥控器对着模块的接收头按一下模块就会自动把解码出的三字节红外码用户码1用户码2命令码通过串口发送出来。你只需要在串口调试助手里看着就行不需要发任何指令。注意模块收发的所有数据都是十六进制格式。在串口调试助手设置和编程时务必注意别当成ASCII字符处理了。3. 动手移植让MSPM0G3507驱动模块理论清楚了现在开始实战。我们的目标是在MSPM0G3507的工程里编写驱动代码实现通过串口控制这个红外模块。3.1 硬件连接与引脚配置首先要把开发板和模块连起来。需要连接4根线VCC(5V), GND, TX, RX。这里有个关键点开发板的TX要接模块的RX开发板的RX要接模块的TX别接反了。在MSPM0G3507上我们需要启用一个串口。根据原文我们选择使用串口1UART1并映射到PA8 (TX) 和 PA9 (RX)引脚。配置引脚在TI的CCS或IAR环境中通常使用图形化工具SysConfig来完成非常方便在你的工程中找到并双击*.syscfg文件例如empty.syscfg。在打开的界面中点击Tools-SYSCONFIG。点击ADD添加新配置选择UART外设。在UART配置中选择对应的实例如UART1将TX Pin设置为PA8RX Pin设置为PA9并配置好波特率模块默认9600先保持一致。点击保存工具可能会提示生成代码选择Yes to All。保存后所有引脚和功能的宏定义会自动生成在ti_msp_dl_config.h文件中。这个文件通常已被包含在board.h里所以我们后续编程直接包含board.h就行。3.2 创建驱动文件我们在工程里新建两个文件bsp_infrared.c和bsp_infrared.h。“bsp”意为板级支持包专门放这类外设的驱动。头文件 (bsp_infrared.h) 定义接口#ifndef _BSP_INFRARED_H_ #define _BSP_INFRARED_H_ #include board.h // 包含MSPM0的配置和驱动库 #define USART1_RECEIVE_LENGTH 1024 // 串口接收缓冲区大小 // 声明全局变量在.c文件中定义 extern unsigned char infrared_recv_buff[USART1_RECEIVE_LENGTH]; // 接收缓存数组 extern uint16_t infrared_recv_length; // 当前接收到的数据长度 extern unsigned char infrared_recv_flag; // 接收完成标志1完成 // 函数声明 void Infrared_Init(void); // 初始化函数 void infrared_receive_clear(void); // 清空接收缓存 char Infrared_emission_cmd(unsigned char* Infrared_buff, char len); // 发送红外命令 char modified_addr_cmd(unsigned int addr_value); // 修改模块地址 char modified_baud_cmd(unsigned int baud_value); // 修改模块波特率 #endif源文件 (bsp_infrared.c) 实现功能这里我挑最核心的红外发射函数Infrared_emission_cmd来详细讲解其他函数原理类似。#include bsp_infrared.h #include stdio.h // 定义全局变量 unsigned char infrared_recv_buff[USART1_RECEIVE_LENGTH]; uint16_t infrared_recv_length 0; unsigned char infrared_recv_flag 0; // 模块的默认地址和操作指令码 unsigned char device_addr 0XA1; // 默认器件地址 unsigned char Infrared_emission 0XF1; // 红外发射指令 unsigned char modified_addr 0XF2; // 修改地址指令 unsigned char modified_baud 0XF3; // 修改波特率指令 /** * brief 初始化红外模块使用的串口 * param None * retval None * note 主要工作是使能串口接收中断这样模块返回的数据才能被及时捕获。 */ void Infrared_Init(void) { // 清除可能存在的旧中断标志避免一上来就误触发 NVIC_ClearPendingIRQ(UART_1_INST_INT_IRQN); // 使能串口1的中断这样收到数据时CPU才会跳转到中断函数处理 NVIC_EnableIRQ(UART_1_INST_INT_IRQN); // 注意串口硬件本身的初始化波特率等已在board_init()中通过SysConfig完成 } /** * brief 通过串口发送一个字节 * param ucch: 要发送的字节 * retval None */ void infrared_send_byte(uint8_t ucch) { // 等待串口发送寄存器空闲避免覆盖之前还没发完的数据 while(DL_UART_isBusy(UART_1_INST) true); // 将数据写入发送数据寄存器硬件会自动发送 DL_UART_Main_transmitData(UART_1_INST, ucch); } /** * brief 通过串口发送一串数据十六进制数组 * param ch: 指向要发送数组的指针 * param len: 要发送的数组长度 * retval None */ void infrared_send_hex(uint8_t *ch, int len) { while(len--) { infrared_send_byte(*ch); // 循环调用发送单字节函数 } } /** * brief 清空接收缓冲区和相关标志位 * param None * retval None * note 每次发送新指令前最好都清空一下防止旧数据干扰判断。 */ void infrared_receive_clear(void) { unsigned int i 0; for(i 0; i USART1_RECEIVE_LENGTH; i) { infrared_recv_buff[i] 0; // 缓冲区清零 } infrared_recv_length 0; // 长度清零 infrared_recv_flag 0; // 标志位清零 } /** * brief 核心函数控制红外模块发射指定编码 * param Infrared_buff: 指向红外编码数组的指针3个字节 * param len: 红外编码数组的长度必须为3 * retval 0: 超时未收到回应 * 1: 发射成功 * 2: 收到回应但不是成功标志失败 * 100: 输入数据长度错误不为3 * note 这个函数完整展示了“发送指令-等待回应-判断结果”的流程。 */ char Infrared_emission_cmd(unsigned char* Infrared_buff, char len) { unsigned char send_data[5] {0}; // 构造发送帧的数组并初始化为0 unsigned int time_out 1000; // 超时时间单位毫秒(ms) // 第一步检查输入参数。NEC红外码固定为3字节。 if((len 3) || (len 3)) return 100; // 第二步按照协议格式填充发送数组 send_data[0] device_addr; // 帧头模块地址 send_data[1] Infrared_emission; // 操作位发射命令 send_data[2] Infrared_buff[0]; // 数据位1红外码字节1 send_data[3] Infrared_buff[1]; // 数据位2红外码字节2 send_data[4] Infrared_buff[2]; // 数据位3红外码字节3 // 第三步清空接收区准备接收本次指令的回应 infrared_receive_clear(); // 第四步通过串口发送这5个字节的指令 infrared_send_hex(send_data, 5); // 第五步等待模块回应并设置超时机制 // infrared_recv_flag 会在串口中断函数中被置1 while(infrared_recv_flag ! 1 time_out 0) { time_out--; delay_ms(1); // 需要一个毫秒级延时函数需自行实现或使用系统延时 } // 第六步判断等待结果 if(time_out 0) // 没有超时意味着收到了数据 { infrared_recv_flag 0; // 清除接收标志为下次接收做准备 // 判断回应的第一个字节是否是成功的标志 (0xF1) if(infrared_recv_buff[0] 0XF1) return 1; // 发射成功 else return 2; // 收到了数据但不是成功标志说明失败 } // 如果超时时间减到0说明一直没收到回应 return 0; // 接收超时 } /** * brief 串口中断服务函数 * param None * retval None * note 这是CPU收到串口数据后自动跳转执行的函数。 * 它负责把接收到的字节存入缓冲区并设置接收完成标志。 */ void UART_1_INST_IRQHandler(void) { // 判断中断来源是否是“接收中断” switch(DL_UART_getPendingInterrupt(UART_1_INST)) { case DL_UART_IIDX_RX: // 如果是接收中断 // 读取接收到的数据存入缓冲区 infrared_recv_buff[infrared_recv_length] DL_UART_Main_receiveData(UART_1_INST); // 在字符串末尾添加结束符如果当字符串处理的话 infrared_recv_buff[infrared_recv_length] \0; // 设置接收完成标志通知主程序 infrared_recv_flag 1; break; default: // 其他类型的中断如发送中断本例中不处理 break; } }提示代码中的delay_ms(1)函数需要你自己根据MSPM0的时钟系统来实现一个毫秒延时函数。board_init()函数通常由TI的示例工程提供它完成了系统时钟、GPIO、UART等基础硬件的初始化。4. 上机测试让空调“听”话驱动写好了最后一步就是写个主程序来测试它。假设我们已经找到了一个美的空调的“开机”红外编码{0xE0, 0xFD, 0xFD}。#include board.h #include stdio.h #include bsp_infrared.h // 美的空调的开机红外编码示例具体码值需自行学习或抓取 unsigned char Midea_AC_Open[3] {0xE0, 0xFD, 0xFD}; int main(void) { // 开发板硬件初始化时钟、GPIO、UART等 board_init(); // 初始化我们的红外驱动主要是使能串口中断 Infrared_Init(); printf(Infrared Module Demo Start\r\n); while(1) { // 尝试发送开机命令并打印返回值 char result Infrared_emission_cmd(Midea_AC_Open, 3); printf(Emission result: %d\r\n, result); // 根据返回值做出简单判断 if(result 1) { printf(Success! AC should be ON.\r\n); } else if(result 0) { printf(Failed: Timeout. Check connection.\r\n); } else if(result 2) { printf(Failed: Module returned error.\r\n); } else if(result 100) { printf(Error: Invalid data length.\r\n); } // 延时一段时间避免连续发送 delay_ms(3000); // 延时3秒 } }测试方法将编译好的程序下载到MSPM0G3507开发板。将红外模块的发射头对准你的目标电器如空调。给开发板和模块上电。通过串口助手连接开发板的调试串口观察打印信息。如果看到返回值为“1”并且你的空调有反应比如“嘀”一声或开机那么恭喜你移植成功了进阶测试你可以用另一个红外模块接USB转TTL连接到电脑作为接收端放在开发板旁边。当开发板控制发射模块发出信号时接收模块会收到并解码你可以在电脑的串口助手上看到解码出的E0 FD FD这能双向验证整个通信链路的正确性。这个移植过程的核心思路其实适用于很多串口外设理解协议 - 配置MCU串口 - 编写数据打包/解析函数 - 实现通信状态机发送、等待、超时。希望这个详细的步骤能帮你顺利搞定红外功能并在其他项目中举一反三。