本文采用ESP32内部只带的RMT模块作为发送红外遥控的发射器。
红外协议来自 美的R05D功能说明书: https://wenku.baidu.com/view/c46594141ed9ad51f01df2c3.html
- 通常编码格式为: L,A,A’,B,B’,C,C’, S, L,A,A’,B,B’,C,C’ T
- 第一帧和第二帧相同
- 采用MSB在先,LSB在后;也就是高位先发
- L为引导码;S为分隔码;A为识别码(A=10110010=0xB2,预留方案时A=10110111=0xB7),A’为A的反码;B’为B的反码;C’为C的反码。T为终结码
- 数据B,C的部分含义如下图
开机码: 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);
}
}