ESP32+BM8563

一、参考

昨天调试了一下BM8563,记录一下完整流程

  1. 参考源码:https://github.com/brettdavidsilverman/bee.fish/tree/9090187baccfdcf6f3045c12d1283fb9e26de665/archive/FeebeeCam/components/bm8563
  2. 数据手册:https://atta.szlcsc.com/upload/public/pdf/source/20220728/5C738140B1563414A58F0126BA001473.pdf

二、程序修改

  1. 参考上面的源码,我们直接写bm8563.c,bm8563.h
    这里有几点需要注意
    (1).I2C 总线从地址:读,0A3H;写,0A2H,程序对应 0x51 << 7
    (2).下面程序修改成自己的sda和scl引脚
    (3).有一个小漏洞需要修复(自行参考手册BCD码),10月份及以上月份读取会出问题
    data->month = BCD2Byte(time_buf[5] & 0x0f);
    修改成
    data->month = BCD2Byte(time_buf[5] & 0x1f);
    即可
    (4).偶现一个问题,i2c_config需要加上static,参考:https://blog.csdn.net/weixin_43242337/article/details/124221546

    bm8563.c:

    #include "bm8563.h"
    #include "driver/i2c.h"
    #include <string.h>
    
    #undef ESP_ERROR_CHECK
    #define ESP_ERROR_CHECK(x)   do { esp_err_t rc = (x); if (rc != ESP_OK) { ESP_LOGE("err", "esp_err_t = %d, line = %d", rc, __LINE__); } } while(0);
    #define I2C_NUM 2
    
    void i2c_init() {
    	static i2c_config_t conf;
    	conf.mode = I2C_MODE_MASTER;
    	conf.sda_io_num = (gpio_num_t)12;
    	conf.scl_io_num = (gpio_num_t)14;
    	conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    	conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    	conf.master.clk_speed = 100000;
    	ESP_ERROR_CHECK(i2c_param_config(I2C_NUM, &conf));
    	ESP_ERROR_CHECK(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0));
    }
    
    void i2c_write(uint8_t slave_addr, uint8_t addr, uint8_t* buf, uint8_t len) {
        i2c_cmd_handle_t cmd;
        cmd = i2c_cmd_link_create();
        ESP_ERROR_CHECK(i2c_master_start(cmd));
    	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, 1));
    	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, addr, 1));
    	ESP_ERROR_CHECK(i2c_master_write(cmd, buf, len, 1));
        ESP_ERROR_CHECK(i2c_master_stop(cmd));
    	ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM, cmd, 1000/portTICK_PERIOD_MS));
    	i2c_cmd_link_delete(cmd);
    }
    
    void i2c_write_byte(uint8_t slave_addr, uint8_t addr, uint8_t data) {
        i2c_write(slave_addr, addr, &data, 1);
    }
    
    uint8_t i2c_read(uint8_t slave_addr, uint8_t addr, uint8_t* buf, uint8_t len) {
        i2c_cmd_handle_t cmd;
    	cmd = i2c_cmd_link_create();
    	ESP_ERROR_CHECK(i2c_master_start(cmd));
    	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, 1));
    	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, addr, 1));
    	ESP_ERROR_CHECK(i2c_master_stop(cmd));
    	ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM, cmd, 1000/portTICK_PERIOD_MS));
    	i2c_cmd_link_delete(cmd);
    
        cmd = i2c_cmd_link_create();
        ESP_ERROR_CHECK(i2c_master_start(cmd));
    	ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_READ, 1));
    	
        if (len>1) {
            ESP_ERROR_CHECK(i2c_master_read(cmd, buf, len - 1,I2C_MASTER_ACK));
        }
    
    	ESP_ERROR_CHECK(i2c_master_read_byte(cmd, &buf[len-1], I2C_MASTER_NACK));
        ESP_ERROR_CHECK(i2c_master_stop(cmd));
    	ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM, cmd, 1000/portTICK_PERIOD_MS));
    	i2c_cmd_link_delete(cmd);
        return 0;
    }
    
    static uint8_t byte2BCD(uint8_t data) {
        return ((data / 10) << 4) + data % 10;
    }
    
    static uint8_t BCD2Byte(uint8_t data) {
        return (data >> 4) * 10 + (data & 0x0f);
    }
    
    void bm8563_init() {
        i2c_init();
        i2c_write_byte(0x51, 0x00, 0x00);
        i2c_write_byte(0x51, 0x01, 0x00);
        i2c_write_byte(0x51, 0x0D, 0x00);
    }
    
    void bm8563_setTime(rtc_date_t* data) {
        if (data == NULL) {
            return ;
        }
        uint8_t time_buf[7];
        time_buf[0] = byte2BCD(data->second);
        time_buf[1] = byte2BCD(data->minute);
        time_buf[2] = byte2BCD(data->hour);
        time_buf[3] = byte2BCD(data->day);
        time_buf[5] = byte2BCD(data->month) | (data->year >= 2000 ? 0x00 : 0x80);
        time_buf[6] = byte2BCD(data->year % 100);
        i2c_write(0x51, 0x02, time_buf, 7);
    }
    
    void bm8563_getTime(rtc_date_t* data) {
        if (data == NULL) {
            return ;
        }
        uint8_t time_buf[7];
        i2c_read(0x51, 0x02, time_buf, 7);
        data->second = BCD2Byte(time_buf[0] & 0x7f);
        data->minute = BCD2Byte(time_buf[1] & 0x7f);
        data->hour = BCD2Byte(time_buf[2] & 0x3f);
        data->day = BCD2Byte(time_buf[3] & 0x3f);
        data->month = BCD2Byte(time_buf[5] & 0x1f);
        data->year = BCD2Byte(time_buf[6]) + (time_buf[5] & 0x80 ? 1900 : 2000);
    }
    
    // -1 :disable
    void bm8563_setDateIRQ(int8_t minute, int8_t hour, int8_t day, int8_t week) {
        uint8_t irq_enable = false;
        uint8_t out_buf[4] = { 0x80, 0x80, 0x80, 0x80 };
        if(minute >= 0) {
            irq_enable = true;
            out_buf[0] = byte2BCD(minute) & 0x7f;
        }
    
        if(hour >= 0) {
            irq_enable = true;
            out_buf[1] = byte2BCD(hour) & 0x3f;
        }
    
        if(day >= 0) {
            irq_enable = true;
            out_buf[2] = byte2BCD(day) & 0x3f;
        }
    
        if(week >= 0) {
            irq_enable = true;
            out_buf[3] = byte2BCD(week) & 0x07;
        }
    
        uint8_t reg_value = 0;
        i2c_read(0x51, 0x01, &reg_value, 1);
        if (irq_enable) {
            reg_value |= (1 << 1);
        } else {
            reg_value &= ~(1 << 1);
        }
    
        i2c_write(0x51, 0x09, out_buf, 4);
        i2c_write(0x51, 0x01, &reg_value, 1);
    }
    
    // -1: disable
    int16_t bm8563_setTimerIRQ(int16_t value) {
        uint8_t reg_value = 0;
        i2c_read(0x51, 0x01, &reg_value, 1);
    
        if (value < 0) {
            reg_value &= ~(1 << 0);
            i2c_write(0x51, 0x01, &reg_value, 1);
            reg_value = 0x03;
            i2c_write(0x51, 0x0E, &reg_value, 1);
            return -1;
        }
    
        uint8_t type_value = 2;
        uint8_t div = 1;
        if (value > 255) {
            div = 60;
            type_value = 0x83;
        } else {
            type_value = 0x82;
        }
        value = (value / div) & 0xFF;
        i2c_write(0x51, 0x0F, (uint8_t *)&value, 1);
        i2c_write(0x51, 0x0E, &type_value, 1);
    
        reg_value |= (1 << 0);
        reg_value &= ~(1 << 7);
        i2c_write(0x51, 0x01, &reg_value, 1);
        return value * div;
    }
    
    int16_t bm8563_getTimerTime() {
        uint8_t value = 0;
        uint8_t type_value = 0;
        i2c_read(0x51, 0x0f, &value, 1);
        i2c_read(0x51, 0x0e, &type_value, 1);
    
        if ((type_value & 0x03) == 3) {
            return value * 60;
        } else {
            return value;
        }
    }
    
    uint8_t bm8563_getIRQ() {
        uint8_t data;
        i2c_read(0x51, 0x01, &data, 1);
        return data;
    }
    
    void bm8563_clearIRQ() {
        uint8_t data;
        i2c_read(0x51, 0x01, &data, 1);
        i2c_write_byte(0x51, 0x01, data & 0xf3);
    }
    

    bm8563.h

    #include "esp_log.h"
    
    typedef struct _rtc_date_t {
        uint16_t year;
        uint8_t month;
        uint8_t day;
        uint8_t hour;
        uint8_t minute;
        uint8_t second;
    } rtc_date_t;
    
    // Clear irq, Init 
    void bm8563_init();
    
    void bm8563_setTime(rtc_date_t* data);
    
    void bm8563_getTime(rtc_date_t* data);
    
    // -1: disable
    void bm8563_setDateIRQ(int8_t minute, int8_t hour, int8_t day, int8_t week);
    
    // sec, max time is 255 * 60
    int16_t bm8563_setTimerIRQ(int16_t value);
    
    // sec, get timer reg value
    int16_t bm8563_getTimerTime();
    
    // get irq status
    uint8_t bm8563_getIRQ();
    
    // clear irq status
    void bm8563_clearIRQ();
    
<think>嗯,用户想找关于ESP32-S3芯片和蓝牙麦克风的设计方案或实现方法。首先,我需要回忆一下ESP32-S3的特性。根据引用[3]和[4],ESP32-S3支持蓝牙5(LE)和Mesh,还有双核处理器,适合AI应用。蓝牙麦克风的话,可能涉及到音频采集和传输。 用户可能需要硬件选型方面的建议,比如麦克风模块的选择。引用[5]提到了INMP441,这是一个数字麦克风,但它是通过I2S接口连接的,不是蓝牙。所以蓝牙麦克风可能需要另外的方案。或者,是否可以使用BLE音频传输?不过BLE的传统音频可能带宽不够,但最新的LE Audio可能有帮助,但需要确认ESP32-S3是否支持。根据引用[3],它支持蓝牙5和Coded PHY,可能支持一些扩展,但LE Audio可能需要特定协议栈支持。 另外,引用[5]中的方案是使用INMP441和MAX98357,结合百度AI实现在线语音助手,但这是通过Wi-Fi传输的。用户可能想用蓝牙传输音频数据,比如将麦克风的数据通过BLE发送到ESP32-S3,或者反过来。或者,使用ESP32-S3作为蓝牙主机接收来自其他蓝牙麦克风设备的数据? 可能需要分几个部分:硬件连接、蓝牙协议选择、音频编码、软件实现。比如,使用ESP-IDF中的蓝牙例程,配置HFP(Hands-Free Profile)或A2DP(高级音频分发规范),但A2DP通常是用于音乐传输,延迟较高。HFP可能更适合语音,但需要确认麦克风作为蓝牙从设备时的角色。 另外,引用[4]提到ESP32-S3有丰富的接口,如I2S,可能可以连接数字麦克风,再通过蓝牙传输数据。比如,用I2S读取麦克风数据,然后通过BLE传输,但需要考虑数据量和实时性。或者,使用内置的蓝牙协议栈实现音频流的传输。 需要检查ESP-IDF是否有相关的示例,比如SPP(串口协议)传输音频数据,或者使用BLE的自定义服务。但音频数据量大,BLE可能不够,需要考虑压缩。或者,使用经典蓝牙的A2DP源或接收端。 可能的实现步骤:1. 硬件连接麦克风模块到ESP32-S3的I2S或PDM接口。2. 配置蓝牙音频协议,如A2DP或HFP。3. 采集音频数据并编码传输。4. 接收端处理或转发到服务器。 同时,引用[5]使用了百度AI,可能用户需要将音频传输到云端处理,所以蓝牙麦克风采集后通过Wi-Fi上传?或者直接在本地处理?需要明确用户的需求。如果是蓝牙麦克风作为输入设备,可能需ESP32-S3作为主机连接蓝牙麦克风,但需要麦克风支持BLE音频传输。 总结可能的方案:使用ESP32-S3的蓝牙功能连接外部BLE麦克风模块,或者通过I2S连接数字麦克风,再通过蓝牙传输数据。具体实现可能需要参考Espressif的文档和示例代码,比如使用I2S采集音频,然后通过BLE传输,或者使用经典蓝牙协议。</think>### ESP32-S3蓝牙麦克风设计方案及实现方式 #### 一、硬件设计要点 1. **麦克风选型** - 数字麦克风(如INMP441)通过I2S接口连接,支持高精度音频采集[^5] - 模拟麦克风需搭配ADC模块(如MAX4466)进行信号转换 - 蓝牙麦克风模块(如BM83)可直连ESP32-S3的蓝牙协议栈 2. **核心硬件配置** ```text ESP32-S3芯片 ├── 双核Xtensa LX7处理器(支持AI加速指令)[^4] ├── 蓝牙5.0 LE(支持Coded PHY远距离通信)[^3] ├── I2S接口(连接数字麦克风) └── SPI/I2C接口(外接编解码芯片) ``` #### 二、蓝牙音频协议选择 | 协议类型 | 适用场景 | 传输速率 | 延迟 | |---------|---------|---------|-----| | BLE Audio | 语音指令传输 | 1-2Mbps | 20-50ms | | A2DP | 高质量音频流 | 2-3Mbps | 100-200ms | 建议采用BLE Audio协议实现低功耗语音传输[^3] #### 三、软件实现流程 ```mermaid graph TD A[音频采集] --> B[蓝牙协议封装] B --> C{传输模式选择} C -->|实时传输| D[使用BLE ISO通道] C -->|批量传输| E[BLE GATT数据分片] D/E --> F[接收端解码] F --> G[语音识别/存储] ``` #### 四、关键代码示例(基于ESP-IDF) ```c // 初始化I2S麦克风 i2s_config_t i2s_config = { .mode = I2S_MODE_MASTER | I2S_MODE_RX, .sample_rate = 16000, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT }; i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); // 配置BLE音频服务 esp_ble_audio_cfg_t audio_cfg = { .codec_type = ESP_BLE_AUDIO_CODEC_CVSD, .sample_rate = ESP_BLE_AUDIO_SAMPLE_RATE_16K, .channel_num = ESP_BLE_AUDIO_CHANNEL_MONO }; esp_ble_audio_stream_start(&audio_cfg); ``` #### 五、低功耗优化 1. 动态调整采样率(8kHz-16kHz) 2. 采用ESP32-S3的ULP协处理器处理静音检测[^3] 3. 蓝牙连接间隔优化(7.5ms-4s) 4. 深度睡眠模式唤醒策略
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值