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();
    
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ESP32是一款32位的微控制器,而ESP-IDF是官方提供的用于开发ESP32的软件开发框架。Clion是一款集成开发环境(IDE),可以用于开发和调试ESP32项目。 在使用Clion进行ESP32开发之前,需要先搭建好ESP-IDF和Clion的开发环境。以下是搭建ESP32+Clion开发环境的步骤: 1. 安装ESP-IDF:根据官方文档的指引,下载并安装ESP-IDF。确保安装的是与你的ESP32兼容的版本。 2. 安装Clion:下载并安装Clion,确保安装的是最新版本。 3. 配置ESP-IDF路径:打开Clion,进入File -> Settings -> Build, Execution, Deployment -> CMake,将ESP-IDF的路径添加到"CMake Options"中。例如,如果ESP-IDF安装在`/path/to/esp-idf`,则添加以下内容: ``` -DCMAKE_TOOLCHAIN_FILE=/path/to/esp-idf/tools/cmake/toolchain-esp32.cmake ``` 4. 创建ESP32项目:在Clion中创建一个新的CMake项目,并将ESP-IDF的示例项目导入到Clion中。可以通过以下命令将示例项目复制到你的项目目录中: ``` cp -r /path/to/esp-idf/examples/get-started/hello_world /path/to/your/project ``` 5. 配置CMakeLists.txt:打开项目中的CMakeLists.txt文件,并根据你的项目需求进行配置。确保设置了正确的目标硬件和端口。 6. 构建和烧录:在Clion中点击Build按钮,Clion将自动构建项目并生成可执行文件。然后,使用ESP-IDF提供的烧录工具将可执行文件烧录到ESP32上。 7. 调试:在Clion中配置调试器,可以使用GDB进行调试。在调试过程中,可以设置断点、查看变量的值等。 请注意,以上步骤仅为搭建ESP32+Clion开发环境的基本步骤,具体的配置和操作可能会因个人需求和环境而有所不同。建议参考ESP-IDF和Clion的官方文档以获取更详细的指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值