硬件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); // 清除中断标志
    }
}


posted @ 2026-05-11 15:07  J_02346  阅读(31)  评论(0)    收藏  举报