一、参考
昨天调试了一下BM8563,记录一下完整流程
- 参考源码:https://github.com/brettdavidsilverman/bee.fish/tree/9090187baccfdcf6f3045c12d1283fb9e26de665/archive/FeebeeCam/components/bm8563
- 数据手册:https://atta.szlcsc.com/upload/public/pdf/source/20220728/5C738140B1563414A58F0126BA001473.pdf
二、程序修改
-
参考上面的源码,我们直接写
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/124221546bm8563.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, ®_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, ®_value, 1); } // -1: disable int16_t bm8563_setTimerIRQ(int16_t value) { uint8_t reg_value = 0; i2c_read(0x51, 0x01, ®_value, 1); if (value < 0) { reg_value &= ~(1 << 0); i2c_write(0x51, 0x01, ®_value, 1); reg_value = 0x03; i2c_write(0x51, 0x0E, ®_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, ®_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();