本文采用ESP32内部只带的RMT模块作为发送红外遥控的发射器。

红外协议来自 美的R05D功能说明书: https://wenku.baidu.com/view/c46594141ed9ad51f01df2c3.html

  1. 通常编码格式为: L,A,A’,B,B’,C,C’, S, L,A,A’,B,B’,C,C’ T
  2. 第一帧和第二帧相同
  3. 采用MSB在先,LSB在后;也就是高位先发
  4. L为引导码;S为分隔码;A为识别码(A=10110010=0xB2,预留方案时A=10110111=0xB7),A’为A的反码;B’为B的反码;C’为C的反码。T为终结码
  5. 数据B,C的部分含义如下图

[ESP32] 用RMT模块做红外遥控发射-LMLPHP

开机码: b2 4d bf 40 d0 2f - b2 4d bf 40 d0 2f        【自动风,26度,制冷】

关机码: b2 4d 7b 84 e0 1f -b2 4d 7b 84 e0 1f       【B2位是开关位】

工程模式:b9 46 f7 08 00 ff-b9 46 f7 08 00 ff

灯光码:b5 4a f5 0a a5 5a -b5 4a f5 0a a5 5a

 6.引导码 Lead : 4400us 低 + 4400us高

7.分割码 Split : 540us 低 + 5220us 高

8. 发送Bit1 :  540us 低 + 1620us 高

9. 发送Bit0: 540us 低 + 540us 高

10.终结符 Terminator: 540us 低 + 一直高

11.两个控制帧信号间最小间隔>5.22ms


#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/rmt.h"
#include "driver/gpio.h"

// 编码格式:L AA` BB` CC`  S L AA` BB` CC`  T [共48*2+3=99Bits]
// value 1: High, 0:Low
#define FRAMES_LEN_MAX 99
static rmt_item32_t g_encode_frame[FRAMES_LEN_MAX] =
    {
        {{{4400, 0, 4400, 1}}}, // Leading
};

#define KEY_1 45
#define KEY_2 46
#define GPIO_INPUT_PIN_SEL ((1ULL << KEY_1) | (1ULL << KEY_2))

#define LED_R 47
#define LED_G 48
#define LED_B 41
#define GPIO_OUTPUT_PIN_SEL ((1ULL << LED_R) | (1ULL << LED_G) | (1ULL << LED_B))

void sleep_ms(int ms)
{
    vTaskDelay(pdMS_TO_TICKS(ms));
}

static void led_gpio_init()
{

    gpio_config_t io_conf; // 定义一个gpio_config类型的结构体,下面的都算对其进行的配置

    io_conf.intr_type = GPIO_INTR_DISABLE;      // 禁止中断
    io_conf.mode = GPIO_MODE_OUTPUT;            // 选择输出模式
    io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; // 配置GPIO_OUT寄存器
    io_conf.pull_up_en = 1;
    io_conf.pull_down_en = 0;

    gpio_config(&io_conf);

    io_conf.intr_type = GPIO_INTR_DISABLE;
    io_conf.mode = GPIO_MODE_INPUT;            // 选择输入模式
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL; // 配置GPIO_INPUT寄存器
    io_conf.pull_up_en = 1;
    io_conf.pull_down_en = 1;
    gpio_config(&io_conf);
}

void led_color_set(uint8_t r, uint8_t g, uint8_t b)
{
    gpio_set_level(LED_R, r);
    gpio_set_level(LED_G, g);
    gpio_set_level(LED_B, b);
}

void set_item_date(int item_index, uint16_t duration0, uint8_t level0, uint16_t duration1, uint8_t level1)
{
    g_encode_frame[item_index].duration0 = duration0;
    g_encode_frame[item_index].level0 = level0;
    g_encode_frame[item_index].duration1 = duration1;
    g_encode_frame[item_index].level1 = level1;
}

void make_one_byte_data(int item_index, uint8_t byte_value)
{
    uint8_t bit_value = 0;

    for (int i = 7; i >= 0; i--)
    {
        bit_value = (byte_value >> i) & 0x01;

        if (bit_value == 1)
            set_item_date(item_index++, 540, 0, 1620, 1); // BIT1
        else
            set_item_date(item_index++, 540, 0, 540, 1); // BIT0
    }
}

// 设置整帧数据,共99bit数据
void make_frame_date(uint8_t byteA, uint8_t byteB, uint8_t byteC)
{
    int item_index = 0;

    set_item_date(item_index++, 4400, 0, 4400, 1); // leading code

    make_one_byte_data(item_index, byteA);
    item_index += 8;
    make_one_byte_data(item_index, ~byteA);
    item_index += 8;

    make_one_byte_data(item_index, byteB);
    item_index += 8;
    make_one_byte_data(item_index, ~byteB);
    item_index += 8;

    make_one_byte_data(item_index, byteC);
    item_index += 8;
    make_one_byte_data(item_index, ~byteC);
    item_index += 8;

    set_item_date(item_index++, 540, 0, 5220, 1); // splice code

    make_one_byte_data(item_index, byteA);
    item_index += 8;
    make_one_byte_data(item_index, ~byteA);
    item_index += 8;

    make_one_byte_data(item_index, byteB);
    item_index += 8;
    make_one_byte_data(item_index, ~byteB);
    item_index += 8;

    make_one_byte_data(item_index, byteC);
    item_index += 8;
    make_one_byte_data(item_index, ~byteC);
    item_index += 8;

    set_item_date(item_index++, 540, 0, 0, 1); // ending code
}

static void rmt_tx_init(void)
{
    // 01 rmt driver共有部分
    rmt_config_t rmt;
    rmt.channel = RMT_CHANNEL_0; // RMT有0-7共8通道
    rmt.clk_div = 80;            // 默认的时钟是80MHZ,分频器是8位的,如果80分频,每个Tick是1us
    rmt.mem_block_num = 1;       // 默认每个通道使用1个block。一共block是64x32bit 这么大。 也就是能储存128个数据
    rmt.rmt_mode = RMT_MODE_TX;  // 配置发送模式
    rmt.gpio_num = GPIO_NUM_1;   // 自定义红外发射引脚

    // 02 配置tx独有的部分
    rmt.tx_config.carrier_en = true;                     // 打开载波
    rmt.tx_config.carrier_freq_hz = 38000;               // 38khz载波
    rmt.tx_config.carrier_duty_percent = 50;             // 占空比50%
    rmt.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; // 载波默认为高电平H
    rmt.tx_config.idle_output_en = true;                 // 空闲输出打开
    rmt.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH;      // 空闲时候为低电平L
    rmt.tx_config.loop_en = false;                       // 关闭持续发送

    // 03 进行配置, 加载配置
    rmt_config(&rmt);
    rmt_driver_install(RMT_CHANNEL_0, 0, 0); // 发送不需要缓冲区,中断级别默认
}

void app_main()
{
    printf("configTICK_RATE_HZ=%d.build at:[%s %s] \n", configTICK_RATE_HZ, __DATE__, __TIME__);

    rmt_tx_init();
    led_gpio_init();

    
    int cnt = 0;
    while (1)
    {
        //循环发送测试
        printf("sendA index:%d \n", ++cnt);
        make_frame_date(0xb2, 0xbf, 0xd0); // power_on [自动风,26度,制冷]
        led_color_set(1, 0, 0);
        rmt_write_items(RMT_CHANNEL_0, g_encode_frame, FRAMES_LEN_MAX, true);
        sleep_ms(1500);

        printf("sendB index:%d \n", ++cnt);
        make_frame_date(0xb2, 0xbf, 0xbc); // power_on [自动风,30度,制热]
        led_color_set(0, 1, 0);
        rmt_write_items(RMT_CHANNEL_0, g_encode_frame, FRAMES_LEN_MAX, true);
        sleep_ms(1500);

        printf("sendC index:%d \n", ++cnt);
        make_frame_date(0xb9, 0xf7, 0x00); // 工程模式
        led_color_set(0, 0, 1);
        rmt_write_items(RMT_CHANNEL_0, g_encode_frame, FRAMES_LEN_MAX, true);
        sleep_ms(1500);

        printf("sendD index:%d \n", ++cnt);
        make_frame_date(0xb2, 0x7b, 0xe0); // power_off
        led_color_set(1, 1, 1);
        rmt_write_items(RMT_CHANNEL_0, g_encode_frame, FRAMES_LEN_MAX, true);
         sleep_ms(1500);
    }
}
04-08 17:09