• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 HiHope Open Source Organization .
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http:// www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  *
14  * limitations under the License.
15  */
16 
17 #include "aht20.h"
18 
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 #include "wifiiot_i2c.h"
24 #include "wifiiot_errno.h"
25 
26 #define AHT20_I2C_IDX WIFI_IOT_I2C_IDX_0
27 
28 #define AHT20_STARTUP_TIME     (20*1000) // 上电启动时间
29 #define AHT20_CALIBRATION_TIME (40*1000) // 初始化(校准)时间
30 #define AHT20_MEASURE_TIME     (75*1000) // 测量时间
31 
32 #define AHT20_DEVICE_ADDR   0x38
33 #define AHT20_READ_ADDR     ((0x38<<1)|0x1)
34 #define AHT20_WRITE_ADDR    ((0x38<<1)|0x0)
35 
36 #define AHT20_CMD_CALIBRATION       0xBE // 初始化(校准)命令
37 #define AHT20_CMD_CALIBRATION_ARG0  0x08
38 #define AHT20_CMD_CALIBRATION_ARG1  0x00
39 
40 #define NUM 8
41 #define NUM_TWO 2
42 #define NUM_THREE 3
43 #define NUM_FOUR 4
44 #define NUM_FIVE 5
45 #define NUM_FIFTY 50
46 #define ONE_HUNDRED 100
47 #define TWO_HUNDRED 200
48 
49 /**
50  * 传感器在采集时需要时间,主机发出测量指令(0xAC)后,延时75毫秒以上再读取转换后的数据并判断返回的状态位是否正常。
51  * 若状态比特位[Bit7]为0代表数据可正常读取,为1时传感器为忙状态,主机需要等待数据处理完成。
52  **/
53 #define AHT20_CMD_TRIGGER       0xAC // 触发测量命令
54 #define AHT20_CMD_TRIGGER_ARG0  0x33
55 #define AHT20_CMD_TRIGGER_ARG1  0x00
56 
57 // 用于在无需关闭和再次打开电源的情况下,重新启动传感器系统,软复位所需时间不超过20 毫秒
58 #define AHT20_CMD_RESET      0xBA // 软复位命令
59 
60 #define AHT20_CMD_STATUS     0x71 // 获取状态命令
61 
62 /**
63  * STATUS 命令回复:
64  * 1. 初始化后触发测量之前,STATUS 只回复 1B 状态值;
65  * 2. 触发测量之后,STATUS 回复6B: 1B 状态值 + 2B 湿度 + 4b湿度 + 4b温度 + 2B 温度
66  *      RH = Srh / 2^20 * 100%
67  *      T  = St  / 2^20 * 200 - 50
68  **/
69 #define AHT20_STATUS_BUSY_SHIFT 7       // bit[7] Busy indication
70 #define AHT20_STATUS_BUSY_MASK  (0x1<<AHT20_STATUS_BUSY_SHIFT)
71 
aht20_status_busy(uint8_t status)72 uint8_t  aht20_status_busy(uint8_t status)
73 {
74     return ((status & AHT20_STATUS_BUSY_MASK) >> (AHT20_STATUS_BUSY_SHIFT));
75 }
76 
77 #define AHT20_STATUS_MODE_SHIFT 5       // bit[6:5] Mode Status
78 #define AHT20_STATUS_MODE_MASK  (0x3<<AHT20_STATUS_MODE_SHIFT)
79 
aht20_status_mode(uint8_t status)80 uint8_t aht20_status_mode(uint8_t status)
81 {
82     return ((status & AHT20_STATUS_MODE_MASK) >> (AHT20_STATUS_MODE_SHIFT))
83 }
84 
85 #define AHT20_STATUS_CALI_SHIFT 3       // bit[3] CAL Enable
86 #define AHT20_STATUS_CALI_MASK  (0x1<<AHT20_STATUS_CALI_SHIFT)
87 
88 uint8_t aht20_status_cali(uint8_t status)
89 {
90     return ((status & AHT20_STATUS_CALI_MASK) >> (AHT20_STATUS_CALI_SHIFT))
91 }
92 
93 
94 #define AHT20_STATUS_RESPONSE_MAX 6
95 
96 #define AHT20_RESOLUTION            (1<<20)  // 2^20
97 
98 #define AHT20_MAX_RETRY 10
99 
100 static uint32_t AHT20_Read(uint8_t* buffer, uint32_t buffLen)
101 {
102     WifiIotI2cData data = { 0 };
103     data.receiveBuf = buffer;
104     data.receiveLen = buffLen;
105     uint32_t retval = I2cRead(AHT20_I2C_IDX, AHT20_READ_ADDR, &data);
106     if (retval != WIFI_IOT_SUCCESS) {
107         printf("I2cRead() failed, %0X!\n", retval);
108         return retval;
109     }
110     return WIFI_IOT_SUCCESS;
111 }
112 
113 static uint32_t AHT20_Write(uint8_t* buffer, uint32_t buffLen)
114 {
115     WifiIotI2cData data = { 0 };
116     data.sendBuf = buffer;
117     data.sendLen = buffLen;
118     uint32_t retval = I2cWrite(AHT20_I2C_IDX, AHT20_WRITE_ADDR, &data);
119     if (retval != WIFI_IOT_SUCCESS) {
120         printf("I2cWrite(%02X) failed, %0X!\n", buffer[0], retval);
121         return retval;
122     }
123     return WIFI_IOT_SUCCESS;
124 }
125 
126 // 发送获取状态命令
127 static uint32_t AHT20_StatusCommand(void)
128 {
129     uint8_t statusCmd[] = { AHT20_CMD_STATUS };
130     return AHT20_Write(statusCmd, sizeof(statusCmd));
131 }
132 
133 // 发送软复位命令
134 static uint32_t AHT20_ResetCommand(void)
135 {
136     uint8_t resetCmd[] = {AHT20_CMD_RESET};
137     return AHT20_Write(resetCmd, sizeof(resetCmd));
138 }
139 
140 // 发送初始化校准命令
141 static uint32_t AHT20_CalibrateCommand(void)
142 {
143     uint8_t clibrateCmd[] = {AHT20_CMD_CALIBRATION, AHT20_CMD_CALIBRATION_ARG0, AHT20_CMD_CALIBRATION_ARG1};
144     return AHT20_Write(clibrateCmd, sizeof(clibrateCmd));
145 }
146 
147 // 读取温湿度值之前, 首先要看状态字的校准使能位Bit[3]是否为 1(通过发送0x71可以获取一个字节的状态字),
148 // 如果不为1,要发送0xBE命令(初始化),此命令参数有两个字节, 第一个字节为0x08,第二个字节为0x00。
149 uint32_t AHT20_Calibrate(void)
150 {
151     uint32_t retval = 0;
152     uint8_t buffer[AHT20_STATUS_RESPONSE_MAX];
153     reval = memset_s(&buffer, sizeof(buffer), 0x0, sizeof(buffer));
154     if (reval == TRUE) {
155     printf("OK");
156     }
157 
158     retval = AHT20_StatusCommand();
159     if (retval != WIFI_IOT_SUCCESS) {
160         return retval;
161     }
162 
163     retval = AHT20_Read(buffer, sizeof(buffer));
164     if (retval != WIFI_IOT_SUCCESS) {
165         return retval;
166     }
167 
168     if (AHT20_STATUS_BUSY(buffer[0]) || !AHT20_STATUS_CALI(buffer[0])) {
169         retval = AHT20_ResetCommand();
170         if (retval != WIFI_IOT_SUCCESS) {
171             return retval;
172         }
173         usleep(AHT20_STARTUP_TIME);
174         retval = AHT20_CalibrateCommand();
175         usleep(AHT20_CALIBRATION_TIME);
176         return retval;
177     }
178 
179     return WIFI_IOT_SUCCESS;
180 }
181 
182 // 发送 触发测量 命令,开始测量
183 uint32_t AHT20_StartMeasure(void)
184 {
185     uint8_t triggerCmd[] = {AHT20_CMD_TRIGGER, AHT20_CMD_TRIGGER_ARG0, AHT20_CMD_TRIGGER_ARG1};
186     return AHT20_Write(triggerCmd, sizeof(triggerCmd));
187 }
188 
189 // 接收测量结果,拼接转换为标准值
190 uint32_t AHT20_GetMeasureResult(float* temp, float* humi)
191 {
192     uint32_t retval = 0, i = 0;
193     if (temp == NULL || humi == NULL) {
194         return WIFI_IOT_FAILURE;
195     }
196 
197     uint8_t buffer[AHT20_STATUS_RESPONSE_MAX];
198     reval = memset_s(&buffer, sizeof(buffer), 0x0, sizeof(buffer));
199     if (reval == TRUE) {
200     printf("OK");
201     }
202 
203     retval = AHT20_Read(buffer, sizeof(buffer));  // recv status command result
204     if (retval != WIFI_IOT_SUCCESS) {
205         return retval;
206     }
207 
208     for (i = 0; AHT20_STATUS_BUSY(buffer[0]) && i < AHT20_MAX_RETRY; i++) {
209         usleep(AHT20_MEASURE_TIME);
210         retval = AHT20_Read(buffer, sizeof(buffer));  // recv status command result
211         if (retval != WIFI_IOT_SUCCESS) {
212             return retval;
213         }
214     }
215     if (i >= AHT20_MAX_RETRY) {
216         printf("AHT20 device always busy!\r\n");
217         return WIFI_IOT_FAILURE;
218     }
219 
220     uint32_t humiRaw = buffer[1];
221     humiRaw = (humiRaw << NUM) | buffer[NUM_TWO];
222     humiRaw = (humiRaw << NUM_FOUR) | ((buffer[NUM_THREE] & 0xF0) >> NUM_FOUR);
223     *humi = humiRaw / (float)AHT20_RESOLUTION * ONE_HUNDRED;
224 
225     uint32_t tempRaw = buffer[3] & 0x0F;
226     tempRaw = (tempRaw << NUM) | buffer[NUM_FOUR];
227     tempRaw = (tempRaw << NUM) | buffer[NUM_FIVE];
228     *temp = tempRaw / (float)AHT20_RESOLUTION * TWO_HUNDRED - NUM_FIFTY;
229     return WIFI_IOT_SUCCESS;
230 }
231