STM32F103C8T6红外发射驱动系统架构
在智能家居设备日益复杂的今天,确保无线连接的稳定性已成为一大设计挑战。然而,在Wi-Fi、蓝牙横行的时代,你有没有想过—— 一个小小的38kHz方波,居然还能掌控家里的空调、电视甚至投影仪? 😮
没错,说的就是 红外遥控 。它看似“古老”,却因结构简单、成本极低、抗干扰强,在家电控制领域稳坐江山几十年。而如今,用一颗 STM32F103C8T6(俗称“蓝丸”) 就能轻松实现万能遥控功能,不仅灵活可编程,还能集成进智能网关,简直是嵌入式爱好者的“性价比神器”!
那问题来了:怎么让这块几块钱的MCU精准发出一串串红外信号?关键就在于—— 定时器 + 载波调制 + 协议编码 三重奏!🎶 下面我们就从硬件到软件,一层层揭开它的神秘面纱。
我们先来看看主角: STM32F103C8T6 。这颗基于ARM Cortex-M3内核的MCU,主频高达72MHz,内置64KB Flash和20KB RAM,虽然不算顶级配置,但胜在性价比高、生态成熟,尤其是那几个通用定时器(TIM2~TIM4),简直就是为时序敏感任务量身定制的。
在红外发射系统中,它的角色可不止是“发个高低电平”这么简单:
- 它要当 编码器 :把“开机”、“音量+”这样的命令翻译成NEC或SIRC协议的数据帧;
- 它要当 调制器 :生成38kHz的载波,用来“点亮”红外LED;
- 它还得当 计时员 :精确控制每个脉冲的宽度,误差必须控制在微秒级,否则接收端直接“听不懂”。
听起来挺复杂?别急,咱们拆开看。
最核心的部分,就是 载波调制 。想象一下,你要控制一盏灯,但如果一直亮着,别人分不清你是想传数据还是只是忘了关灯。于是聪明的人类想到了一个办法: 用高频闪烁来代表“有信号” ——这就是所谓的 幅度键控(OOK)调制 。
对于红外通信,最常见的载波频率是 38kHz ,对应周期约26.3μs。为了让红外LED有效工作,通常采用1/3占空比,也就是高电平持续约8~9μs。这个任务交给STM32的 定时器PWM模式 再合适不过了。
比如我们可以选择
TIM3_CH1
(对应PA6引脚),配置如下:
htim3.Instance = TIM3;
htim3.Init.Prescaler = 71; // 72MHz / 72 = 1MHz → 每tick=1μs
htim3.Init.Period = 25; // 自动重载值,26μs周期 → ~38.46kHz
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
这样,只要调用
HAL_TIM_PWM_Start()
,PA6就会自动输出38kHz方波。而当我们需要发送“低电平”时,只需停止PWM并拉低GPIO即可:
void IR_Carrier_Enable(void) {
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 7); // CCR=7 → ~7μs ON
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
}
void IR_Carrier_Disable(void) {
HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
}
是不是很巧妙?😎 不用手动翻转IO,也不用担心中断延迟,全部由硬件自动完成。
接下来是 协议编码 环节。市面上红外协议五花八门,但最常见的是 NEC协议 。它的规则非常清晰:
- 引导码:9ms高电平 + 4.5ms低电平
- 数据位:
- “0”:560μs高 + 560μs低
- “1”:560μs高 + 1690μs低
- 整个帧长32位(地址 + 命令 + 反码)
- 重复码:9ms高 + 2.25ms低(用于长按)
注意啦!这里的“高电平”其实是指 载波开启状态 ,即38kHz PWM输出;而“低电平”则是完全关闭。所以真正的代码逻辑应该是:
// 发送一位数据
void ir_send_bit(uint8_t bit) {
IR_Carrier_Enable(); // 开启38kHz载波
HAL_Delay_us(560); // 固定高电平时间
IR_Carrier_Disable(); // 关闭载波
if (bit == 0) {
HAL_Delay_us(560); // 低电平持续560μs
} else {
HAL_Delay_us(1690); // 低电平持续1690μs
}
}
等等……这里用了
HAL_Delay_us()
?🚨 危险操作!因为HAL库的延时函数在优化级别高的时候可能不准,而且会阻塞CPU!
更靠谱的做法是使用 定时器中断 或者 单脉冲模式(OPM) 来触发下一个动作,避免主程序卡死。例如可以用TIM2做时间基准,每到关键节点触发一次中断,切换载波状态,真正做到非阻塞运行。
整个系统的物理连接其实很简单:
VCC (5V)
│
[R] 限流电阻 (~100Ω)
│
IR_LED
│
NPN Collector
│
GND
↑
Base ── [1kΩ] ── PA6 (STM32)
为什么加三极管?因为STM32的IO口最大输出电流也就20mA左右,而要想让红外LED射得远,最好能推到80~100mA。加个S8050或2N3904之类的NPN三极管,瞬间搞定驱动能力问题 💪。
当然,如果你追求更高性能,也可以换MOSFET,开关更快、损耗更低,适合频繁发射场景。
实际应用中,总会遇到一些“玄学”问题,比如:
🔧 发射距离短?
- 检查载波频率是否准确!内部RC振荡器偏差大,建议外接8MHz晶振并通过PLL倍频到72MHz。
- 提高驱动电流,但别烧了LED哦~一般峰值不超过100mA为宜。
🔧 接收端偶尔失灵?
- 很可能是时序偏移导致。避免使用粗粒度延时函数,改用定时器中断或DMA联动。
- PCB布局也要注意:PWM走线远离模拟电路,防止EMI干扰其他模块。
🔧 想支持多种协议怎么办?
这时候就得搞点“架构思维”了。可以抽象出一个统一接口:
typedef struct {
void (*init)(void);
void (*send)(uint32_t addr, uint32_t cmd);
const char* name;
} ir_protocol_t;
// 示例:注册NEC协议
extern const ir_protocol_t nec_protocol;
然后通过函数指针动态切换协议,未来扩展Sony SIRC、RC5都不用改底层驱动,维护起来简直不要太爽~ ✨
说到应用场景,这玩意儿可不只是做个遥控器那么简单:
🎯 智能家居中枢 :配合ESP8266或ESP32,打造Wi-Fi转红外网关,手机App远程控制老式空调!
🧪 自动化测试平台 :工厂里批量检测电视遥控功能?写个脚本自动发指令,省下人工成本。
👂 学习型遥控器 :加上一个红外接收头(如VS1838B),收到信号后反向解析,存入Flash,下次就能模仿原装遥控器啦~
🗣️ 语音控制联动 :接入LD3320这类离线语音模块,喊一声“打开电视”,立马安排上!
甚至还可以玩点高级的:OTA升级码库,适配新上市的电器型号,真正做到“一机在手,全家通控” 🔮
当然,也不能忽视一些工程细节:
🔋 电池供电? 那就必须考虑低功耗了。可以用STOP模式待机,通过按键中断唤醒,瞬间启动发射流程,续航轻松撑几个月。
🌡️ 长时间发射过热? 加个软件节流机制,连续发5次就暂停一下,保护LED寿命。
📦 量产要考虑什么? 统一校准晶振频率、固化常用码库、预留串口更新通道……这些都会影响最终用户体验。
你看,一块小小的STM32F103C8T6,配上一个红外LED,再加上几行精心编排的代码,就能构建出一个高度灵活、可扩展性强的红外发射系统。它不仅是学习嵌入式定时器与通信协议的绝佳案例,更是通往智能家居世界的“低成本入口”。
更重要的是,这种 软硬结合、以小博大 的设计思路,正是现代嵌入式开发的魅力所在。💡
下次当你按下遥控器的时候,不妨想想:也许就在某个角落,有一块蓝丸正在默默为你“发光发热”呢~ 🌟
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

被折叠的 条评论
为什么被折叠?



