基于沁恒CH585学习使用I2C驱动温度传感器,获取环境温度。
本文基于原厂EVK修改,路径:EVT\EXAM\I2C 例程。

1、I2C初始化

打开例程后可以看到“i2c_app_init”的初始化API

void i2c_app_init(uint8_t address)
{
    i2c_state = I2C_READY;
    i2c_send_stop = true;
    i2c_in_repstart = false;

    GPIOB_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13, GPIO_ModeIN_PU);

    I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable,
            I2C_AckAddr_7bit, address);

    I2C_ITConfig(I2C_IT_BUF, ENABLE);
    I2C_ITConfig(I2C_IT_EVT, ENABLE);
    I2C_ITConfig(I2C_IT_ERR, ENABLE);
    
    PFIC_EnableIRQ(I2C_IRQn);
}

初始化API
参数介绍如下:
1、I2C的模式,可配置为多种模式
2、时钟速率:100KHz和400KHz
3、快速模式时的时钟高电平时间的占空比: 1:36% 0:33.3%
4、使能应答与否
5、地址的格式:7bit 或 10nit
6、从机地址:需要填写 8bit地址>>1 位,因为在发送时会左移一位。
如想要发送0X70,需要填写0X70>>1。

I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9,I2C_Ack_Enable,I2C_AckAddr_7bit, address);

2、发送与读取数据

原厂提供的API,在“CH58x_i2c.c”中,只是对I2C相关寄存器做了简单的封装,需要参考I2C的逻辑去组合出完成的收发数据的API。

好处:灵活度相当高,遇到一些奇奇怪怪的非标准I2C协议,就可以自行改动,非常好用
坏处:标准I2C的用户需要自己对着协议文档 和 逻辑分析仪对照调整代码。

好在原厂提供了“app_i2c.c”了,有提供标准I2C的API。

收发数据API
参数介绍如下:
1、从机地址:同上
2、发送\接收数据的地址
3、数据长度
4、是否需要停止位
5、超时时间

i2c_write_to(SLAVE_ADDR >> 1, data_buf, len, true, true);
i2c_read_from(SLAVE_ADDR >> 1, data_buf, len, true, 1000);   

3、驱动传感器

3.1、验证初始化传感器

#define SLAVE_ADDR      0x70

void i2c_write(uint8_t *data_buf,uint8_t len){    
  i2c_write_to(SLAVE_ADDR >> 1, data_buf, len, true, true);
}

void i2c_read(uint8_t *data_buf,uint8_t len){
    i2c_read_from(SLAVE_ADDR >> 1, data_buf, len, true, 1000);   
}

int main()
{
    uint8_t i = 0;
    HSECFG_Capacitance(HSECap_18p);
    SetSysClock(CLK_SOURCE_HSE_PLL_62_4MHz);
    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();

    GPIOB_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13, GPIO_ModeIN_PU);

    PRINT("IIC Host mode\r\n");    

    i2c_app_init(SLAVE_ADDR >> 1);

    uint8_t init_data[]={0xAC,0x33,0x00};
    
    i2c_write(&init_data[0],3);  
}


使用逻辑分析仪抓取数据,可见发送的数据正常 和 从机ACK正常在这里插入图片描述

3.2 读取数据

按照传感器规格书,截取-拼接-整合数据
下图是温度传感器的规格书,温度数据在Read的数据的 第3位的高八位 第4位 第5位 组成的。
所以拼接的数据如:

((int32_t)(read_back_data[3]&0x0F)<<16) | ((int32_t)read_back_data[4]<<8) | ((int32_t)read_back_data[5]);

在这里插入图片描述

完整的初始化、获取温度、计算温度的代码如下:


int main()
{
    uint8_t i = 0;
    HSECFG_Capacitance(HSECap_18p);
    SetSysClock(CLK_SOURCE_HSE_PLL_62_4MHz);
    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();

    GPIOB_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13, GPIO_ModeIN_PU);

    PRINT("IIC Host mode\r\n");    
	//初始化数据,写
    i2c_app_init(SLAVE_ADDR >> 1);

    uint8_t init_data[]={0xAC,0x33,0x00};
    
    i2c_write(&init_data[0],3);  

    DelayMs(80);
    
	//读取温度数据,读
    uint8_t read_back_data[7]={0x0};
    
    i2c_read(read_back_data,sizeof(read_back_data));   
    PRINT("\rRAW DATA: ");
    
    for(int i=0;i<7;i++){

        PRINT(" 0x%02x",read_back_data[i]);
    }
    PRINT("\r");
    
    float temp=0;
    data32 =  ((int32_t)(read_back_data[3]&0x0F) << 16) | ((int32_t)read_back_data[4] << 8) | ((int32_t)read_back_data[5]);

    temp=(data32*200)/1048576-50;
    PRINT("Temp %X  %f ",data32,temp);

}


3.3 数据分析

运行之后的读取的原始数据 与 计算的数据打印如下:

IIC Host mode

RAW DATA:  0x1c 0x8d 0x1a 0x06 0x2d 0x6e 0xa7
Temp 62D6E  27.000000 

温度换算:

404846(62D6E)*200=80969200/1048576=77-50=27

核算后,温度换算的公式正常计算值正确。

按照温度传感器规格书,这个传感器的温度分辨率是0.01℃,但是目前只能采集到整数的温度。
在这里插入图片描述

第一个字节是传感器的状态字(见上文LOG),打印的是 0x1C,即:0001 1100
在这里插入图片描述
对照后比特位后发现,bit[2] 为1是异常“校准后的电容数据超出CMP中断阈值范”,并且查阅规格书后,发现不能调整。

以上就是CH585 I2C驱动AHT30的完整流程,整理分享供大家参考。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐