/* i2c - Simple example
Simple I2C example that shows how to initialize I2C
as well as reading and writing from and to registers for a sensor connected over I2C.
The sensor used in this example is a PCF85063 inertial measurement unit.
*/
#include <stdio.h>
#include "esp_log.h"
#include "driver/i2c.h"
static const char *TAG = "i2c-pcf85063";
#define I2C_MASTER_SDA_IO 36 //CONFIG_I2C_MASTER_SDA /*!< GPIO number used for I2C master data */
#define I2C_MASTER_SCL_IO 35 //CONFIG_I2C_MASTER_SCL /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS 1000
#define PCF85063_SENSOR_ADDR 0x51 /*!< Slave address of the PCF85063 sensor */
//注意:PCF85063秒寄存器0x04 ,PCF8563秒寄存器地址是0x02
#define PCF85063_SEC_REG_ADDR 0x04 /*!< Register addresses of the timer_second register */
//PCF85063_REG: sec=4,min=5,hour=6,day=7,week=8,month=9,year=10
typedef struct
{
int nYear;
int nMonth;
int nWeek;
int nDay;
int nHour;
int nMin;
int nSec;
} CTime;
//12=>0x12
uint8_t PCD85063TP_decToBcd(uint8_t val)
{
return ( (val/10*16) + (val%10) );
}
//0x12=>12
uint8_t PCD85063TP_bcdToDec(uint8_t val)
{
return ( (val/16*10) + (val%16) );
}
/**
* @brief Read a sequence of bytes from a PCF85063 sensor registers
*/
static esp_err_t PCF85063_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
{
return i2c_master_write_read_device(I2C_MASTER_NUM, PCF85063_SENSOR_ADDR, ®_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
}
/**
* @brief Write N byte to a PCF85063 sensor register
*/
static esp_err_t PCF85063_register_write(uint8_t reg_addr, uint8_t *data,int len)
{
int ret = 0;
uint8_t *wr_dat = (uint8_t*) malloc(len+1);
if(wr_dat==NULL)
return -1;
wr_dat[0] = reg_addr;
for(int i=0;i<len;i++)
{
wr_dat[i+1] = data[i];
}
ret = i2c_master_write_to_device(I2C_MASTER_NUM, PCF85063_SENSOR_ADDR, wr_dat, len+1, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
free(wr_dat);
return ret;
}
int PCF85063_get_Week(int y,int m,int d)
{
int week = 0;
if(m==1 || m == 2)
{
m += 12;
y--;
}
week=(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7;
//ret=0 星期天
//ret=N 星期N
return (week+1)%7;
}
//设置时间结构体,isAutoCalcWeek自动计算星期几
void PCF85063_setTime(CTime tm,int isAutoCalcWeek)
{
uint8_t data[7] = {0};
if (isAutoCalcWeek)
{
tm.nWeek = pcf8563_get_Week(tm.nYear, tm.nMonth, tm.nDay);
}
bool flag_19xx = true;
uint16_t yr = tm.nYear;
if (tm.nYear >= 2000)
{
flag_19xx = false;
yr -= 2000;
}
else
{
yr -= 1900;
}
data[0] = pcf8563_decToBcd(tm.nSec);
data[1] = pcf8563_decToBcd(tm.nMin);
data[2] = pcf8563_decToBcd(tm.nHour);
data[3] = pcf8563_decToBcd(tm.nDay);
data[4] = pcf8563_decToBcd(tm.nWeek);
data[5] = pcf8563_decToBcd(tm.nMonth);
data[6] = pcf8563_decToBcd(yr);
if (flag_19xx)
{
data[5] |= 0x80;
}
ESP_ERROR_CHECK(pcf8563_register_write(PCF8563_SEC_REG_ADDR, data, 7));
}
//获取年月日时分秒
bool PCF85063_getTime(CTime *tm)
{
uint8_t data[7] = {0};
ESP_ERROR_CHECK(PCF85063_register_read(PCF85063_SEC_REG_ADDR, data,7));
bool flag_19xx = (data[5] >> 7) & 0x01; // Year:19XX_Flag
bool flag_vl = (data[0] >> 7) & 0x01; //(Voltage Low)VL=1:初始数据不可靠
tm->nSec = PCD85063TP_bcdToDec( data[0]&0x7f );
tm->nMin = PCD85063TP_bcdToDec( data[1]&0x7f );
tm->nHour = PCD85063TP_bcdToDec( data[2]&0x3f );
tm->nDay = PCD85063TP_bcdToDec( data[3]&0x3f );
tm->nWeek = PCD85063TP_bcdToDec( data[4] );
tm->nMonth = PCD85063TP_bcdToDec( data[5]&0x1f );
tm->nYear = PCD85063TP_bcdToDec( data[6] ); //0~99
if (flag_19xx)
{
tm->nYear += 1900;
}
else
{
tm->nYear += 2000;
}
return flag_vl;
}
//格式1: 20xx/xx/xx xx:xx:xx
//格式0: xx:xx:xx
char *PCF85063_getTmString(int isYMD)
{
char tmStr[25]={0};
CTime tm;
PCF85063_getTime(&tm);
if( isYMD )
sprintf(tmStr,"20%02d/%02d/%02d %02d:%02d:%02d", tm.nYear,tm.nMonth,tm.nDay,tm.nHour,tm.nMin,tm.nSec );
else
sprintf(tmStr,"%02d:%02d:%02d", tm.nHour,tm.nMin,tm.nSec );
return tmStr;
}
/**
* @brief i2c master initialization
*/
static esp_err_t i2c_master_init(void)
{
int i2c_master_port = I2C_MASTER_NUM;
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
i2c_param_config(i2c_master_port, &conf);
return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
void test_loop_task()
{
int cnt = 0;
//日期初始化为: 22年10月(周1)24日,09:58:50
CTime tm={22,10,1,24,9,58,50};
PCF85063_setTime( tm ,1 );
while(1)
{
uint8_t data[10]={0};
ESP_ERROR_CHECK(PCF85063_register_read(PCF85063_SEC_REG_ADDR, data,7));
ESP_LOGI(TAG, "20%02X/%02X/%02X %02X:%02X:%02X_%X.", data[6],data[5],data[3],data[2],data[1]&0x7F,data[0]&0x7F,data[4] );
printf("cnt[%d].time=> %s \n ",cnt++,PCF85063_getTmString(1) );
vTaskDelay(100);//x10ms
}
}
void app_main(void)
{
uint8_t data[2];//M+S
ESP_ERROR_CHECK(i2c_master_init());
ESP_LOGI(TAG, "I2C initialized successfully,BUILD:[%s %s]",__DATE__,__TIME__);
/* Read the PCF85063 initial second+minute register */
ESP_ERROR_CHECK( PCF85063_register_read(PCF85063_SEC_REG_ADDR, data, 2) );
ESP_LOGI(TAG, "Initial read ,Sec= %02X ,Min = %02X", data[0]&0x7F,data[1]&0x7F );
vTaskDelay(150);
xTaskCreate(test_loop_task, "test_loop_task", 1024*10, NULL, 10, NULL);
}
PCF8563/85063 高精度时钟IIC芯片 ESP驱动程序
于 2022-10-24 10:15:51 首次发布