乐鑫技术交流
直播中

发烧友推温针

8年用户 807经验值
擅长:光电显示
私信 关注
[问答]

求助,关于ESP32C3 RMT红外编码器3bit数据编码问题求解

开发环境:
开发板:ESP32-C3-DEVKITM-1
IDE: Vscode esp-idf
操作系统:win10
IDF 版本:5.1.1

在使用RMT发射设置时,我发现esp-idf提供的例程只有对完整字节的处理,编码器时按照字节处理的。现在如果我有35bit的数据,应该怎样进行处理? 我需要处理的是前导码+35bit数据位+连接码+32bit数据位的数据

之前想用esp-idf 4版本的解决问题,但是4版本的选择不了时钟源

编码器部分:
esp_err_t rmt_new_ir_nec_encoder(const ir_nec_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder)
{
    esp_err_t ret = ESP_OK;
    //创建自定义编码器结构体,用于控制发送编码的流程
    rmt_ir_nec_encoder_t *nec_encoder = NULL;
    ESP_GOTO_ON_FALSE(config    ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
    nec_encoder = calloc(1, sizeof(rmt_ir_nec_encoder_t));
    ESP_GOTO_ON_FALSE(nec_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for ir nec encoder");
    nec_encoder->base.encode = rmt_encode_ir_nec;  //这个函数会在rmt发送数据的时候被调用,在这个函数增加额外代码进行控制
    nec_encoder->base.del = rmt_del_ir_nec_encoder;  //这个函数在卸载rmt时被调用
    nec_encoder->base.reset = rmt_ir_nec_encoder_reset; //这个函数在复位rmt时被调用

    rmt_copy_encoder_config_t copy_encoder_config = {};
    ESP_GOTO_ON_ERROR(rmt_new_copy_encoder( copy_encoder_config,  nec_encoder->copy_encoder), err, TAG, "create copy encoder failed");

    // 拷贝一个编码器,用于传输恒定字符,起始位和连接位
    nec_encoder->nec_leading_symbol = (rmt_symbol_word_t) {
        .level0 = 1,
        .duration0 = 4500ULL * config->resolution / 1000000,
        .level1 = 0,
        .duration1 = 9000ULL * config->resolution / 1000000,
    };
    nec_encoder->nec_ending_symbol = (rmt_symbol_word_t) {
        .level0 = 1,
        .duration0 = 20000ULL * config->resolution / 1000000,
        .level1 = 0,
        .duration1 = 600 * config->resolution / 1000000,
    };

    //新建一个编码器,用于0,1表示
   
    rmt_bytes_encoder_config_t bytes_encoder_config = {
        .bit0 = {  //
            .level0 = 1,
            .duration0 = 600 * config->resolution / 1000000, // T0H=560us
            .level1 = 0,
            .duration1 = 600 * config->resolution / 1000000, // T0L=560us
        },
        .bit1 = {
            .level0 = 1,
            .duration0 = 1600 * config->resolution / 1000000,  // T1H=560us
            .level1 = 0,
            .duration1 = 600 * config->resolution / 1000000, // T1L=1690us
        },
        .flags.msb_first = 1,
    };
    //传入编码器配置,获取数据编码器句柄
    ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder( bytes_encoder_config,  nec_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
    //返回编码器
    *ret_encoder =  nec_encoder->base;
    return ESP_OK;
err:
    if (nec_encoder) {
        if (nec_encoder->bytes_encoder) {
            rmt_del_encoder(nec_encoder->bytes_encoder);
        }
        if (nec_encoder->copy_encoder) {
            rmt_del_encoder(nec_encoder->copy_encoder);
        }
        free(nec_encoder);
    }
    return ret;
}

自定义 NEC 协议的 RMT 编码器
static size_t rmt_encode_ir_nec(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
    rmt_ir_nec_encoder_t *nec_encoder = __containerof(encoder, rmt_ir_nec_encoder_t, base);
    rmt_encode_state_t session_state = RMT_ENCODING_RESET;
    rmt_encode_state_t state = RMT_ENCODING_RESET;
    size_t encoded_symbols = 0;
    ir_nec_scan_code_t *scan_code = (ir_nec_scan_code_t *)primary_data;
    rmt_encoder_handle_t copy_encoder = nec_encoder->copy_encoder;
    rmt_encoder_handle_t bytes_encoder = nec_encoder->bytes_encoder;
    switch (nec_encoder->state) {
    case 0: // send leading code
        encoded_symbols += copy_encoder->encode(copy_encoder, channel,  nec_encoder->nec_leading_symbol,
                                                sizeof(rmt_symbol_word_t),  session_state);
        if (session_state   RMT_ENCODING_COMPLETE) {
            nec_encoder->state = 1; // we can only switch to next state when current encoder finished
        }
        if (session_state   RMT_ENCODING_MEM_FULL) {
            state |= RMT_ENCODING_MEM_FULL;
            goto out; // yield if there's no free space to put other encoding artifacts
        }
    // fall-through
    case 1: // send DATA_front 35bit
        encoded_symbols += bytes_encoder->encode(bytes_encoder, channel,  scan_code->command, sizeof(uint32_t),  session_state);
        if (session_state   RMT_ENCODING_COMPLETE) {
            nec_encoder->state = 2; // we can only switch to next state when current encoder finished
        }
        if (session_state   RMT_ENCODING_MEM_FULL) {
            state |= RMT_ENCODING_MEM_FULL;
            goto out; // yield if there's no free space to put other encoding artifacts
        }
    // fall-through
    case 2: //
        encoded_symbols += bytes_encoder->encode(bytes_encoder, channel,  scan_code->num, sizeof(ir_front_bit35),  session_state);
        if (session_state   RMT_ENCODING_COMPLETE) {
            nec_encoder->state = 3; // we can only switch to next state when current encoder finished
        }
        if (session_state   RMT_ENCODING_MEM_FULL) {
            state |= RMT_ENCODING_MEM_FULL;
            goto out; // yield if there's no free space to put other encoding artifacts
        }

    // fall-through
    case 3: // send connect code
        encoded_symbols += copy_encoder->encode(copy_encoder, channel,  nec_encoder->nec_ending_symbol,
                                                sizeof(rmt_symbol_word_t),  session_state);
        if (session_state   RMT_ENCODING_COMPLETE) {
            nec_encoder->state = 4; // we can only switch to next state when current encoder finished
        }
        if (session_state   RMT_ENCODING_MEM_FULL) {
            state |= RMT_ENCODING_MEM_FULL;
            goto out; // yield if there's no free space to put other encoding artifacts
        }
    // fall-through
    case 4: //send data_rear 32bit
        encoded_symbols += bytes_encoder->encode(bytes_encoder, channel,  scan_code->command1, sizeof(uint32_t),  session_state);
         if (session_state   RMT_ENCODING_COMPLETE) {
            nec_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
            state |= RMT_ENCODING_COMPLETE;
        }
        if (session_state   RMT_ENCODING_MEM_FULL) {
            state |= RMT_ENCODING_MEM_FULL;
            goto out; // yield if there's no free space to put other encoding artifacts
        }
    }
out:
    *ret_state = state;
    return encoded_symbols;
}

按照上面代码实际上3bit输出了8bit的数据
                                                                                                                                            

回帖(1)

vinww特烦恼

2024-7-19 14:37:32
您好!根据您的需求,您需要将35bit的数据通过ESP32-C3的RMT模块进行编码。以下是一些建议和步骤,帮助您实现这个目标。

1. **准备工作**:
   - 确保您的开发环境已经正确设置,包括ESP-IDF、VSCode和ESP32-C3开发板。

2. **了解RMT模块**:
   - ESP32-C3的RMT模块可以发送和接收PWM信号。在这里,我们将使用RMT模块发送红外信号。

3. **自定义编码器**:
   - 由于ESP-IDF提供的例程只处理完整字节,您需要自定义一个编码器来处理35bit的数据。您可以创建一个新的C文件(例如:`custom_encoder.c`),并实现以下函数:

```c
#include "esp_rmt.h"
#include "esp_log.h"

static const char *TAG = "CUSTOM_ENCODER";

esp_err_t custom_ir_encoder(const uint8_t *data, size_t data_size, rmt_item32_t *item, size_t *item_size) {
    size_t index = 0;
    for (size_t i = 0; i < data_size; i++) {
        for (int bit = 7; bit >= 0; bit--) {
            if (data[i] & (1 << bit)) {
                item[index++] = {{{1, 1, 0, 0, 0, 0, 0}, 0, 1}}; // 1 bit
            } else {
                item[index++] = {{{0, 1, 0, 0, 0, 0, 0}, 0, 0}}; // 0 bit
            }
        }
    }
    *item_size = index;
    return ESP_OK;
}
```

4. **发送数据**:
   - 在您的主程序中,创建一个RMT通道并初始化。然后,使用自定义编码器将35bit数据编码为RMT项目数组。

```c
#include "esp_rmt.h"
#include "custom_encoder.h"

#define RMT_CHANNEL RMT_CHANNEL_0
#define RMT_PIN 4

void app_main() {
    esp_rmt_config_t rmt_config = {
        .channel = RMT_CHANNEL,
        .gpio_num = RMT_PIN,
        .mem_block_num = 1,
        .clk_src = RMT_BASECLK_APB,
        .tx_config = {
            .loop_en = false,
            .carrier_freq_hz = 38000,
            .carrier_level = RMT_CARRIER_LEVEL_HIGH,
            .carrier_duty_percent = 33,
            .idle_level = RMT_IDLE_LEVEL_LOW,
            .idle_output_en = true,
        },
    };

    esp_err_t ret = esp_rmt_init(&rmt_config);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to initialize RMT: %d", ret);
        return;
    }

    uint8_t data[5] = {0x12, 0x34, 0x56, 0x78, 0x9A}; // 35bit data
    rmt_item32_t items[35];
    size_t item_size;

    ret = custom_ir_encoder(data, sizeof(data), items, &item_size);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to encode data: %d", ret);
        return;
    }

    ret = esp_rmt_write_items(RMT_CHANNEL, items, item_size, true);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to send data: %d", ret);
        return;
    }

    ESP_LOGI(TAG, "Data sent successfully");
}
```

5. **编译和烧录**:
   - 使用ESP-IDF构建系统编译您的程序,并将其烧录到ESP32-C3开发板上。

通过以上步骤,您应该能够实现将35bit数据通过ESP32-C3的RMT模块进行编码和发送。希望这些信息对您有所帮助!
举报

更多回帖

发帖
×
20
完善资料,
赚取积分