10a7ce71fSopenharmony_ci/* 20a7ce71fSopenharmony_ci * Copyright (C) 2022 HiHope Open Source Organization . 30a7ce71fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 40a7ce71fSopenharmony_ci * you may not use this file except in compliance with the License. 50a7ce71fSopenharmony_ci * You may obtain a copy of the License at 60a7ce71fSopenharmony_ci * 70a7ce71fSopenharmony_ci * http:// www.apache.org/licenses/LICENSE-2.0 80a7ce71fSopenharmony_ci * 90a7ce71fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 100a7ce71fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 110a7ce71fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 120a7ce71fSopenharmony_ci * See the License for the specific language governing permissions and 130a7ce71fSopenharmony_ci * 140a7ce71fSopenharmony_ci * limitations under the License. 150a7ce71fSopenharmony_ci */ 160a7ce71fSopenharmony_ci 170a7ce71fSopenharmony_ci 180a7ce71fSopenharmony_ci#include "aht20.h" 190a7ce71fSopenharmony_ci 200a7ce71fSopenharmony_ci#include <stdio.h> 210a7ce71fSopenharmony_ci#include <string.h> 220a7ce71fSopenharmony_ci#include <unistd.h> 230a7ce71fSopenharmony_ci 240a7ce71fSopenharmony_ci#include "wifiiot_i2c.h" 250a7ce71fSopenharmony_ci#include "wifiiot_errno.h" 260a7ce71fSopenharmony_ci 270a7ce71fSopenharmony_ci#define AHT20_I2C_IDX WIFI_IOT_I2C_IDX_0 280a7ce71fSopenharmony_ci 290a7ce71fSopenharmony_ci#define AHT20_STARTUP_TIME (20*1000) // 上电启动时间 300a7ce71fSopenharmony_ci#define AHT20_CALIBRATION_TIME (40*1000) // 初始化(校准)时间 310a7ce71fSopenharmony_ci#define AHT20_MEASURE_TIME (75*1000) // 测量时间 320a7ce71fSopenharmony_ci 330a7ce71fSopenharmony_ci#define AHT20_DEVICE_ADDR 0x38 340a7ce71fSopenharmony_ci#define AHT20_READ_ADDR ((0x38<<1)|0x1) 350a7ce71fSopenharmony_ci#define AHT20_WRITE_ADDR ((0x38<<1)|0x0) 360a7ce71fSopenharmony_ci 370a7ce71fSopenharmony_ci#define AHT20_CMD_CALIBRATION 0xBE // 初始化(校准)命令 380a7ce71fSopenharmony_ci#define AHT20_CMD_CALIBRATION_ARG0 0x08 390a7ce71fSopenharmony_ci#define AHT20_CMD_CALIBRATION_ARG1 0x00 400a7ce71fSopenharmony_ci 410a7ce71fSopenharmony_ci/** 420a7ce71fSopenharmony_ci * 传感器在采集时需要时间,主机发出测量指令(0xAC)后,延时75毫秒以上再读取转换后的数据并判断返回的状态位是否正常。 430a7ce71fSopenharmony_ci * 若状态比特位[Bit7]为0代表数据可正常读取,为1时传感器为忙状态,主机需要等待数据处理完成。 440a7ce71fSopenharmony_ci **/ 450a7ce71fSopenharmony_ci#define AHT20_CMD_TRIGGER 0xAC // 触发测量命令 460a7ce71fSopenharmony_ci#define AHT20_CMD_TRIGGER_ARG0 0x33 470a7ce71fSopenharmony_ci#define AHT20_CMD_TRIGGER_ARG1 0x00 480a7ce71fSopenharmony_ci 490a7ce71fSopenharmony_ci// 用于在无需关闭和再次打开电源的情况下,重新启动传感器系统,软复位所需时间不超过20 毫秒 500a7ce71fSopenharmony_ci#define AHT20_CMD_RESET 0xBA // 软复位命令 510a7ce71fSopenharmony_ci 520a7ce71fSopenharmony_ci#define AHT20_CMD_STATUS 0x71 // 获取状态命令 530a7ce71fSopenharmony_ci 540a7ce71fSopenharmony_ci/** 550a7ce71fSopenharmony_ci * STATUS 命令回复: 560a7ce71fSopenharmony_ci * 1. 初始化后触发测量之前,STATUS 只回复 1B 状态值; 570a7ce71fSopenharmony_ci * 2. 触发测量之后,STATUS 回复6B: 1B 状态值 + 2B 湿度 + 4b湿度 + 4b温度 + 2B 温度 580a7ce71fSopenharmony_ci * RH = Srh / 2^20 * 100% 590a7ce71fSopenharmony_ci * T = St / 2^20 * 200 - 50 600a7ce71fSopenharmony_ci **/ 610a7ce71fSopenharmony_ci#define AHT20_STATUS_BUSY_SHIFT 7 // bit[7] Busy indication 620a7ce71fSopenharmony_ci#define AHT20_STATUS_BUSY_MASK (0x1<<AHT20_STATUS_BUSY_SHIFT) 630a7ce71fSopenharmony_ci 640a7ce71fSopenharmony_ciuint8_t aht20_status_busy(uint8_t status) 650a7ce71fSopenharmony_ci{ 660a7ce71fSopenharmony_ci return ((status & AHT20_STATUS_BUSY_MASK) >> (AHT20_STATUS_BUSY_SHIFT)); 670a7ce71fSopenharmony_ci} 680a7ce71fSopenharmony_ci 690a7ce71fSopenharmony_ci#define AHT20_STATUS_MODE_SHIFT 5 // bit[6:5] Mode Status 700a7ce71fSopenharmony_ci#define AHT20_STATUS_MODE_MASK (0x3<<AHT20_STATUS_MODE_SHIFT) 710a7ce71fSopenharmony_ci 720a7ce71fSopenharmony_ciuint8_t aht20_status_mode(uint8_t status) 730a7ce71fSopenharmony_ci{ 740a7ce71fSopenharmony_ci return ((status & AHT20_STATUS_MODE_MASK) >> (AHT20_STATUS_MODE_SHIFT)) 750a7ce71fSopenharmony_ci} 760a7ce71fSopenharmony_ci // bit[4] Reserved 770a7ce71fSopenharmony_ci#define AHT20_STATUS_CALI_SHIFT 3 // bit[3] CAL Enable 780a7ce71fSopenharmony_ci#define AHT20_STATUS_CALI_MASK (0x1<<AHT20_STATUS_CALI_SHIFT) 790a7ce71fSopenharmony_ci 800a7ce71fSopenharmony_ciuint8_t aht20_status_cali(uint8_t status) 810a7ce71fSopenharmony_ci{ 820a7ce71fSopenharmony_ci return ((status & AHT20_STATUS_CALI_MASK) >> (AHT20_STATUS_CALI_SHIFT)) 830a7ce71fSopenharmony_ci} 840a7ce71fSopenharmony_ci // bit[2:0] Reserved 850a7ce71fSopenharmony_ci 860a7ce71fSopenharmony_ci#define AHT20_STATUS_RESPONSE_MAX 6 870a7ce71fSopenharmony_ci 880a7ce71fSopenharmony_ci#define AHT20_RESLUTION (1<<20) // 2^20 890a7ce71fSopenharmony_ci 900a7ce71fSopenharmony_ci#define AHT20_MAX_RETRY 10 910a7ce71fSopenharmony_ci#define TWO 2 920a7ce71fSopenharmony_ci#define THREE 3 930a7ce71fSopenharmony_ci#define FOUR 4 940a7ce71fSopenharmony_ci#define FIVE 5 950a7ce71fSopenharmony_ci#define EIGHT 8 960a7ce71fSopenharmony_ci#define FIFTY 50 970a7ce71fSopenharmony_ci#define ONE_HUNDRED 100 980a7ce71fSopenharmony_ci#define TWO_HUNDRED 200 990a7ce71fSopenharmony_ci 1000a7ce71fSopenharmony_cistatic uint32_t AHT20_Read(uint8_t* buffer, uint32_t buffLen) 1010a7ce71fSopenharmony_ci{ 1020a7ce71fSopenharmony_ci WifiIotI2cData data = { 0 }; 1030a7ce71fSopenharmony_ci data.receiveBuf = buffer; 1040a7ce71fSopenharmony_ci data.receiveLen = buffLen; 1050a7ce71fSopenharmony_ci uint32_t retval = I2cRead(AHT20_I2C_IDX, AHT20_READ_ADDR, &data); 1060a7ce71fSopenharmony_ci if (retval != WIFI_IOT_SUCCESS) { 1070a7ce71fSopenharmony_ci printf("I2cRead() failed, %0X!\n", retval); 1080a7ce71fSopenharmony_ci return retval; 1090a7ce71fSopenharmony_ci } 1100a7ce71fSopenharmony_ci return WIFI_IOT_SUCCESS; 1110a7ce71fSopenharmony_ci} 1120a7ce71fSopenharmony_ci 1130a7ce71fSopenharmony_cistatic uint32_t AHT20_Write(uint8_t* buffer, uint32_t buffLen) 1140a7ce71fSopenharmony_ci{ 1150a7ce71fSopenharmony_ci WifiIotI2cData data = { 0 }; 1160a7ce71fSopenharmony_ci data.sendBuf = buffer; 1170a7ce71fSopenharmony_ci data.sendLen = buffLen; 1180a7ce71fSopenharmony_ci uint32_t retval = I2cWrite(AHT20_I2C_IDX, AHT20_WRITE_ADDR, &data); 1190a7ce71fSopenharmony_ci if (retval != WIFI_IOT_SUCCESS) { 1200a7ce71fSopenharmony_ci printf("I2cWrite(%02X) failed, %0X!\n", buffer[0], retval); 1210a7ce71fSopenharmony_ci return retval; 1220a7ce71fSopenharmony_ci } 1230a7ce71fSopenharmony_ci return WIFI_IOT_SUCCESS; 1240a7ce71fSopenharmony_ci} 1250a7ce71fSopenharmony_ci 1260a7ce71fSopenharmony_ci// 发送获取状态命令 1270a7ce71fSopenharmony_cistatic uint32_t AHT20_StatusCommand(void) 1280a7ce71fSopenharmony_ci{ 1290a7ce71fSopenharmony_ci uint8_t statusCmd[] = { AHT20_CMD_STATUS }; 1300a7ce71fSopenharmony_ci return AHT20_Write(statusCmd, sizeof(statusCmd)); 1310a7ce71fSopenharmony_ci} 1320a7ce71fSopenharmony_ci 1330a7ce71fSopenharmony_ci// 发送软复位命令 1340a7ce71fSopenharmony_cistatic uint32_t AHT20_ResetCommand(void) 1350a7ce71fSopenharmony_ci{ 1360a7ce71fSopenharmony_ci uint8_t resetCmd[] = {AHT20_CMD_RESET}; 1370a7ce71fSopenharmony_ci return AHT20_Write(resetCmd, sizeof(resetCmd)); 1380a7ce71fSopenharmony_ci} 1390a7ce71fSopenharmony_ci 1400a7ce71fSopenharmony_ci// 发送初始化校准命令 1410a7ce71fSopenharmony_cistatic uint32_t AHT20_CalibrateCommand(void) 1420a7ce71fSopenharmony_ci{ 1430a7ce71fSopenharmony_ci uint8_t clibrateCmd[] = {AHT20_CMD_CALIBRATION, AHT20_CMD_CALIBRATION_ARG0, AHT20_CMD_CALIBRATION_ARG1}; 1440a7ce71fSopenharmony_ci return AHT20_Write(clibrateCmd, sizeof(clibrateCmd)); 1450a7ce71fSopenharmony_ci} 1460a7ce71fSopenharmony_ci 1470a7ce71fSopenharmony_ci// 读取温湿度值之前, 首先要看状态字的校准使能位Bit[3]是否为 1(通过发送0x71可以获取一个字节的状态字), 1480a7ce71fSopenharmony_ci// 如果不为1,要发送0xBE命令(初始化),此命令参数有两个字节, 第一个字节为0x08,第二个字节为0x00。 1490a7ce71fSopenharmony_ciuint32_t AHT20_Calibrate(void) 1500a7ce71fSopenharmony_ci{ 1510a7ce71fSopenharmony_ci uint32_t retval = 0; 1520a7ce71fSopenharmony_ci uint8_t buffer[AHT20_STATUS_RESPONSE_MAX] = { AHT20_CMD_STATUS }; 1530a7ce71fSopenharmony_ci memset_s(&buffer, sizeof(buffer), 0x0, sizeof(buffer)); 1540a7ce71fSopenharmony_ci 1550a7ce71fSopenharmony_ci retval = AHT20_StatusCommand(); 1560a7ce71fSopenharmony_ci if (retval != WIFI_IOT_SUCCESS) { 1570a7ce71fSopenharmony_ci return retval; 1580a7ce71fSopenharmony_ci } 1590a7ce71fSopenharmony_ci 1600a7ce71fSopenharmony_ci retval = AHT20_Read(buffer, sizeof(buffer)); 1610a7ce71fSopenharmony_ci if (retval != WIFI_IOT_SUCCESS) { 1620a7ce71fSopenharmony_ci return retval; 1630a7ce71fSopenharmony_ci } 1640a7ce71fSopenharmony_ci 1650a7ce71fSopenharmony_ci if (AHT20_STATUS_BUSY(buffer[0]) || !AHT20_STATUS_CALI(buffer[0])) { 1660a7ce71fSopenharmony_ci retval = AHT20_ResetCommand(); 1670a7ce71fSopenharmony_ci if (retval != WIFI_IOT_SUCCESS) { 1680a7ce71fSopenharmony_ci return retval; 1690a7ce71fSopenharmony_ci } 1700a7ce71fSopenharmony_ci usleep(AHT20_STARTUP_TIME); 1710a7ce71fSopenharmony_ci retval = AHT20_CalibrateCommand(); 1720a7ce71fSopenharmony_ci usleep(AHT20_CALIBRATION_TIME); 1730a7ce71fSopenharmony_ci return retval; 1740a7ce71fSopenharmony_ci } 1750a7ce71fSopenharmony_ci 1760a7ce71fSopenharmony_ci return WIFI_IOT_SUCCESS; 1770a7ce71fSopenharmony_ci} 1780a7ce71fSopenharmony_ci 1790a7ce71fSopenharmony_ci// 发送 触发测量 命令,开始测量 1800a7ce71fSopenharmony_ciuint32_t AHT20_StartMeasure(void) 1810a7ce71fSopenharmony_ci{ 1820a7ce71fSopenharmony_ci uint8_t triggerCmd[] = {AHT20_CMD_TRIGGER, AHT20_CMD_TRIGGER_ARG0, AHT20_CMD_TRIGGER_ARG1}; 1830a7ce71fSopenharmony_ci return AHT20_Write(triggerCmd, sizeof(triggerCmd)); 1840a7ce71fSopenharmony_ci} 1850a7ce71fSopenharmony_ci 1860a7ce71fSopenharmony_ci// 接收测量结果,拼接转换为标准值 1870a7ce71fSopenharmony_ciuint32_t AHT20_GetMeasureResult(float* temp, float* humi) 1880a7ce71fSopenharmony_ci{ 1890a7ce71fSopenharmony_ci uint32_t retval = 0, i = 0; 1900a7ce71fSopenharmony_ci if (temp == NULL || humi == NULL) { 1910a7ce71fSopenharmony_ci return WIFI_IOT_FAILURE; 1920a7ce71fSopenharmony_ci } 1930a7ce71fSopenharmony_ci 1940a7ce71fSopenharmony_ci uint8_t buffer[AHT20_STATUS_RESPONSE_MAX] = { 0 }; 1950a7ce71fSopenharmony_ci memset_s(&buffer, sizeof(buffer), 0x0, sizeof(buffer)); 1960a7ce71fSopenharmony_ci retval = AHT20_Read(buffer, sizeof(buffer)); // recv status command result 1970a7ce71fSopenharmony_ci if (retval != WIFI_IOT_SUCCESS) { 1980a7ce71fSopenharmony_ci return retval; 1990a7ce71fSopenharmony_ci } 2000a7ce71fSopenharmony_ci 2010a7ce71fSopenharmony_ci for (i = 0; AHT20_STATUS_BUSY(buffer[0]) && i < AHT20_MAX_RETRY; i++) { 2020a7ce71fSopenharmony_ci usleep(AHT20_MEASURE_TIME); 2030a7ce71fSopenharmony_ci retval = AHT20_Read(buffer, sizeof(buffer)); // recv status command result 2040a7ce71fSopenharmony_ci if (retval != WIFI_IOT_SUCCESS) { 2050a7ce71fSopenharmony_ci return retval; 2060a7ce71fSopenharmony_ci } 2070a7ce71fSopenharmony_ci } 2080a7ce71fSopenharmony_ci if (i >= AHT20_MAX_RETRY) { 2090a7ce71fSopenharmony_ci printf("AHT20 device always busy!\r\n"); 2100a7ce71fSopenharmony_ci return WIFI_IOT_FAILURE; 2110a7ce71fSopenharmony_ci } 2120a7ce71fSopenharmony_ci 2130a7ce71fSopenharmony_ci uint32_t humiRaw = buffer[1]; 2140a7ce71fSopenharmony_ci humiRaw = (humiRaw << EIGHT) | buffer[TWO]; 2150a7ce71fSopenharmony_ci humiRaw = (humiRaw << FOUR) | ((buffer[THREE] & 0xF0) >> FOUR); 2160a7ce71fSopenharmony_ci *humi = humiRaw / (float)AHT20_RESLUTION * ONE_HUNDRED; 2170a7ce71fSopenharmony_ci 2180a7ce71fSopenharmony_ci uint32_t tempRaw = buffer[3] & 0x0F; 2190a7ce71fSopenharmony_ci tempRaw = (tempRaw << EIGHT) | buffer[FOUR]; 2200a7ce71fSopenharmony_ci tempRaw = (tempRaw << EIGHT) | buffer[FIVE]; 2210a7ce71fSopenharmony_ci *temp = tempRaw / (float)AHT20_RESLUTION * TWO_HUNDRED - FIFTY; 2220a7ce71fSopenharmony_ci return WIFI_IOT_SUCCESS; 2230a7ce71fSopenharmony_ci} 224