
AHT20 Sensor Library for Proteus V1.0: Temperature, Humidity, BMP280

Hello friends, I hope you all are doing great. Today, I am going to share the new AHT20 Sensor Library for Proteus V1.0. The AHT20 is the small I2C temperature and humidity sensor that has replaced the DHT11 in many new designs: it is more accurate, it answers on the I2C bus in a fraction of a second, and it costs about the same. It often comes on a combo board with the BMP280 pressure sensor, which makes a complete weather station on four wires. Now you can build and test those projects in Proteus, with the blue AHT20 module and the purple AHT20 + BMP280 module.
Behind the parts sit our own models, not parts that show a number. The AHT20 answers the Arduino exactly as its datasheet says: the status byte with the busy bit, the 80 ms measurement, the 20-bit values and the CRC-8. On the combo board the BMP280 sits on the same I2C bus with its chip ID, its calibration words and its modes, and the Adafruit library turns its raw values back into the air pressure. You get four devices: both modules as a Simple device with a live STATUS panel and the air's controls, and as an Advance device with a pop-up window and the test tools. The demo runs the Adafruit AHTX0 library and the Adafruit BMP280 library on our Arduino UNO V4.0.
NOTICE: a weather sensor is easy to fake: read a number from a property and hand it to the Arduino. We wanted more. Our AHT20 measures for 80 ms, sets its busy bit, packs its 20-bit values and computes its CRC, and our BMP280 hands out raw values that only its calibration words turn into a pressure, so the Adafruit libraries read them exactly as on your desk, and the classic mistakes fail exactly as they do there. It took our team a lot of hard work. Your feedback is the fuel that keeps us going, so please tell us what you think in the comments below or in the AHT20 board of our forum. And if our free libraries help you, you can buy us a coffee. So, let's get started with the AHT20 Sensor Library for Proteus V1.0:
What is the AHT20?
The AHT20 from Aosong is a digital temperature and relative humidity sensor with an I2C interface, in a 3 x 3 mm package with a small opening that lets the air reach its humidity element. It is the successor of the AHT10 (read our AHT10 Temperature and Humidity Module) and a modern alternative to the DHT11 and DHT22 of our DHT11 / DHT22 Library for Proteus and the SHT31 of our SHT31 Library for Proteus. The module adds a 3.3 V regulator and the I2C pull-ups, so it works from 5 V too.
| AHT20 | |
|---|---|
| Temperature | -40 to 85 C, 0.01 C resolution, +-0.3 C typical |
| Humidity | 0 to 100 %RH, 0.024 %RH resolution, +-2 %RH typical |
| Measurement | triggered by 0xAC 0x33 0x00, about 80 ms, busy bit in the status |
| Data | status, 20 bits of humidity, 20 bits of temperature, CRC-8 |
| Interface | I2C at 0x38 (one address only) |
| Supply | 2.0 to 5.5 V (the module: 3.3 or 5 V) |
| Devices | AHT20TEP and AHTBMPTEP (Simple), AHT20ADVTEP and AHTBMPADVTEP (Advance) |
The Status Byte and a Measurement
The AHT20 has no registers to point at. A read returns the status byte first: bit 7 is busy and bit 3 is CAL, calibrated, so an idle sensor answers 0x18. A measurement starts with the three bytes 0xAC 0x33 0x00; the sensor sets the busy bit, measures for about 80 ms, and clears it. The Arduino then reads six bytes: the status, 20 bits of humidity and 20 bits of temperature packed together, and, if it wants, a seventh byte, the CRC-8. Humidity = S / 2^20 x 100 %, temperature = S / 2^20 x 200 - 50 C.
The BMP280 Next to It
The BMP280 from Bosch measures the air pressure (300 to 1100 hPa) and its own temperature, and from the pressure an Arduino can work out the altitude. On the combo module it shares the I2C bus at address 0x77. Our BMP280 Library for Proteus and BME280 Sensor Library for Proteus cover it on its own; here it works next to the AHT20, the way a small weather station like our IoT based Weather Station with Raspberry Pi 4 uses them.
What's New in AHT20 Sensor Library for Proteus V1.0
- Two real modules: the blue AHT20 module and the purple AHT20 + BMP280 module, drawn at about three times their real size.
- Two styles each: a Simple device with a STATUS panel and an Advance device with a pop-up window; the LEDs and the panel button sit on the board itself.
- The real AHT20: the status byte, the 80 ms measurement with the busy bit, the soft reset, the initialize command, the 40 ms after power-on, the 20-bit values and the CRC-8.
- The real BMP280: the chip ID, the calibration words, the modes and the oversampling, raw values for the Bosch compensation, on the same bus as the AHT20.
- The air on the panel: temperature and humidity - and +, the pressure on the combo board, and six presets from a hot day to a freezer.
- Mistake detection: a reading before a measurement, a reading while the sensor is busy, the same result twice, a trigger while busy, an unknown command, a temperature out of range.
- Four test tools on the Advance devices: I2C, Readings, Frame and CRC, and BMP280.
- A two-node demo on our Arduino UNO V4.0 with the Adafruit libraries: one sketch for both modules, with the 7 bytes by hand, the status byte and the soft reset.
- A compact package: about 1.31 MB, without the C++ source code of the model.
Four Devices: Two Modules, Two Styles
The AHT20 module carries the AHT20 with its sensing opening, the 662K regulator, the pull-ups R1 and R2, the capacitor C1 and the header VIN, GND, SCL and SDA on the left. The combo module adds the BMP280 in its metal package with the vent hole. Both use the same four pins, so you can swap one for the other.
| Simple | Advance | |
|---|---|---|
| AHT20 module | AHT20TEP | AHT20ADVTEP |
| AHT20 + BMP280 module | AHTBMPTEP | AHTBMPADVTEP |
| On the schematic | The module and the STATUS panel | The module |
| The air | On the STATUS panel | In the pop-up |
| Status | Banner, 10 readouts, the last 4 events | A pop-up: Sensor, Event log, Tests |
Download AHT20 Sensor Library for Proteus
Click the button below to download AHT20-Sensor-Library-for-Proteus-v1.0.zip (about 1.31 MB, without the C++ source code of the model):
AHT20 Sensor Library for Proteus V1.0: Temperature, Humidity, BMP280- README.txt: the devices, installation, the demo, wiring, the test tools and real hardware.
- Proteus Library Files:
TEPAHT20.LIBandArduinoV4TEP.LIBfrom our Arduino Library for Proteus V4.0. - Proteus Model Files:
TEPAHT20.DLLandTEPARDUINO.DLL. - Proteus Simulation:
AHT20-Sensor-ArduinoUnoV4.pdsprj,AHT20_Demo.hexand copies of the two DLLs. - Arduino Code:
AHT20_Demo.ino. It needs the Adafruit AHTX0 and BMP280 libraries from the Library Manager of the Arduino IDE, only if you want to change the sketch.
No Proteus yet? Read How to Download and Install Proteus 7 and 8. New to libraries? Follow How to Install a New Library in Proteus.
How to Install AHT20 Sensor Library for Proteus
- Close Proteus and extract the whole zip file, for example to your Desktop.
- Copy the two files from Proteus Library Files into the LIBRARY folder of Proteus (usually
C:\Program Files (x86)\Labcenter Electronics\Proteus 8 Professional\LIBRARY). - Copy
TEPAHT20.DLLandTEPARDUINO.DLLfrom Proteus Model Files into the MODELS folder. - Delete
TEPAHT20.IDXfrom the LIBRARY folder if it is there. - Start Proteus, press P and search for AHT20 or AHTBMP.
Tip: keep the Proteus Simulation folder together, because the project needs its .hex file and the DLLs beside it. The library is tested in Proteus 8.5; Proteus 7 is not supported.
The AHT20 Parts in Proteus
Two LEDs sit on the module's board: PWR while VIN is there and I2C, which flashes when the Arduino talks to the module. Next to the SIMPLE or ADVANCE badge is the panel button. The LEDs, the badge, the button and the panels are TEP additions; the real modules have none of them.
The Simple device adds the STATUS panel. Its banner says what the sensor read, for example "READ 24.01 C, 50.03 %RH - 23 MEASUREMENTS", and turns red when a warning comes. Below it are the air's controls: TEMPERATURE and HUMIDITY with - and + (0.5 C and 1 % a click; on the combo board also PRESSURE, 1 hPa a click) and six presets: ROOM, HOT, HUMID, DRY, COLD and FREEZER. Ten readouts follow - the state, what the sensor read, the status byte, the reads, the air, the measurements, the busy polls and the last CRC - and the last four events.
The red X closes the STATUS panel, and the PANEL button on the board opens it again:
The Advance devices keep the schematic clean: only the module. Their live data opens in a pop-up window at Run, and the OPEN PANEL button on the board brings the window back. The properties TEMPERATURE, HUMIDITY and, on the combo module, PRESSURE set the air at the start; NOISE (1 by default, about one step) sets the AHT20's noise.
The Demo Circuit
The demo project has two nodes. Each one is an Arduino UNO V4.0 from our Arduino UNO Library for Proteus V4.0 with a module on its SDA and SCL pins, which are A4 and A5. Both UNOs run the same AHT20_Demo.hex: it looks for the BMP280 and adds the pressure when it finds one. Node 1 uses the Simple AHT20 module in air at 24 C and 50 %RH; node 2 uses the Advance AHT20 + BMP280 module at 28 C, 65 %RH and 1005 hPa.
Wiring
| Module | Arduino UNO |
|---|---|
| VIN | 5V (3.3 V works too) |
| GND | GND |
| SCL | A5 (the SCL pin) |
| SDA | A4 (the SDA pin) |
In Proteus, SDA and SCL reach their UNO through net labels, SDA_1 and SCL_1 for node 1 and SDA_2 and SCL_2 for node 2. The Wire library turns on the UNO's internal pull-ups, which hold the I2C bus HIGH in the simulation. The serial monitor needs no wires at all, because it is built into the UNO V4.0.
The Arduino Code
The demo sketch uses the Adafruit AHTX0 library (version 2.0.6) and the Adafruit BMP280 library (version 3.0.0) with Adafruit Unified Sensor and Adafruit BusIO. New to Arduino? Start with Arduino Tutorial for Beginners and Introduction to Arduino UNO. The sketch begins with Wire and the two libraries:
#include <Wire.h>
#include <Adafruit_AHTX0.h>
#include <Adafruit_BMP280.h>
In setup(), aht.begin() waits 20 ms, sends the soft reset and the initialize command and checks the CAL bit; bmp.begin() looks for the BMP280 at 0x77, which only the combo module has:
haveAht = aht.begin();
Serial.println(haveAht ? F("AHT20 found at 0x38 (calibrated)") : F("AHT20 not found - check the wiring"));
haveBmp = bmp.begin(BMP_ADDR);
Serial.println(haveBmp ? F("BMP280 found at 0x77") : F("no BMP280 - the AHT20 module alone"));
A reading is one getEvent() for the AHT20: it sends 0xAC 0x33 0x00, polls the status until the busy bit clears and reads six bytes. With a BMP280 the sketch adds its temperature, the pressure in hPa and the altitude:
void readAll() {
sensors_event_t humidity, temp;
Serial.print('#'); Serial.print(++count);
if (!aht.getEvent(&humidity, &temp)) { Serial.println(F(" AHT20 read failed")); return; }
Serial.print(F(" AHT20 ")); Serial.print(temp.temperature, 2);
Serial.print(F(" C ")); Serial.print(humidity.relative_humidity, 2); Serial.print(F(" %RH"));
if (haveBmp) {
Serial.print(F(" BMP280 ")); Serial.print(bmp.readTemperature(), 2);
Serial.print(F(" C ")); Serial.print(bmp.readPressure() / 100.0, 2);
Serial.print(F(" hPa ")); Serial.print(bmp.readAltitude(seaLevel), 1); Serial.print(F(" m"));
}
Serial.println();
}
The HEX file is in the package, so you do not need the Arduino IDE to run the demo. To change the sketch, install "Adafruit AHTX0" and "Adafruit BMP280 Library" from the Library Manager, open the sketch in the Arduino IDE and export the compiled binary, as in How to get the HEX file from Arduino. It needs 20,464 bytes of flash and 667 bytes of RAM.
The Serial Monitor
Both UNOs have the serial monitor built in, and it opens at Run. The screenshots use its Simple interface. Node 1 starts like this:
TEP AHT20 - demo (Adafruit AHTX0 and BMP280 libraries)
SDA on A4, SCL on A5
AHT20 found at 0x38 (calibrated)
no BMP280 - the AHT20 module alone
Commands: RUN | STOP | RAW | STATUS | RESET | HELP
#1 AHT20 23.99 C 50.00 %RH
#2 AHT20 23.99 C 50.01 %RH
#3 AHT20 23.99 C 50.00 %RH
The AHT20 answers at 0x38 with the CAL bit set, and nobody answers at 0x77, so this is the AHT20 module alone. Every 2 seconds a reading follows: 24 C reads 23.99 C or 24.00 C, and the humidity moves by a hundredth either way, one step of noise as on a real sensor. Node 2 has the BMP280 too:
BMP280 found at 0x77
Commands: RUN | STOP | RAW | STATUS | RESET | HELP
SEA 1013.25 (the sea-level pressure for the altitude)
#1 AHT20 27.99 C 65.00 %RH BMP280 28.00 C 1005.00 hPa 68.9 m
#2 AHT20 27.99 C 65.01 %RH BMP280 28.00 C 1005.00 hPa 68.9 m
The two chips agree on the temperature, and 1005 hPa is 68.9 m above a sea level of 1013.25 hPa. Type a command in the monitor and press Enter: STOP stops the readings, RUN starts them again, and the others are explained below.
Change the Air
Now let's change the air while the simulation runs. We clicked HOT on U1's STATUS panel with the mouse:
#23 AHT20 24.01 C 50.03 %RH
#24 AHT20 38.00 C 29.99 %RH
#25 AHT20 38.00 C 29.97 %RH
The next reading already shows the new air. The real AHT20 needs a few seconds to follow a change of air; the model answers at once, so you see the result of every click without waiting. Then four clicks on the temperature's + and five on the humidity's -:
#26 AHT20 37.99 C 30.00 %RH
#27 AHT20 40.01 C 28.97 %RH
#28 AHT20 40.00 C 24.97 %RH
#29 AHT20 39.99 C 25.02 %RH
Line #27 caught the clicks on the way, 40 C but not yet 25 %RH. Each click is 0.5 C or 1 %RH. Then the coldest preset, FREEZER:
#30 AHT20 39.98 C 24.99 %RH
#31 AHT20 -17.99 C 70.00 %RH
#32 AHT20 -17.99 C 70.00 %RH
#33 AHT20 -18.00 C 70.02 %RH
A negative temperature needs nothing special: 20 bits from -50 to 150 C cover it. Below -40 C or above 85 C the AHT20 is out of its range; the model then stops at the limit and the banner says so.
RAW: the Seven Bytes by Hand
RAW does what the library does, by hand with Wire, and reads the seventh byte too: the trigger, 80 ms, the busy bit, then seven bytes:
void raw() {
Wire.beginTransmission(AHT_ADDR);
Wire.write(0xAC); Wire.write(0x33); Wire.write(0x00);
Wire.endTransmission();
delay(80);
while (readStatus() & 0x80) delay(10);
uint8_t d[7];
Wire.requestFrom(AHT_ADDR, (uint8_t)7);
for (uint8_t i = 0; i < 7; i++) d[i] = Wire.read();
Serial.print(F("RAW:"));
for (uint8_t i = 0; i < 7; i++) { Serial.print(' '); printHex(d[i]); }
const uint8_t c = crc8(d, 6);
The CRC-8 has the polynomial 0x31 and starts at 0xFF:
uint8_t crc8(const uint8_t* d, uint8_t n) {
uint8_t c = 0xFF;
for (uint8_t i = 0; i < n; i++) {
c ^= d[i];
for (uint8_t k = 0; k < 8; k++) c = (c & 0x80) ? (c << 1) ^ 0x31 : c << 1;
}
return c;
}
RAW
RAW: 18 B3 49 B2 8F 44 E6 CRC E6 OK
RAW: humidity 734363 = 70.03 %RH, temperature 167748 = -18.00 C
#34 AHT20 -18.00 C 70.00 %RH
STATUS
STATUS: 0x18 - busy 0, calibrated 1
The bytes decode by the datasheet: 18 is the status, idle and calibrated; B3 49 B are the 20 bits of humidity, 734363 / 1048576 x 100 = 70.03 %RH; 2 8F 44 are the 20 bits of temperature, 167748 / 1048576 x 200 - 50 = -18.00 C; and E6 is the CRC of the first six bytes. The two values share byte 3, half each:
const uint32_t h = ((uint32_t)d[1] << 12) | ((uint32_t)d[2] << 4) | (d[3] >> 4);
const uint32_t t = ((uint32_t)(d[3] & 0x0F) << 16) | ((uint32_t)d[4] << 8) | d[5];
STATUS reads one byte: 0x18, busy 0 and calibrated 1. RESET sends the soft reset 0xBA, after which the AHT20 needs 20 ms.
The Advance Pop-Up Window
At Run, the Advance AHT20 + BMP280 module opens its own window, AHT20 + BMP280 Module, with the look of our TEP Serial Monitor Advance for Proteus. It has three tabs, Sensor, Event log and Tests, plus Settings and Help behind the gear and question mark icons. The status bar at the bottom always shows the air, the AHT20's reading, the pressure and the state.
The toolbar carries the six presets. The top card is the air: the temperature with -5, -0.5, +0.5 and +5 C, the humidity and the pressure with -10, -1, +1 and +10, the dew point and the altitude. The next card is the AHT20: the banner, the temperature and humidity it read with their raw values, the status byte and the measurements. The BMP280 card shows its temperature, the pressure, the altitude and its mode; the last card draws the last I2C transaction byte by byte, with the ones before it. We clicked HUMID:
At 90 %RH the dew point is 28.2 C, only 1.8 C below the air: any surface a little colder gets wet. Then three clicks on the pressure's -10 and one on the temperature's +5:
#6 AHT20 29.98 C 90.02 %RH BMP280 30.00 C 1005.00 hPa 68.9 m
#7 AHT20 30.01 C 90.01 %RH BMP280 30.00 C 985.00 hPa 237.9 m
#8 AHT20 29.99 C 90.01 %RH BMP280 30.00 C 975.00 hPa 323.4 m
#10 AHT20 35.00 C 89.99 %RH BMP280 35.00 C 975.00 hPa 323.5 m
30 hPa less is about 250 m higher: near sea level 1 hPa is about 8.4 m. The altitude is only as good as the sea-level pressure the sketch assumes, so SEA sets it:
RESET
RESET: soft reset (0xBA), 20 ms
SEA 1000
SEA: 1000.00 hPa
#14 AHT20 34.99 C 90.01 %RH BMP280 35.00 C 975.00 hPa 213.1 m
With today's sea-level pressure at 1000 hPa, the same 975 hPa is 213.1 m instead of 323.5 m. A weather station at a fixed place does it the other way round: it knows its altitude and works out the sea-level pressure. Then we clicked FREEZER in the pop-up:
The Test Tools
The I2C tool is the one to open for a sensor that does not answer, a reading that never changes or a reading that is all zero. It counts the triggers, the status polls (the library polls every 10 ms, about 8 times a measurement), the readings with or without the CRC, and the mistakes: a reading while busy, before any measurement or twice. The Readings tool lists the last 24 transactions of the module, both chips:
Frame and CRC takes the last reading apart: the bytes, which bits are the humidity and which the temperature, the maths, and the CRC-8 step by step. Open it for a wrong value or a reading that is all zero. The BMP280 tool covers the pressure sensor:
It shows the chip ID 0x58, the calibration reads, the settings (normal mode with x16 oversampling after begin()), the conversion time and the 12 calibration words the compensation uses. Note that readAltitude() reads the pressure again, so each line of the demo is five BMP280 reads.
The Event Log
The Event log lists everything that happened, newest first: the power, every AHT20 reading with its status and values, the commands, the BMP280's reads and writes, the air's changes with where they came from, notes and warnings. Filter it by I2C or warnings, pause it, or clear it.
The Simulation Log
Every module also writes to the simulation log of Proteus, with the exact simulation time. This part shows begin() and the first readings:
U1: Write 0xBA - soft reset (20 ms) at 0.0994 s
U1: Write 0xE1 0x08 0x00 - initialize: the CAL bit is set (0xE1 is the AHT10's command; the AHT20's is 0xBE) at 0.1201 s
U2: BMP280: Write 0xF4 (ctrl_meas) = 0xB7 - temperature x16, pressure x16, normal mode; standby 0.5 ms, filter off at 0.1393 s
U1: Write 0xAC 0x33 0x00 - trigger a measurement (busy for 80 ms) at 0.7058 s
U1: Read 6 bytes: status 0x18, humidity 0x7FFED = 50.00 %RH, temperature 0x5EB54 = 23.99 C (CRC not read) at 0.7888 s
U2: BMP280: Read 0xFA (temperature): 0x81333 = 28.00 C at 0.9011 s
U2: BMP280: Read 0xF7 (pressure): 0x66340 = 1005.00 hPa at 0.9030 s
The trigger at 0.7058 s and the reading at 0.7888 s are 83 ms apart: the 80 ms measurement and the last status poll. The Adafruit library still sends the AHT10's initialize command 0xE1; the AHT20 accepts it, and the log says which one the datasheet names.
How the Model Works
Both modules are digital models. VIN and GND power them, and SCL and SDA are the I2C bus: Proteus runs every edge from the Arduino with its exact time, and the model pulls SDA low to acknowledge and to send. The AHT20 keeps its status byte, starts an 80 ms measurement on 0xAC 0x33 0x00, turns the air into 20-bit values with about one step of noise when it ends, and computes the CRC-8 of what it sends. On the combo module our BMP280 core answers at 0x77 on the same lines: it keeps its registers, converts in its mode and timing, and inverts the Bosch compensation, so the raw values it sends turn back into the air's temperature and pressure.
Troubleshooting
- "AHT20 not found": no power on VIN and GND, or SDA and SCL swapped or missing; the PWR LED is off or the I2C LED never flashes.
- "no BMP280": right on the AHT20 module; on the combo module check the address (0x77 here).
- -50.00 C and 0.00 %RH: the AHT20 was read before any measurement; trigger it first, as getEvent() does.
- The reading lags one step: the data was read while the AHT20 was still measuring; wait for the busy bit.
- The temperature stops at -40 C or 85 C: the AHT20's range.
- A wrong altitude: set today's sea-level pressure with SEA.
- No part or no monitor: TEPAHT20.DLL or TEPARDUINO.DLL is missing from MODELS and the project folder; a closed monitor opens again with a click on the UNO's USB port.
Things to Know Before Using a Real AHT20
- One address: the AHT20 is always at 0x38, so two of them need two I2C buses or a multiplexer.
- Give it time: leave about 2 seconds between measurements, as the demo does; a sensor that measures all the time warms itself.
- Placement: keep the module away from the regulator and other warm parts, and give the air a way in.
- The BMP280's address: 0x77 on this combo board, 0x76 on some others: then call bmp.begin(0x76).
Limitations of the Simulation
- Not modelled: the AHT20's accuracy (the datasheet: +-0.3 C, +-2 %RH) and its response time (about 8 s for humidity), self-heating, drift and condensation, the BMP280's own errors, SPI and the I2C clock stretching.
- The LEDs, the badge, the panel button and the panels are TEP additions.
- The models are our own, written from the AHT20 and BMP280 datasheets. This library is not made or endorsed by Aosong, Bosch, Adafruit, the makers of the modules or Labcenter.
- Licences: the demo sketch uses the Adafruit AHTX0 library 2.0.6 (BSD), the Adafruit BMP280 library 3.0.0 (MIT), Adafruit Unified Sensor 1.1.15 (Apache 2.0) and Adafruit BusIO 1.17.4 (MIT), which are not shipped; install them from the Library Manager. The demo's HEX file contains them and the Arduino AVR core 1.8.6 with LGPL-licensed code; the licence texts and the source links are in the README.
- Tested in Proteus 8.5 in October 2026 (the demo as shipped on two Arduino UNO V4.0 boards with their built-in monitors: both nodes reading, HOT, the + and - buttons, FREEZER, RAW and STATUS on node 1 with the mouse, the red X and PANEL, HUMID, the pressure, +5 C, RAW, STATUS, RESET, SEA and FREEZER on node 2, the four tools; 89.5 s of simulation took 165 s, about 0.5 x real time with the pop-up and both monitors open). Proteus 7 is not supported.
So, that was all about the AHT20 Sensor Library for Proteus V1.0. I hope the status byte, the 80 ms measurement and the CRC are clear now, and that your weather station reads the right air from the first run. If you use the AHT20 Sensor Library for Proteus in a project, please share it in the comments or in our forum, and if you have any questions, ask in the comments and I will help you out. Till the next tutorial, take care and have fun!
























Comments
0