基于CH592x的硬件I2C驱动(AHT20)调试记录
前言:AHT20是一个I2C器件,恰好CH592芯片资源有硬件I2C我们可以尝试使用592的硬件I2C去驱动AHT20。
资料:I2C接口使用指南(可见EVT中I2C例程文件下),AHT20数据手册(可以在立创商城直接下载)
数据手册中对这个器件的驱动流程也有说明,
分别对几个步骤进行解读:
1、根据手册提示开机后,要等待40ms才能够与AHT20通信。0x71地址实际上AHT20作为IIC从机的地址。按照AHT20手册,在启动传输后,随后传输的 I2C首字节包括 7位的 I2C设备地址0x38。因为IIC通信一般使用7位地址码,但是读写数据都是一个字节一个字节的读写。0x38的七位二进制为0111000。规定从机地址要左一位。多出来的第八位就是读写位。IIC协议规定,如果主机发起通信的目的是为了写从机,那么读写位是0,此时AHT20的地址是01110000,即0x70.如果主机发起通信的目的是为了读从机传入的数据,那么读写位就是1。此时AHT20的地址是0x71。
2、直接发送按照命令。按照(0xac,0x33,0x00)依次发送;
3、等待75ms后,读取6个字节数据,里面包含了状态信息,湿度信息,和温度信息。其中第0个字节是状态位,需获取bit[7]判断设备是否空闲。而后,湿度数据由20个bit位组成:第1个字节是湿度的高8位,第2个字节是湿度的次高8位.第3个字节的高4个bit位是湿度的低4位。温度数据也由20个bit位组成。第3个字节的低4个bit位是温度的高4位,第4个字节是温度的次高8位,第5个字节是温度的低8位。
4、根据手册的计算公式将获取的温度、湿度值计算出来。
接下来就可可以看代码实现部分:
AHT20.h
#ifndef DRIVER_CODE_AHT20_H_ #define DRIVER_CODE_AHT20_H_ #include "CH59x_common.h" #include "app_i2c.h" extern uint8_t send_data[4]; #define AHT20_Slave_Adress 0x38 #define AHT20_Init_REG_Adress 0x71 extern void AHT20_READ_Status(uint8_t slave_adress , uint8_t reg_adress , uint32_t *cb_data );
AHT20.c
#include "aht20.h" uint8_t send_data[4]={0xac , 0x33, 0x00}; uint8_t receive_data[7]; uint8_t Inspection_data; void AHT20_READ_Status(uint8_t slave_adress , uint8_t reg_adress ,uint32_t *cb_data) { uint8_t i = 0; uint32_t humi_temp_data =0; I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_7bit, 0x42); DelayMs(40); while(I2C_GetFlagStatus(I2C_FLAG_BUSY) != RESET); I2C_GenerateSTART(ENABLE); while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(slave_adress<<1, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); while(i < 3) { if(I2C_GetFlagStatus(I2C_FLAG_TXE) != RESET) { I2C_SendData(send_data[i]); i++; } } while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTART(ENABLE); //重起始信号 while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)); //判断BUSY, MSL and SB flags I2C_Send7bitAddress(reg_adress, I2C_Direction_Receiver); //发送地址+最低位1表示为“读” while(!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //判断BUSY, MSL and ADDR flags //I2C_GenerateSTOP(DISABLE); for(uint8_t j=0; j<7; j++) { if(j == 7-1) I2C_AcknowledgeConfig(DISABLE); //清除ACK位 主设备为了能在收到最后一个字节后产生一个NACK脉冲, //必须在读取倒数第二个字节之后(倒数第二个RxNE 事件之后)清除ACK位(ACK=0) while(!I2C_GetFlagStatus(I2C_FLAG_RXNE)); //获取RxEN的状态,等待收到数据 receive_data[j] = I2C_ReceiveData(); } I2C_GenerateSTOP(ENABLE); //停止信号 humi_temp_data = 0; humi_temp_data =(humi_temp_data | receive_data[1])<<8; humi_temp_data =(humi_temp_data | receive_data[2])<<8; humi_temp_data =(humi_temp_data | receive_data[3]); humi_temp_data = humi_temp_data >>4; cb_data[0] = humi_temp_data; humi_temp_data = 0; humi_temp_data =(humi_temp_data | receive_data[3])<<8; humi_temp_data =(humi_temp_data | receive_data[4])<<8; humi_temp_data =(humi_temp_data | receive_data[5]); humi_temp_data = humi_temp_data&0xfffff; cb_data[1] = humi_temp_data; PRINT("湿度 %d\r\n",cb_data[0]*100/1048576); PRINT("温度 %d\r\n",(cb_data[1]*200/1048576)-50); };
仅是个人学习分享;如有任何错漏敬请留言指正。