前言
上一篇文章分析了美的空调 R05D 红外协议原理,接下来将通过 STM32 单片机编程实现空调控制。
代码
初始化 PWM
将红外发射管接在 PA1 引脚上,使用 TIM2 时钟控制 PWM 波形,输出 38kHz 载波。通过分频和自动重装载值设定,得出 PWM 波形频率为 72MHz / 19(预分频)/ 101(计数次数)≈ 38kHz。
void PWM_Init(void)
{
// 38kHz 初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); // PA1 引脚设置
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseStructure.TIM_Period = 101 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 19 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
微秒级延时
基于 SysTick 系统嘀嗒定时器实现微秒级延时。
void delay_us(uint32_t nus)
{
uint32_t temp;
SysTick -> LOAD = 9 * nus;
SysTick -> VAL = 0x00;
SysTick -> CTRL = 0x01;
do
{
temp = SysTick -> CTRL;
}while((temp & 0x01) && (!(temp & (1 << 16))));
SysTick -> CTRL = 0x00;
SysTick -> VAL = 0x00;
}
引导码 L、分隔码 S、数据位 0 和 1
通过改变比较计数器,来输出高电平和低电平
接收高电平:对于发射端而言就是输出低电平,比较值为 0,无红外载波输出
接收低电平:对于发射端而言就是输出高电平,比较值为 50,有红外载波输出
void Lead_Code(void)
{
// 引导码 4400us 高电平, 4400us 低电平
TIM_SetCompare2(TIM2, 50);
delay_us(4400);
TIM_SetCompare2(TIM2, 0);
delay_us(4400);
}
void Stop_Code(void)
{
// 结束码 540us 高电平,5220us 低电平
TIM_SetCompare2(TIM2, 50);
delay_us(540);
TIM_SetCompare2(TIM2, 0);
delay_us(5220);
}
void Send_0_Code(void)
{
// 数据位 0,540us 高电平,540us 低电平
TIM_SetCompare2(TIM2, 50);
delay_us(540);
TIM_SetCompare2(TIM2, 0);
delay_us(540);
}
void Send_1_Code(void)
{
// 数据位 1,540us 高电平,1620us 低电平
TIM_SetCompare2(TIM2, 50);
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 IR_Send(u8 A, u8 B, u8 C)
{
// A 识别码 固定为 0xB2 (1011 0010)
// B 风速
// 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();
}
完整代码
IR.c
#include "stm32f10x.h" // Device header
void PWM_Init(void)
{
// 38kHz 初始化
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); // PA1 引脚设置
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseStructure.TIM_Period = 101 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 19 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
void delay_us(uint32_t nus)
{
uint32_t temp;
SysTick -> LOAD = 9 * nus;
SysTick -> VAL = 0x00;
SysTick -> CTRL = 0x01;
do
{
temp = SysTick -> CTRL;
}while((temp & 0x01) && (!(temp & (1 << 16))));
SysTick -> CTRL = 0x00;
SysTick -> VAL = 0x00;
}
void Lead_Code(void)
{
// 引导码 4400us 高电平, 4400us 低电平
TIM_SetCompare2(TIM2, 50);
delay_us(4400);
TIM_SetCompare2(TIM2, 0);
delay_us(4400);
}
void Stop_Code(void)
{
// 结束码 540us 高电平,5220us 低电平
TIM_SetCompare2(TIM2, 50);
delay_us(540);
TIM_SetCompare2(TIM2, 0);
delay_us(5220);
}
void Send_0_Code(void)
{
// 数据位 0,540us 高电平,540us 低电平
TIM_SetCompare2(TIM2, 50);
delay_us(540);
TIM_SetCompare2(TIM2, 0);
delay_us(540);
}
void Send_1_Code(void)
{
// 数据位 1,540us 高电平,1620us 低电平
TIM_SetCompare2(TIM2, 50);
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 IR_Send(u8 A, u8 B, u8 C)
{
// A 识别码 固定为 0xB2 (1011 0010)
// B 风速
// 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();
}
IR.h
#ifndef __IR_H
#define __IR_H
void PWM_Init(void);
void IR_Send(u8 A, u8 B, u8 C);
#endif
验证
main.c
#include "stm32f10x.h" // Device header
#include "IR.h"
int main(void)
{
PWM_Init();
IR_Send(0xB2, 0xBF, 0xC0);
}