写在前面的话:这个demo需要结合前面的oled部分。另外在调试aht20的驱动的时候遇到有问题,卡了差不多两三天吧。今天晚上才解决掉。明天上午单独发个贴说明怎定位问题并解决问题的。
AHT20和OLED一样都是I2C驱动的。有了前面oled的基础了,移植这个的驱动就简单很多了。
查看原理图可以看到,AHT20和OLED共用相同的I2C,都是GPIO13_I2C0_SDA、GPIO4_I2C0_SCL.只是地址有区分而已。
[attach]992095[/attach]
查看AHT20 的数据手册,得到其地址为0x38,读命令为0x71,写命令为0x70;
[attach]992096[/attach]
剩下的就是根据手册中的读取流程读取数据就行了。
读取流程\n
如下是demo程序
- static hi_u32 aht20_i2c_write(hi_u8 *sendbuf, hi_u32 send_len)
- {
- hi_u32 status;
- hi_i2c_data aht20_i2c_data = { 0 };
- aht20_i2c_data.send_buf = sendbuf;
- aht20_i2c_data.send_len = send_len;
- status = hi_i2c_write(HI_I2C_IDX_0, AHT20_SLAVE_WRITE_ADDR, &aht20_i2c_data);
- if (status != HI_ERR_SUCCESS) {
- printf("===== Error: AHT20 I2C write status = 0x%x! =====rn", status);
- return status;
- }
- return HI_ERR_SUCCESS;
- }
- static hi_u32 aht20_i2c_read(hi_u8 *recvbuf, hi_u32 read_len)
- {
- hi_u32 status;
- hi_i2c_data aht20_i2c_data = {0};
- aht20_i2c_data.receive_buf = recvbuf;
- aht20_i2c_data.receive_len = read_len;
- status = hi_i2c_read(HI_I2C_IDX_0, AHT20_SLAVE_READ_ADDR, &aht20_i2c_data);
- if (status != HI_ERR_SUCCESS) {
- printf("===== Error: AHT20 I2C read status = 0x%x! =====rn", status);
- return status;
- }
- return HI_ERR_SUCCESS;
- }
- /**
- * [url=home.php?mod=space&uid=2666770]@Brief[/url] 读AHT20 设备状态字
- * [url=home.php?mod=space&uid=3142012]@param[/url] void
- * @retval hi_u8 设备状态字
- */
- static hi_u8 AHT20_ReadStatusCmd(void)
- {
- hi_u8 tmp = 0;
- aht20_i2c_read(&tmp, 1);
- return tmp;
- }
-
- /**
- * @brief 读AHT20 设备状态字 中的Bit3: 校准使能位
- * @param void
- * @retval hi_u8 校准使能位:1 - 已校准; 0 - 未校准
- */
- static hi_u8 AHT20_ReadCalEnableCmd(void)
- {
- hi_u8 tmp;
- tmp = AHT20_ReadStatusCmd();
- return (tmp>>3)&0x01;
- }
-
- /**
- * @brief 读AHT20 设备状态字 中的Bit7: 忙标志
- * @param void
- * @retval hi_u8 忙标志:1 - 设备忙; 0 - 设备空闲
- */
- static hi_u8 AHT20_ReadBusyCmd(void)
- {
- hi_u8 tmp;
- tmp = AHT20_ReadStatusCmd();
- return (tmp>>7)&0x01;
- }
- //发送获取状态字命令
- static hi_u32 AHT20_StatusCmd(void)
- {
- hi_u8 cmd[1] = {AHT20_STATUS_REG};
- return aht20_i2c_write(cmd, 1);
- }
- /**
- * @brief AHT20 芯片初始化命令
- * @param void
- * @retval void
- */
- static hi_u32 AHT20_IcInitCmd(void)
- {
- hi_u8 cmd[3] = {AHT20_INIT_REG, AHT20_INIT_REG_ARG0, AHT20_INIT_REG_ARG1};
- return aht20_i2c_write(cmd, 3);
- }
-
- /**
- * @brief AHT20 触发测量命令
- * @param void
- * @retval void
- */
- static hi_u32 AHT20_TrigMeasureCmd(void)
- {
- hi_u8 cmd[3] = {AHT20_TrigMeasure_REG, AHT20_TrigMeasure_REG_ARG0, AHT20_TrigMeasure_REG_ARG1};
- return aht20_i2c_write(cmd, 3);
- }
-
- /**
- * @brief AHT20 软复位命令
- * @param void
- * @retval void
- */
- static hi_u32 AHT20_SoftResetCmd(void)
- {
- hi_u8 cmd[1] = {AHT20_SoftReset};
- return aht20_i2c_write(cmd, 3);
- }
-
- /**
- * @brief AHT20 设备初始化
- * @param void
- * @retval uint8_t:0 - 初始化AHT20设备成功; 1 - 初始化AHT20失败,可能设备不存在或器件已损坏
- */
- static hi_u8 AHT20_Init(void)
- {
- hi_u8 rcnt = 2+1;//软复位命令 重试次数,2次
- hi_u8 icnt = 2+1;//初始化命令 重试次数,2次
- hi_u32 retVal = 0; //记录返回状态
- usleep(40000);
- while(--rcnt)
- {
- icnt = 2+1;
- retVal = AHT20_StatusCmd();
- if(retVal != HI_ERR_SUCCESS)
- return retVal;
- // 读取温湿度之前,首先检查[校准使能位]是否为1
- while((!AHT20_ReadCalEnableCmd()) && (--icnt))// 2次重试机会
- {
- usleep(20000);
- // 如果不为1,要发送初始化命令
- AHT20_IcInitCmd();
- usleep(40000);
- }
-
- if(icnt)//[校准使能位]为1,校准正常
- {
- break;//退出rcnt循环
- }
- else//[校准使能位]为0,校准错误
- {
- AHT20_SoftResetCmd();//软复位AHT20器件,重试
- usleep(40000);//这个时间不确定,手册没讲
- }
- }
-
- if(rcnt)
- {
- usleep(10000);//这个时间不确定,手册没讲
- return 0;// AHT20设备初始化正常
- }
- else
- {
- return 1;// AHT20设备初始化失败
- }
- }
-
- /**
- * @brief AHT20 设备读取 相对湿度和温度(原始数据20Bit)
- * @param hi_u32 *HT:存储20Bit原始数据的uint32数组
- * @retval uint8_t:0-读取数据正常; 1-读取设备失败,设备一直处于忙状态,不能获取数据
- */
- static hi_u8 AHT20_ReadHT(hi_u32 *HT)
- {
- hi_u8 cnt=3+1;//忙标志 重试次数,3次
- hi_u8 tmp[6];
- hi_u32 RetuData = 0;
-
- // 发送触发测量命令
- AHT20_TrigMeasureCmd();
-
- do{
- usleep(76000);//等待75ms待测量完成,忙标志Bit7为0
- }while(AHT20_ReadBusyCmd() && (--cnt));//重试3次
-
- if(cnt)//设备闲,可以读温湿度数据
- {
- usleep(5000);
- // 读温湿度数据
- aht20_i2c_read(tmp, 6);
- // 计算相对湿度RH。原始值,未计算为标准单位%。
- RetuData = 0;
- RetuData = (RetuData|tmp[1]) << 8;
- RetuData = (RetuData|tmp[2]) << 8;
- RetuData = (RetuData|tmp[3]);
- RetuData = RetuData >> 4;
- HT[0] = RetuData;
-
- // 计算温度T。原始值,未计算为标准单位°C。
- RetuData = 0;
- RetuData = (RetuData|tmp[3]) << 8;
- RetuData = (RetuData|tmp[4]) << 8;
- RetuData = (RetuData|tmp[5]);
- RetuData = RetuData&0x0fffff;
- HT[1] = RetuData;
-
- return 0;
- }
- else//设备忙,返回读取失败
- {
- return 1;
- }
- }
-
- /**
- * @brief AHT20 温湿度信号转换(由20Bit原始数据,转换为标准单位RH=%,T=°C)
- * @param struct m_AHT20* aht:存储AHT20传感器信息的结构体
- * @retval uint8_t:0-计算数据正常; 1-计算数据失败,计算值超出元件手册规格范围
- */
- static hi_u8 StandardUnitCon(struct m_AHT20* aht)
- {
- aht->RH = (double)aht->HT[0] *100 / 1048576;//2^20=1048576 //原式:(double)aht->HT[0] / 1048576 *100,为了浮点精度改为现在的
- aht->Temp = (double)aht->HT[1] *200 / 1048576 -50;
-
- //限幅,RH=0~100%; Temp=-40~85°C
- if((aht->RH >=0)&&(aht->RH <=100) && (aht->Temp >=-40)&&(aht->Temp <=85))
- {
- aht->flag = 0;
- return 0;//测量数据正常
- }
- else
- {
- aht->flag = 1;
- return 1;//测量数据超出范围,错误
- }
- }
- #define AHT20_TASK_STACK_SIZE 1024
- #define AHT20_TASK_PRIO 26
- struct m_AHT20 AHT20_Reseult = {0};
- static void *AHT20_Task(const char *arg)
- {
- hi_u8 result = 0;
-
- hi_u32 ht_raw[2] = {0};
- (void)arg;
- usleep(100000);
- result = AHT20_Init();
- if(result == 0)
- printf("AHT20 Init Successrn");
- else
- printf("AHT20 Init Failedrn");
-
- while(1)
- {
- result = AHT20_ReadHT(ht_raw);
- if(result)
- printf("read HT data Failedrn");
- else
- {
- AHT20_Reseult.HT[0] = ht_raw[0];
- AHT20_Reseult.HT[1] = ht_raw[1];
- result = StandardUnitCon(&AHT20_Reseult);
- if(result)
- printf("cal HT data Failedrn");
- else
- {
- printf("HT:%.2f temp:%.2frn", AHT20_Reseult.RH, AHT20_Reseult.Temp);
- OLED_ShowFloat(56,32,AHT20_Reseult.RH,2,16);
- OLED_ShowFloat(56,48,AHT20_Reseult.Temp,2,16);
- OLED_Refresh();
- }
-
- }
- usleep(1000000);
- }
- return NULL;
- }
- static void AHT20ExampleEntry(void)
- {
- osThreadAttr_t attr;
- attr.name = "AHT20Task";
- attr.attr_bits = 0U;
- attr.cb_mem = NULL;
- attr.cb_size = 0U;
- attr.stack_mem = NULL;
- attr.stack_size = AHT20_TASK_STACK_SIZE;
- attr.priority = AHT20_TASK_PRIO;
- if (osThreadNew((osThreadFunc_t)AHT20_Task, NULL, &attr) == NULL) {
- printf("[AHT20 Example] Falied to create AHT20Task!n");
- }
- }
- SYS_RUN(AHT20ExampleEntry);
复制代码
头文件内容
- #define ATH20_SLAVE_ADDRESS 0x38 /* I2C从机地址 */
- #define AHT20_SLAVE_READ_ADDR (ATH20_SLAVE_ADDRESS<<1 | 0x01) //读命令
- #define AHT20_SLAVE_WRITE_ADDR (ATH20_SLAVE_ADDRESS<<1 | 0x00) //写命令
- //****************************************
- // 定义 AHT20 内部地址
- //****************************************
- #define AHT20_STATUS_REG 0x71 //状态字 寄存器地址
- #define AHT20_INIT_REG 0xBE //初始化 寄存器地址
- #define AHT20_INIT_REG_ARG0 0x08 //初始化 寄存器参数1
- #define AHT20_INIT_REG_ARG1 0x00 //初始化 寄存器参数2
- #define AHT20_SoftReset 0xBA //软复位 单指令
- #define AHT20_TrigMeasure_REG 0xAC //触发测量 寄存器地址
- #define AHT20_TrigMeasure_REG_ARG0 0x33 //触发测量 寄存器参数1
- #define AHT20_TrigMeasure_REG_ARG1 0x00 //触发测量 寄存器参数2
- // 存储AHT20传感器信息的结构体
- struct m_AHT20
- {
- hi_u8 alive; // 0-器件不存在; 1-器件存在
- hi_u8 flag; // 读取/计算错误标志位。0-读取/计算数据正常; 1-读取/计算设备失败
- hi_u32 HT[2]; // 湿度、温度 原始传感器的值,20Bit
-
- float RH; // 湿度,转换单位后的实际值,标准单位%
- float Temp; // 温度,转换单位后的实际值,标准单位°C
- };
复制代码编译成功后,串口间隔1s打印温湿度信息以及oled上显示当前温湿度信息。