硬件I2C的使用_沁恒CH585evt_kp69100电量计
GPIOB_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13, GPIO_ModeIN_PU);
I2C_Init(I2C_Mode_I2C, 100000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_7bit, MASTER_ADDR); //初始化了 I2C 接口,设置了通信速率为 100kHz
-
初始化SDA/SCL,配置为上拉输入模式,根据芯片手册,需要时会自动开漏输出
![1149ad9b-b78f-408c-ab91-800312fb34ea]()
-
I2C_Init:
I2C_Mode:支持主模式/从模式
I2C_ClockSpeed:最大400KHz
I2C_DutyCycle:快速模式中时钟线的占空比
I2C_Ack:使能ACK
I2C_AckAddr:ACK 7位或10位地址
I2C_OwnAddress1:本机地址 -
以电量计KPL69100为例使用硬件I2C读写寄存器,在TMOS任务系统中实现每秒读取一次数据
-
master: CH585EVT slave:KPL69100
/**
* @brief first send slave addr for wake up, sencond send slave addr is real send addr
*
* @return uint8_t
*/
static uint8_t KP691000_Send_Slave_Address()
{
// first time send slave address to wake up
I2C_GenerateSTART(ENABLE); //start i2c
timeout_count_1ms = 0;
while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) //master mode selectd
{
if(timeout_count_1ms >I2C_TIMEOUT_MS)
{
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
I2C_Send7bitAddress(KP691000_SLAVE_ADDR_7BIT, I2C_Direction_Transmitter); //send slave address
I2C_GenerateSTOP(ENABLE);
DelayMs(1);//if dont delay, cant work
// second time send slave address
I2C_GenerateSTART(ENABLE); //start i2c
timeout_count_1ms = 0;
while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) //master mode selectd
{
if(timeout_count_1ms >I2C_TIMEOUT_MS)
{
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
I2C_Send7bitAddress(KP691000_SLAVE_ADDR_7BIT, I2C_Direction_Transmitter); //send slave address
}
/**
* @brief read reg value
*
* @param slave_adress
* @param reg_adress
* @param cb_data
* @param len
* @return uint8_t true or false
*/
static uint8_t KP691000_Read_Data(uint8_t slave_adress, uint8_t reg_adress, uint8_t *cb_data, uint16_t len)
{
uint32_t temp_data =0;
timeout_count_1ms = 0;
while(I2C_GetFlagStatus(I2C_FLAG_BUSY) != RESET) //if busy
{
if(timeout_count_1ms >I2C_TIMEOUT_MS)
{
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
KP691000_Send_Slave_Address();
timeout_count_1ms = 0;
while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //if master transmitter
{
if(timeout_count_1ms >I2C_TIMEOUT_MS)
{
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
//send reg address
if(I2C_GetFlagStatus(I2C_FLAG_TXE) != RESET)
{
I2C_SendData(reg_adress);
}
//read data
I2C_GenerateSTART(ENABLE);
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT))
{
if(timeout_count_1ms >I2C_TIMEOUT_MS)
{
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
I2C_Send7bitAddress(KP691000_SLAVE_ADDR_7BIT, I2C_Direction_Receiver); //send slave address
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if(timeout_count_1ms >I2C_TIMEOUT_MS)
{
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
//receive data
for(uint8_t i = 0; i < len; i++)
{
if(i == len - 1)
{
I2C_AcknowledgeConfig(DISABLE);
}
timeout_count_1ms = 0;
while (!I2C_GetFlagStatus(I2C_FLAG_RXNE)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) {
I2C_GenerateSTOP(ENABLE);
I2C_AcknowledgeConfig(ENABLE);
return FALSE;
}
}
cb_data[i] = I2C_ReceiveData(); //receive data
}
I2C_GenerateSTOP(ENABLE);
I2C_AcknowledgeConfig(ENABLE); // recover ack
return TRUE;
}
/**
* @brief write DF
*
* @param slave_adress
* @param reg_adress
* @param wrwrite_buf
* @param len
* @return uint8_t
*/
uint8_t KP691000_DF_Write_Data(uint16_t df_adress, uint8_t reg_adress, uint8_t *pdata, uint16_t len)
{
uint8_t block[2 + len]; // total Block
block[0] = (uint8_t)(df_adress & 0xFF); // DF_addr_low
block[1] = (uint8_t)((df_adress >> 8) & 0xFF); // DF_addr_high
if (len > 0 && pdata != NULL) {
memcpy(&block[2], pdata, len);
}
timeout_count_1ms = 0;
while(I2C_GetFlagStatus(I2C_FLAG_BUSY) != RESET) //if busy
{
if(timeout_count_1ms >I2C_TIMEOUT_MS)
{
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
I2C_GenerateSTART(ENABLE);
KP691000_Send_Slave_Address();
// send reg address
while (!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) {
I2C_GenerateSTOP(I2C_TIMEOUT_MS);
return FALSE;
}
}
I2C_SendData(reg_adress);
// send block
for (uint8_t i = 0; i < sizeof(block); i++) {
// wait for buf empty
timeout_count_1ms = 0;
while (!I2C_GetFlagStatus(I2C_FLAG_TXE)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) {
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
I2C_SendData(block[i]);
// wait for transmitted
if (i < sizeof(block) - 1) {
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) {
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
}
}
// wait for transmitted
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) {
I2C_GenerateSTOP(ENABLE);
return FALSE;
}
}
// send stop
I2C_GenerateSTOP(ENABLE);
return TRUE;
}
/**
* @brief read DF data
*
* @param df_adress
* @param reg_adress
* @param pdata
* @param len
* @return uint8_t
*/
uint8_t KP691000_DF_Read_Data(uint16_t df_adress, uint8_t reg_adress, uint8_t *pdata, uint16_t len)
{
uint8_t addr_block[2];
addr_block[0] = (uint8_t)(df_adress & 0xFF);
addr_block[1] = (uint8_t)((df_adress >> 8) & 0xFF);
uint8_t total_read = 2 + len;
uint8_t read_buf[total_read];
// try 3 times
for (uint8_t attempt = 0; attempt < 3; attempt++) {
// if busy
timeout_count_1ms = 0;
while (I2C_GetFlagStatus(I2C_FLAG_BUSY)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) {
I2C_GenerateSTOP(ENABLE);
goto retry;
}
}
// wake up
I2C_GenerateSTART(ENABLE);
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) { I2C_GenerateSTOP(ENABLE); goto retry; }
}
I2C_Send7bitAddress(KP691000_SLAVE_ADDR_7BIT, I2C_Direction_Transmitter);
I2C_GenerateSTOP(ENABLE);
DelayMs(1);
// send slave addr
I2C_GenerateSTART(ENABLE);
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) { I2C_GenerateSTOP(ENABLE); goto retry; }
}
I2C_Send7bitAddress(KP691000_SLAVE_ADDR_7BIT, I2C_Direction_Transmitter);
timeout_count_1ms = 0;
// wait ack
while (1) {
if (I2C_GetFlagStatus(I2C_FLAG_AF)) { // NACK 立即重试
I2C_ClearFlag(I2C_FLAG_AF);
I2C_GenerateSTOP(ENABLE);
goto retry;
}
if (I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) break;
if (timeout_count_1ms > I2C_TIMEOUT_MS) {
I2C_GenerateSTOP(ENABLE);
goto retry;
}
}
// send reg address
I2C_SendData(reg_adress);
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) { I2C_GenerateSTOP(ENABLE); goto retry; }
}
// send block
for (int i = 0; i < 2; i++) {
I2C_SendData(addr_block[i]);
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) { I2C_GenerateSTOP(ENABLE); goto retry; }
}
}
// receive
I2C_GenerateSTART(ENABLE);
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) { I2C_GenerateSTOP(ENABLE); goto retry; }
}
I2C_Send7bitAddress(KP691000_SLAVE_ADDR_7BIT, I2C_Direction_Receiver);
timeout_count_1ms = 0;
while (!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) { I2C_GenerateSTOP(ENABLE); goto retry; }
}
// read data
for (int i = 0; i < total_read; i++) {
if (i == total_read - 1) {
I2C_AcknowledgeConfig(DISABLE);
}
timeout_count_1ms = 0;
while (!I2C_GetFlagStatus(I2C_FLAG_RXNE)) {
if (timeout_count_1ms > I2C_TIMEOUT_MS) {
I2C_AcknowledgeConfig(ENABLE); I2C_GenerateSTOP(ENABLE); goto retry;
}
}
read_buf[i] = I2C_ReceiveData();
}
I2C_GenerateSTOP(ENABLE);
I2C_AcknowledgeConfig(ENABLE);
// check addr
if (read_buf[0] != addr_block[0] || read_buf[1] != addr_block[1]) goto retry;
memcpy(pdata, &read_buf[2], len);
return TRUE;
retry:
I2C_GenerateSTOP(ENABLE);
I2C_AcknowledgeConfig(ENABLE);
}
return FALSE;
}
/**
* @brief read DF reg data
*
* @return uint8_t
*/
uint8_t KP691000_Write_DF_data(uint16_t df_adress, uint16_t data)
{
uint8_t buf[2];
buf[0] = (uint8_t)(data & 0xFF); // low byte
buf[1] = (uint8_t)((data >> 8) & 0xFF); // high byte
if (KP691000_DF_Write_Data(df_adress, 0x44, buf, 2)) {
return TRUE;
}
return FALSE;
}
/**
* @brief read 0x16 reg data
*
* @return uint8_t
*/
uint8_t KP691000_Get_Bat_Status()
{
uint8_t buf[2];
if(KP691000_Read_Data(KP691000_SLAVE_ADDR_7BIT, BATSTATUS, buf, 2))
{
uint16_t status = (uint16_t)(buf[1] << 8) | buf[0];
PRINT("BATSTATUS = 0x%04X\n", status);
PRINT(" FG Init : %s\n", (status & (1<<11)) ? "YES" : "NO");
PRINT(" Discharging : %s\n", (status & (1<<10)) ? "YES" : "NO");
PRINT(" Fully Charged : %s\n", (status & (1<<9)) ? "YES" : "NO");
PRINT(" Fully Discharged: %s\n", (status & (1<<8)) ? "YES" : "NO");
PRINT(" Low Temp Alert : %s\n", (status & (1<<2)) ? "YES" : "NO");
PRINT(" High Temp Alert : %s\n", (status & (1<<1)) ? "YES" : "NO");
PRINT(" SOC Alert : %s\n", (status & (1<<0)) ? "YES" : "NO");
PRINT("---------------------------------------\n");
return TRUE;
}
return FALSE;
}
/**
* @brief read 0x20 reg data
*
* @return uint8_t
*/
uint8_t Get_IntgData()
{
uint8_t buf[20];
if(KP691000_Read_Data(KP691000_SLAVE_ADDR_7BIT, 0x20, buf, 20))
{
uint16_t voltage = (buf[1] << 8) | buf[0]; // mV
int16_t current = (buf[3] << 8) | buf[2]; // mA
int16_t temp_ext = (buf[5] << 8) | buf[4]; // 0.1°C
int16_t temp_int = (buf[7] << 8) | buf[6]; // 0.1°C
uint16_t rsoc = (buf[9] << 8) | buf[8]; // 0.01%
uint16_t soh = (buf[11] << 8) | buf[10]; // %
uint16_t cycles = (buf[13] << 8) | buf[12]; // 次
uint16_t coulomb = (buf[15] << 8) | buf[14]; // mAh
uint16_t time_empty = (buf[17] << 8) | buf[16]; // min
uint16_t time_full = (buf[19] << 8) | buf[18]; // min
PRINT("voltage is %d mV\n current is %d mA\n ex_temp is %d\n in_temp is %d\n rsoc is %d\n soh is %d\n \
cycles is %d\n coulomb is %d mAh\n time_empty is %d\n time_full is %d\n",\
voltage, current, temp_ext, temp_int, rsoc, soh, cycles, coulomb,time_empty, time_full);
PRINT("---------------------------------------\n");
return TRUE;
}
return FALSE;
}
/**
* @brief read df value
*
* @param df_address
* @return uint8_t
*/
uint8_t KP691000_Read_DF_Value(uint16_t df_address)
{
uint8_t buf[2];
if(KP691000_DF_Read_Data(df_address, 0x44, buf, 2))
{
uint16_t value = (uint16_t)(buf[1] << 8) | buf[0];
PRINT("DF[0x%04X] = %u\n", df_address, value);
PRINT("----------------------------------\n");
return value;
}
else
{
PRINT("READ DF FAILED\n");
return FALSE;
}
}
////////////////////////main/////////////////////////
extern volatile uint32_t timeout_count_1ms;
#define MASTER_ADDR 0x42
/*********************************************************************
* @fn Main_Circulation
*
* @brief 主循环
*
* @return none
*/
__HIGH_CODE
__attribute__((noinline))
void Main_Circulation()
{
while(1)
{
TMOS_SystemProcess();
}
}
/*********************************************************************
* @fn main
*
* @brief 主函数
*
* @return none
*/
int main(void)
{
#if(defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE)
PWR_DCDCCfg(ENABLE);
#endif
HSECFG_Capacitance(HSECap_18p);
SetSysClock(SYSCLK_FREQ);
#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
#endif
#ifdef DEBUG
GPIOA_SetBits(GPIO_Pin_14);
GPIOPinRemap(ENABLE, RB_PIN_UART0);
GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_PU);
GPIOA_ModeCfg(GPIO_Pin_14, GPIO_ModeOut_PP_5mA);
UART0_DefInit();
#endif
PRINT("%s\n", VER_LIB);
GPIOB_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13, GPIO_ModeIN_PU);
I2C_Init(I2C_Mode_I2C, 100000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_7bit, MASTER_ADDR); //初始化了 I2C 接口,设置了通信速率为 400kHz
CH58x_BLEInit();
HAL_Init();
GAPRole_PeripheralInit();
HidDev_Init();
HidEmu_Init();
TMR0_TimerInit(FREQ_SYS / 1000); // 设置定时时间 1ms
TMR0_ITCfg(ENABLE, TMR0_3_IT_CYC_END); // 开启中断
PFIC_EnableIRQ(TMR0_IRQn);
Main_Circulation();
}
/*********************************************************************
* @fn TMR0_IRQHandler
*
* @brief TMR0中断函数
*
* @return none
*/
__INTERRUPT
__HIGH_CODE
void TMR0_IRQHandler(void) // TMR0 定时中断
{
if(TMR0_GetITFlag(TMR0_3_IT_CYC_END))
{
timeout_count_1ms++;
TMR0_ClearITFlag(TMR0_3_IT_CYC_END); // 清除中断标志
}
}


浙公网安备 33010602011771号