Read and translate AHT20 sensor readings

This commit is contained in:
2024-09-03 22:42:10 +02:00
parent 83f6fa58a4
commit b9443f8cec
6 changed files with 225 additions and 196 deletions

View File

@@ -4,18 +4,23 @@
#include <avr/io.h>
#include <assert.h>
#define TW_START 0x08
#define TW_REP_START 0x10
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
#define TW_START 0x08
#define TW_REP_START 0x10
#define TW_MT_SLA_ACK 0x18
#define TW_MT_SLA_NACK 0x20
#define TW_MT_DATA_ACK 0x28
#define TW_MR_SLA_ACK 0x40
#define TW_MR_SLA_NACK 0x48
#define TW_MR_DATA_ACK 0x50
// XXX: Handle interrupts in TWI_vect ISR? This may not
// actually be much better than the blocking approach
static void TWI_AHT20_Reset(void);
static bool TWI_AHT20_IsCalibrated(void);
static void TWI_AHT20_Calibrate(void);
static void TWI_AHT20_Trigger(void);
int TWI_Init(void)
{
// Set SCL bit rate to 400kHz
@@ -139,11 +144,6 @@ int TWI_SetChannel(int channel)
{
unsigned char crb;
// assert(channel >= 0 && channel <= 3);
// PCA9546 I2C Multiplexer
// =======================
Info("Switching I2C channel to %d...", channel);
// Excerpts taken from the PCA9546A datasheet:
@@ -187,3 +187,171 @@ int TWI_SetChannel(int channel)
return 0;
}
int TWI_AHT20_Init(void)
{
TWI_AHT20_Reset();
// Wait 40ms after power-on
Sleep(40);
Info("Initializing AHT20 sensor...");
if (!TWI_AHT20_IsCalibrated()) {
TWI_AHT20_Calibrate();
if (!TWI_AHT20_IsCalibrated()) {
Info("Error: Calibration failed.");
return -1;
}
}
return 0;
}
int TWI_AHT20_Read(float *temp, float *rhum)
{
unsigned char data[6], crc;
unsigned long hraw, traw;
TWI_AHT20_Trigger();
TWI_Start(0x38, 1);
TWI_Wait_ACK();
data[0] = TWI_Read_ACK();
data[1] = TWI_Read_ACK();
data[2] = TWI_Read_ACK();
data[3] = TWI_Read_ACK();
data[4] = TWI_Read_ACK();
data[5] = TWI_Read_ACK();
crc = TWI_Read_NACK();
TWI_Stop();
// After receiving six bytes, the next byte is the
// CRC check data, the user can read it as needed,
// if the receiving end needs CRC check, then send
// it after receiving the sixth byte ACK response,
// otherwise NACK is sent out, CRC initial value is
// 0xFF. The CRC8 check polynomial is:
// CRC[7:0]= 1 + (x^4) + (x^5) + (x^8)
// TODO: Implement CRC8 check
UNUSED(crc);
hraw = (unsigned long) data[1] << 12;
hraw |= (unsigned short) data[2] << 4;
hraw |= data[3] >> 4;
traw = (unsigned long) (data[3] & 0x0F) << 16;
traw |= (unsigned short) data[4] << 8;
traw |= data[5];
*rhum = (float) hraw / 1048576.0f * 100.0f;
*temp = (float) traw / 1048576.0f * 200.0f - 50.0f;
return 0;
}
static void TWI_AHT20_Reset(void)
{
// The command 0xBA is used to restart the sensor
// system without turning the power off and on
// again. After receiving this command, the sensor
// system begins to re-initialize and restore the
// default setting state. The time required for
// soft reset does not exceed 20 ms.
TWI_Start(0x38, 0);
TWI_Wait_ACK();
TWI_Write(0xBA);
TWI_Wait_ACK();
TWI_Stop();
Sleep(20);
}
static bool TWI_AHT20_IsCalibrated(void)
{
unsigned char status;
// Before reading the temperature and humidity
// values, first check whether the calibration
// enable bit Bit [3] of the status word is 1 (you
// can get a byte of status word by sending 0x71).
TWI_Start(0x38, 0);
TWI_Wait_ACK();
TWI_Write(0x71);
TWI_Wait_ACK();
TWI_Stop();
TWI_Start(0x38, 1);
TWI_Wait_ACK();
status = TWI_Read_NACK();
TWI_Stop();
// Note: The calibration status check only needs to
// be checked at power-on. No operation is required
// during the normal acquisition process.
return status & BIT(3);
}
static void TWI_AHT20_Calibrate(void)
{
// To calibrate you need to send 0xBE command (for
// initialization), this command parameter has two
// bytes, the first byte is 0x08, the second byte
// is 0x00, and then wait for 10ms.
TWI_Start(0x38, 0);
TWI_Wait_ACK();
TWI_Write(0xBE);
TWI_Wait_ACK();
TWI_Write(0x08);
TWI_Wait_ACK();
TWI_Write(0x00);
TWI_Wait_ACK();
TWI_Stop();
}
static void TWI_AHT20_Trigger(void)
{
unsigned char status;
// Send the 0xAC command directly (trigger
// measurement). The parameter of this command has
// two bytes, the first byte is 0x33 and the second
// byte is 0x00.
TWI_Start(0x38, 0);
TWI_Wait_ACK();
TWI_Write(0xAC);
TWI_Wait_ACK();
TWI_Write(0x33);
TWI_Wait_ACK();
TWI_Write(0x00);
TWI_Wait_ACK();
TWI_Stop();
// Wait for 80ms to wait for the measurement to be
// completed. If the read status word Bit [7] is 0,
// it indicates that the measurement is completed,
// and six bytes can be read in a row. Otherwise
// continue to wait.
TWI_Start(0x38, 1);
TWI_Wait_ACK();
do {
Sleep(80);
status = TWI_Read_ACK();
} while ((status & BIT(7)) == 1);
TWI_Stop();
}

View File

@@ -15,4 +15,7 @@ unsigned char TWI_Read_NACK(void);
int TWI_Wait_ACK(void);
int TWI_Stop(void);
int TWI_AHT20_Init(void);
int TWI_AHT20_Read(float *temp, float *rhum);
#endif // MAD_CORE_BUS_TWI_H