SHT31 BASCOM-AVR Code: I²C Reading, CRC-8 and Conversion

Follow the SHT31 from a 0x2400 high-repeatability measurement request to a six-byte I²C read on ATmega328P. The BASCOM-AVR listing shows separate CRC-8 checks for temperature and humidity, conversion formulas, serial output, and practical NACK and CRC diagnostics.

Real SHT31 bench test showing 18.4 degrees Celsius and 50.9 percent humidity on an OLED
Completed SHT31 test bench with an OLED reading of 18.4 °C and 50.9% RH.

How does the BASCOM-AVR code read the SHT31?

The program sends 0x24 0x00, waits, then reads six bytes from the sensor. Bytes 1–2 contain temperature, byte 3 is its CRC, bytes 4–5 contain humidity, and byte 6 is the humidity CRC. Initialize CRC separately for each two-byte word (0xFF start, polynomial 0x31). Check temperature against byte 3 and humidity against byte 6 before converting: T = raw × 175 / 65535 − 45 and RH = raw × 100 / 65535.

What this SHT31 implementation covers

Temperature and relative humidity monitoring is useful in drying equipment, storage cabinets and other environmental-control systems. Among common digital sensors such as DHT22, BME280, SHT31 and SHT35, the SHT31 provides a compact I²C interface and separate integrity checks for temperature and humidity data.

This implementation follows the complete path from an I²C command to a checked and converted value. It separates four stages that are often collapsed into one: starting a measurement, receiving the six-byte data structure, validating data integrity and formatting the result.

SHT31 implementation summary
ItemImplementation
Controller definitionm328pdef.dat, 16 MHz
Programming environmentBASCOM-AVR IDE 2.0.8.6
I²C libraryi2c_twi.lbx
Pins and clockSCL on PORTC.5, SDA on PORTC.4, TWI at 400000
I²C 7-bit address0x44 (0x88 write / 0x89 read); alternative 0x45 when ADDR is high
Command bytes0x24 0x00 — single-shot, high repeatability, no clock stretching
High-repeatability conversion12.5 ms typical, 15.5 ms maximum in the SHT3x-DIS datasheet; listing uses Wait 1
ResponseSix bytes: two data bytes plus CRC for temperature, then the same for humidity
CRC parametersInitial value 0xFF, polynomial 0x31
Displayed precisionOne decimal place

The real SHT31 module and bench wiring

The breakout board exposes the primary connections VIN, GND, SCL and SDA/RH. Additional reverse-side pads are labelled AL and AD, with the supporting resistors and passive components already installed on the module.

Front and back view of the purple SHT31 breakout module
Front and rear views of the SHT31 breakout board, including the sensor, connection labels, auxiliary pads and passive components.

The module connects to a small controller board through a short four-wire lead, while a ribbon cable connects the controller to the OLED. The wiring follows the labelled power and I²C functions on the breakout board.

Electrical checks before powering the bus

Connect grounds, confirm the breakout board's actual supply-voltage range, and ensure SDA/SCL pull-ups go to a voltage accepted by both the module and the ATmega328P. Do not assume a breakout labelled VIN contains a regulator or level shifter. On an SHT31-DIS sensor, ADDR low selects 7-bit address 0x44; ADDR high selects 0x45. The shown code uses 0x44.

Real SHT31 module connected by four wires to the controller and OLED test assembly
Assembled test wiring: SHT31 breakout at upper left, controller at upper right and OLED at lower left.

BASCOM-AVR configuration and variables

The BASCOM source file is named SHT31 Test mit CRC.bas. It targets an ATmega328P definition, uses a 16 MHz clock and configures serial output at 9600 baud. Hardware TWI is initialized at 400 kHz.

The program stores converted readings in Temperatur and Feuchte, and formats them into Str_temp and Str_rel. Ar(10) is the receive buffer, although only elements 1 through 6 are used for the transaction. Calc holds the combined 16-bit raw word. Crc, Anded and Rep support the bitwise CRC loop.

BASCOM AVR screen showing SHT31 I2C setup and variable declarations
BASCOM-AVR device definition, I²C library, pin configuration and core variables.

Initialization and variable declarations

INITIALIZATION AND VARIABLES
$regfile = "m328pdef.dat"
$crystal = 16000000
$baud = 9600

$lib "i2c_twi.lbx"
Config Scl = PORTC.5
Config Sda = PORTC.4
Config Twi = 400000
I2cinit

Dim Temperatur As Single , Str_temp As String * 10
Dim Feuchte As Single , Str_rel As String * 10
Dim Ar(10) As Byte
Dim Calc As Word
Dim I As Integer
Dim Crc As Byte
Dim Anded As Byte
Dim Rep As Byte

Do
  Str_temp = ""
  Str_rel = ""

How the code starts one SHT31 measurement

Inside Do ... Loop, the program writes the 8-bit address 0x88 followed by 0x24 0x00. Together, 0x2400 requests single-shot, high-repeatability measurement without clock stretching, not just a generic read. The SHT3x-DIS datasheet specifies 12.5 ms typical and 15.5 ms maximum for high-repeatability conversion.

The example uses Wait 1 (one second), a deliberately conservative demo delay rather than the sensor’s required conversion time. The selected 7-bit I²C address is 0x44: (0x44 << 1) | 0 gives 0x88 for writing and (0x44 << 1) | 1 gives 0x89 for reading. If ADDR selects 0x45, the corresponding transmitted bytes are 0x8A/0x8B.

What the six returned bytes contain

The read transaction starts again and sends 0x89. The first five bytes are read with ACK, while the sixth and final byte is read with NACK before the bus is stopped. This ACK/NACK pattern lets the controller accept each continuing byte and then terminate the read cleanly after the known frame length.

Buffer elementData functionRead response
Ar(1)Temperature MSBACK
Ar(2)Temperature LSBACK
Ar(3)Temperature CRCACK
Ar(4)Humidity MSBACK
Ar(5)Humidity LSBACK
Ar(6)Humidity CRCNACK
BASCOM AVR code reading six SHT31 bytes with ACK and final NACK
BASCOM-AVR command sequence, six-byte receive order and the beginning of the temperature CRC block.

Measurement command and six-byte read

MEASURE AND READ SIX BYTES
I2cstart
I2cwbyte &H88
I2cwbyte &H24
I2cwbyte &H00
I2cstop

Wait 1

I2cstart
I2cwbyte &H89
I2crbyte Ar(1) , Ack
I2crbyte Ar(2) , Ack
I2crbyte Ar(3) , Ack
I2crbyte Ar(4) , Ack
I2crbyte Ar(5) , Ack
I2crbyte Ar(6) , Nack
I2cstop

How the CRC-8 check works

Temperature and humidity are validated independently. For temperature, the loop processes Ar(1) and Ar(2), then compares the result with Ar(3). For humidity, it processes Ar(4) and Ar(5), then compares the result with Ar(6).

  1. Initialize Crc to 0xFF.
  2. XOR the next data byte into the current CRC.
  3. Repeat eight times, testing the top bit with 0x80.
  4. Shift left once; when the tested bit was set, XOR with 0x31.
  5. Accept the word only when the calculated CRC equals its received CRC byte.

A six-byte read is not proof that the values are valid. Both two-byte measurement words need their own initialized CRC calculation; the previous temperature CRC must not be reused for humidity. The checksum uses CRC-8, polynomial 0x31 (x⁸ + x⁵ + x⁴ + 1), init 0xFF, no reflection, and final XOR 0x00.

Verifiable test vector

The manufacturer gives the two data bytes 0xBE 0xEF → calculated CRC 0x92. Run that vector through your CRC routine before trusting live samples. The earlier HTML excerpt calculated only the temperature CRC before comparing Crc with the humidity checksum; the humidity pass is explicitly added below.

BASCOM AVR SHT31 CRC loop and temperature conversion code
CRC loop, comparison with Ar(3) and the temperature conversion.

Temperature CRC and conversion code

TEMPERATURE CRC AND CONVERSION
Crc = &HFF
For I = 1 To 2
  Crc = Crc Xor Ar(i)
  For Rep = 1 To 8
    Anded = Crc And &H80
    If Anded <> 0 Then
      Shift Crc , Left , 1
      Crc = Crc Xor &H31
    Else
      Shift Crc , Left , 1
    End If
  Next Rep
Next I

If Crc = Ar(3) Then
  Calc = Makeint(ar(2) , Ar(1))
  Temperatur = Calc * 175
  Temperatur = Temperatur / 65535
  Temperatur = Temperatur - 45
  Str_temp = Fusing(temperatur , "#.#")
  Str_temp = Str_temp + " C "
Else
  Str_temp = "--- C "
End If

SHT31 temperature and humidity conversion formulas

After a successful temperature CRC check, the program combines Ar(2) and Ar(1) with Makeint. The resulting unsigned 16-bit value is scaled across 65535 counts.

Temperature (°C) = raw × 175 / 65535 − 45

The valid temperature is formatted with Fusing(Temperatur, "#.#"), producing one decimal place, and C is appended. If CRC fails, the temperature string becomes --- C.

Humidity follows the same structure after its own CRC check. Ar(5) and Ar(4) are combined, then scaled directly to percent relative humidity.

Relative humidity (%RH) = raw × 100 / 65535

The valid value is formatted to one decimal place and followed by %. A failed humidity CRC produces --- %. The placeholders are useful because they preserve the output shape without presenting corrupted data as a plausible environmental reading.

Serial output and the final OLED test

After the temperature check, CRC must be reset to 0xFF and recalculated over Ar(4) and Ar(5) before comparison with Ar(6). The original HTML excerpt omitted this intermediate step. The corrected listing below then prints both formatted results.

BASCOM AVR humidity conversion and serial print output for SHT31
Humidity conversion, CRC-failure placeholder and serial Print statements.

Corrected humidity CRC, conversion and serial output

HUMIDITY CRC, CONVERSION AND OUTPUT — CORRECTED
Crc = &HFF
For I = 4 To 5
  Crc = Crc Xor Ar(i)
  For Rep = 1 To 8
    Anded = Crc And &H80
    If Anded <> 0 Then
      Shift Crc , Left , 1
      Crc = Crc Xor &H31
    Else
      Shift Crc , Left , 1
    End If
  Next Rep
Next I

If Crc = Ar(6) Then
  Calc = Makeint(ar(5) , Ar(4))
  Feuchte = Calc * 100
  Feuchte = Feuchte / 65535
  Str_rel = Fusing(feuchte , "#.#")
  Str_rel = Str_rel + " % "
Else
  Str_rel = "--- % "
End If

Print Str_temp ; " | " ; Str_rel
Print

Loop
End

The supplied OLED image shows 18.4 °C and 50.9% RH in the depicted setup. However, the BASCOM source presented here only prints sensor data over serial; it does not implement OLED drawing. The image should not be treated as proof that this exact corrected BASCOM listing was compiled and tested on the photographed hardware.

Auditable read flow (code-level review)

Initialize TWI → send 0x24 0x00 → wait → read six bytes → recalculate and check the temperature CRC → convert temperature → reset and recalculate the humidity CRC → convert humidity → print values or placeholders → repeat. Bench compilation and electrical ACK/error checks remain necessary before production use.

Complete corrected SHT31 BASCOM-AVR example

This single copyable listing combines the code blocks above. It targets the ATmega328P at 16 MHz, uses the original 400 kHz TWI setup and fixes the missing humidity CRC calculation. Code-review example: it has not been compiled in a BASCOM-AVR IDE or independently run on the pictured bench. For a deployed instrument, add explicit address ACK/read-failure handling, recovery and logging rather than relying on CRC alone.

Show the complete BASCOM source (with separate CRC for both measurements)
FULL BASCOM-AVR LISTING — REVIEW BEFORE DEPLOYMENT
$regfile = "m328pdef.dat"
$crystal = 16000000
$baud = 9600

$lib "i2c_twi.lbx"
Config Scl = PORTC.5
Config Sda = PORTC.4
Config Twi = 400000
I2cinit

Dim Temperatur As Single , Str_temp As String * 10
Dim Feuchte As Single , Str_rel As String * 10
Dim Ar(10) As Byte
Dim Calc As Word
Dim I As Integer
Dim Crc As Byte
Dim Anded As Byte
Dim Rep As Byte

Do
  Str_temp = ""
  Str_rel = ""

I2cstart
I2cwbyte &H88
I2cwbyte &H24
I2cwbyte &H00
I2cstop

Wait 1

I2cstart
I2cwbyte &H89
I2crbyte Ar(1) , Ack
I2crbyte Ar(2) , Ack
I2crbyte Ar(3) , Ack
I2crbyte Ar(4) , Ack
I2crbyte Ar(5) , Ack
I2crbyte Ar(6) , Nack
I2cstop

Crc = &HFF
For I = 1 To 2
  Crc = Crc Xor Ar(i)
  For Rep = 1 To 8
    Anded = Crc And &H80
    If Anded <> 0 Then
      Shift Crc , Left , 1
      Crc = Crc Xor &H31
    Else
      Shift Crc , Left , 1
    End If
  Next Rep
Next I

If Crc = Ar(3) Then
  Calc = Makeint(ar(2) , Ar(1))
  Temperatur = Calc * 175
  Temperatur = Temperatur / 65535
  Temperatur = Temperatur - 45
  Str_temp = Fusing(temperatur , "#.#")
  Str_temp = Str_temp + " C "
Else
  Str_temp = "--- C "
End If

Crc = &HFF
For I = 4 To 5
  Crc = Crc Xor Ar(i)
  For Rep = 1 To 8
    Anded = Crc And &H80
    If Anded <> 0 Then
      Shift Crc , Left , 1
      Crc = Crc Xor &H31
    Else
      Shift Crc , Left , 1
    End If
  Next Rep
Next I

If Crc = Ar(6) Then
  Calc = Makeint(ar(5) , Ar(4))
  Feuchte = Calc * 100
  Feuchte = Feuchte / 65535
  Str_rel = Fusing(feuchte , "#.#")
  Str_rel = Str_rel + " % "
Else
  Str_rel = "--- % "
End If

Print Str_temp ; " | " ; Str_rel
Print

Loop
End

SHT31 I²C NACK, invalid readings and CRC-8 troubleshooting

Check the failure at the earliest observable stage. An address NACK, a measurement-not-ready NACK, a corrupted data frame and a wrong conversion are different faults and should not be diagnosed with the same fix.

Read failures and concrete checks for the ATmega328P example
SymptomMost useful first checkAction
Sensor does not acknowledge 0x88/0x897-bit vs 8-bit address; ADDR level; supply and shared groundProbe for 0x44 or 0x45; use 0x8A/0x8B only for 7-bit 0x45, and confirm SDA/SCL pull-ups
Read header is NACK after 0x2400Conversion may still be running; this command disables clock stretchingWait for the high-repeatability maximum conversion time plus design margin, or retry after a clean STOP
Temperature CRC passes but humidity CRC failsCRC was not reset; wrong byte indexes; missing receive byteSet Crc = 0xFF and process Ar(4) and Ar(5), comparing against Ar(6)
Both CRC checks fail intermittentlyRise time, pull-ups, bus speed, wire length or noisy powerInspect SDA/SCL on a scope and retry at 100 kHz for diagnosis; evaluate bus capacitance and voltage levels
CRC passes but units or values look wrongUnsigned MSB/LSB assembly and arithmeticUse Makeint(LSB, MSB); validate -45 + 175 × raw / 65535 and 100 × raw / 65535
CRC cannot replace I²C error handling

The demonstration loop has no explicit check of command/address acknowledgement. If a write NACKs or a read fails, do not assume six valid sensor bytes were delivered. Production firmware should check bus status, reject failed transactions, bound retries and log the failure; compare against real hardware behavior before release.

What makes this implementation useful

The value of the example is not a large software framework. It keeps every boundary where a sensor reading can fail separate and inspectable: command transfer, conversion delay, data length, byte order, CRC, numeric conversion and output formatting.

  • The frame layout is explicit. Temperature and humidity each have their own data pair and CRC byte, which must be calculated and checked separately.
  • Integrity is checked before calculation. On a successful six-byte transfer, CRC-mismatched raw words are rejected instead of being converted into realistic-looking numbers.
  • CRC failure is visible. --- C and --- % distinguish checksum failures from valid zeroes; I²C transaction failures still need separate handling.
  • The formulas are traceable. The displayed number can be followed back to the exact 16-bit word used in the calculation.

For a drying cabinet or another environmental monitor, that traceability matters more than merely producing two numeric readings. It gives the developer a clear place to test the bus, received data, CRC and conversion independently.

Frequently asked BASCOM-AVR and SHT31 questions

How many bytes does the SHT31 read return?

Six. The order is temperature MSB, temperature LSB, temperature CRC, humidity MSB, humidity LSB and humidity CRC.

Why is the final byte read with NACK?

The code ACKs the first five bytes because more data are expected. It reads the sixth byte with NACK to mark the end of the fixed-length transfer, then stops the I²C transaction.

What CRC values does the code use?

For each two-byte measurement word, initialize 0xFF, use polynomial 0x31 without reflection or final XOR, and compare the result to its associated CRC byte. The datasheet test bytes 0xBE 0xEF must yield 0x92.

What does the SHT31 0x2400 command select?

Single-shot high-repeatability conversion without clock stretching. The SHT3x-DIS datasheet gives 12.5 ms typical and 15.5 ms maximum conversion time for high repeatability; a read attempted too early can receive a NACK.

Is SHT31 I²C address 0x44 or 0x88?

0x44 is the 7-bit address when ADDR is low; 0x88 is its 8-bit write byte and 0x89 is its read byte. With ADDR high, the 7-bit address is 0x45, so BASCOM sends 0x8A and 0x8B.

Why does the program wait one second before reading?

The one-second delay provides a generous margin beyond the conversion time noted beside the command. It simplifies this test loop, although a time-sensitive application could choose a shorter delay after validating the sensor's timing requirements.

How are the two temperature bytes converted into one raw value?

Makeint(Ar(2), Ar(1)) combines the temperature LSB and MSB into a 16-bit word. Humidity uses the same pattern with Ar(5) and Ar(4).

Why are temperature and humidity checked separately?

Temperature occupies Ar(1:2) with checksum Ar(3); humidity occupies Ar(4:5) with checksum Ar(6). Reset and recalculate CRC between these words; otherwise the humidity result can be rejected incorrectly.

What happens when a CRC check fails?

The invalid raw value is not converted. The program outputs --- C for temperature or --- % for humidity, making a communication error distinguishable from a legitimate zero reading.

What I²C clock rate is configured?

Config Twi = 400000 sets the hardware TWI interface to 400 kHz. The SCL and SDA pins are assigned to PORTC.5 and PORTC.4.

Are OLED drawing routines included?

No. This BASCOM listing ends with serial Print and does not drive the OLED shown in the supplied image. Confirm the display/controller software separately.

What if SHT31 always returns NACK after a measurement?

First verify supply, the ADDR pin, 7-bit versus 8-bit addressing and SDA/SCL pull-ups. For 0x2400, a read NACK can also mean the non-clock-stretching conversion is not yet complete. See the troubleshooting table.

Implementation notes

The code examples focus on the sensor data path: TWI initialization, measurement command, six-byte read, independent CRC checks, conversion and serial output. The screenshots and displayed OLED result are provided as source illustrations; the corrected full program still requires BASCOM-AVR compilation and bench confirmation. OLED rendering is not included in the listing.

Technical claims for SHT31-DIS timing, the single-shot command, response byte order, CRC and conversion formulas follow the manufacturer datasheet (Tables 4, 9 and 20). Confirm the breakout-board wiring, source compiler options, component marking and firmware status behavior for your own hardware.

NYFEA FHT31 digital temperature and humidity sensor in an open-cavity DFN-8 package
NYFEA FHT31 digital temperature and humidity sensor for compact board-level environmental monitoring applications.

Evaluate FHT31 for Your Temperature and Humidity Application

For a production design, review the required humidity and temperature accuracy, I²C address, acquisition rate, airflow, thermal coupling, condensation risk, PCB layout and contamination controls. NYFEA FHT31 integrates calibrated digital sensing, CRC-protected I²C communication, dual address selection and control functions in a compact 2.5 mm × 2.5 mm DFN-8 package.

© 2023 All Rights Reserved. www.nyfea.com Terms of Use | Privacy Policy