【STM32】R05D电控红外协议的美的空调遥控器

本文详细介绍了R05D红外协议的原理及其实现过程,包括协议手册的理解、时序验证、硬件电路修改和STM32的GPIO控制。通过分析遥控器波形,确定了高位先发的编码规则,并提供了相应的代码实现,包括载波38kHz的生成和0、1数据位的发送方法。最终,通过STM32控制红外发射模块成功实现了对美的空调的遥控功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、设计思路

通常红外遥控采用NEC传输协议,而美的空调采用的是R05D红外协议(应该是自己设计的协议),因此用一般红外编码发射模块无法直接对空调进行控制。

解决方法:获取R05D协议手册 + 用红外接收管对原有遥控器红外接收进行波形分析。

一、R05D红外协议原理

R05D电控功能说明书:https://wenku.baidu.com/view/c46594141ed9ad51f01df2c3.html

1.协议手册理解

总的来说,编码时序都跟NEC不一样。 下面1–5点为编码讲解;6–10点为时序讲解

  1. 通常编码格式为: L,A,A’,B,B’,C,C’, S, L,A,A’,B,B’,C,C’
  2. 第一帧和第二帧相同
  3. 采用MSB在先,LSB在后;也就是高位先发(重点:手册没讲,是通过接收管波形分析出来的!!!!下一部分时序分析有说明)
  4. L为引导码;S为分隔码;A为识别码(A=10110010=0xB2,预留方案时A=10110111=0xB7),A’为A的反码;B’为B的反码;C’为C的反码。
  5. B、C含义如下
    在这里插入图片描述在这里插入图片描述
    例如:自动风,制冷,18摄氏度的编码
L 10110010 01001101 10111111 01000000 00010000 11101111 S L ...(省略)
L 0xB2 0x4D 0xBF 0x40 0x10 0xEF S L 0xB2 0x4D 0xBF 0x40 0x10 0xEF
  1. 引导码L

在这里插入图片描述

  1. 分隔码S

在这里插入图片描述

  1. 发送"1"数据 在这里插入图片描述

  2. 发送"0"数据
    在这里插入图片描述

  3. 终止符和两个控制波形间隔
    在这里插入图片描述

很明显,编码与时序都跟NEC不一样,注定通过控制GPIO时序来发送R05D协议的编码

2.验证时序(重点)

通过示波器分析遥控器发送的红外编码

在这里插入图片描述
L引导码后 接收到A=10110010=0xB2 A‘=01001101=0xB7

因此,证实了上面一部分第3点。高位先发,低位后发!!这跟NEC不一样(NEC采用低位先发送),所以普通红外编码发射模块根本不适用!!
由于之前没有对遥控器进行时序分析,所以默认低位先发,结果还是不行,借了一个遥控器,把红外接收管接示波器,才知道出错了。改了时序就能实现了。

二、硬件实现

1.需要的材料

  1. 首先要有一台空调(美的中央空调)
  2. 红外发射模块
  3. STM32F1

2.对发射模块电路进行修改

由于买的发射模块自带编码,不用NEC编码只能改电路(这里推荐直接买红外发射模块就好了,不带任何编码的那种)
在这里插入图片描述
根据原理图,把IRT引出来跟STM32的IO口相接
在这里插入图片描述
实物图如下:
在这里插入图片描述
直接焊接一条杜邦线,跟STM32相连接
在这里插入图片描述

这时候,只需要控制STM32GPIO的输出,就可以控制红外发射的波形,而不需要用到编码芯片了

3.STM32 GPIO选择

本人用的是蓝桥杯嵌入式的开发板(stm32f103rbt6),至于其他芯片也几乎大同小异。
由于载波频率为38KHZ,GPIO必须有定时器功能,因为可以输出PWM波形,设置频率38KHZ,控制输出与否就能实现编码时序

这里选择使用PA1,属于定时器2通道2
在这里插入图片描述

通过搞懂协议原理和修改电路并进行连接后,只需要写出对的时序控制代码就能控制空调了!!

三、代码实现

1.载波38kHZ实现

由于TIM2的输入时钟为72MHZ,通过分频和自动重装载值的设定,得出PWM的频率为72Mhz / 5(预分频) / 378(计数次数) ≈ 38Khz

void TIM_PWM_Init(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
	
	/* TIM2 clock enable */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);		
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	/* PA1引脚设置 */
	
	TIM_TimeBaseStructure.TIM_Period = 378;  		//72 000khz/378/5 = 38.09khz
	TIM_TimeBaseStructure.TIM_Prescaler = 5-1;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	//TIM2预分频设置:72kHZ。APB1分频系数2,输入到TIM3时钟为36MHzx2 = 72MHz  

	/* Channel 2 Configuration in PWM mode */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择PWM模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
	//	TIM_OCInitStructure.TIM_Pulse=500;//设置占空比时间
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);

	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能预装载寄存器

	//使能TIM2定时计数器
	TIM_Cmd(TIM2, ENABLE);
}

2.R05D时序实现

通过改变比较计数器,来输出高电平和低电平
接收高电平:对于发送来说就是输出低,比较值为0,占空比0%,红外无输出
接收低电平:对于发送来说就是输出高,比较值为189,占空比50%,红外输出载波
(此发送接收关系与NEC一样,不懂自行百度)
延时用的是嘀嗒定时器

void Lead_Code()
{
	TIM_SetCompare2(TIM2,189); //接收器拉低
	delay_us(4400);
	TIM_SetCompare2(TIM2,0); //接收器拉高
	delay_us(4400);
}

void Stop_Code()
{
	TIM_SetCompare2(TIM2,189); //接收器拉低
	delay_us(540);
	TIM_SetCompare2(TIM2,0); //接收器拉高
	delay_us(5220);
}

void Send_0_Code()
{
	TIM_SetCompare2(TIM2,189); //接收器拉低
	delay_us(540);
	TIM_SetCompare2(TIM2,0); //接收器拉高
	delay_us(540);
}

void Send_1_Code()
{
	TIM_SetCompare2(TIM2,189); //接收器拉低
	delay_us(540);
	TIM_SetCompare2(TIM2,0); //接收器拉高
	delay_us(1620);
}

void Send_Byte(u8 data)
{
	int i;
	for(i=7;i>=0;i--)
	{
		if(data & (1<<i))
		{
			Send_1_Code();
		}
		else
		{
			Send_0_Code();
		}
	}
}

void Normal_Code(u8 A, u8 B, u8 C)
{
	Lead_Code();
	Send_Byte(A);
	Send_Byte(~A);
	Send_Byte(B);
	Send_Byte(~B);
	Send_Byte(C);
	Send_Byte(~C);
	Stop_Code();
	Lead_Code();
	Send_Byte(A);
	Send_Byte(~A);
	Send_Byte(B);
	Send_Byte(~B);
	Send_Byte(C);
	Send_Byte(~C);
	Stop_Code();
}

3.调用函数并验证

void main()
{
	初始化函数();
	
	Normal_Code(0xB2, 0x9F, 0x00); //制冷 低风 17
}

在这里插入图片描述

至于调控温度,模式,自行根据协议修改发送数值就OK了!

### 解析 Import Error 的常见原因 当遇到 `ImportError: cannot import name 'Generic'` 错误时,通常意味着尝试从模块中导入的对象不存在或无法访问。此问题可能由多种因素引起: - 版本不兼容:不同库之间的版本冲突可能导致此类错误。 - 安装缺失:目标库未正确安装或路径配置有误。 - 导入语句不当:可能存在循环依赖或其他语法层面的问题。 ### 针对 Generic 类型的具体解决方案 对于特定于 `Generic` 的情况,考虑到 Python 中 `Generic` 是 typing 模块的一部分,在处理该类别的 ImportError 时可采取如下措施[^1]: #### 方法一:确认typing模块可用性 确保环境中已安装标准库中的 typing 模块,并且其版本支持所使用的特性。可以通过以下命令验证: ```bash python -c "from typing import Generic; print(Generic)" ``` 如果上述命令执行失败,则可能是由于 Python 或者相关扩展包的版本过低造成的。此时应考虑升级至更高版本的解释器以及对应的开发工具链。 #### 方法二:调整导入方式 有时直接通过顶层命名空间来获取所需组件会更稳定可靠。修改代码以采用这种做法可能会解决问题: ```python from collections.abc import Iterable # 如果是迭代器相关接口 from typing import TypeVar, Protocol # 对于协议和泛型定义 T = TypeVar('T') class MyContainer(Protocol[T]): ... ``` 注意这里并没有显式提到 `Generic` ,而是利用了更为基础的数据结构抽象基类或是其他替代方案实现相同功能[^2]。 #### 方法三:排查环境变量设置 检查系统的 PYTHONPATH 和虚拟环境配置是否正常工作。任何异常都可能导致某些第三方软件包找不到必要的资源文件而引发类似的错误提示。建议清理并重建项目专属的工作区以便排除干扰项的影响。 #### 示例修正后的代码片段 假设原始代码试图这样引入 `Generic` : ```python from some_module import Generic # 可能导致 ImportError ``` 改为遵循官方文档推荐的方式后变为: ```python from typing import Generic # 正确的做法 ```
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值