美的空调 R05D 红外协议研究(二)

技术 · 05-20 · 514 人浏览

前言

上一篇文章分析了美的空调 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);
}
Theme Jasmine by Kent Liao