STM32 software I2C reading AM2320 temperature and humidity sensor data

STM32 MCU reads AM2320 temperature and humidity sensor data via software I²C and displays it on a 0.96-inch OLED screen.

My board is STM32F103C8T6 and the code is written with the ST Standard Peripheral Library.

STM32 uses hardware I²C to read SHTC3 sensor: https://blog.zeruns.com/archives/692.html
STM32 reads AHT10 sensor data: https://blog.zeruns.com/archives/693.html

Electronics / MCU QQ group: 2169025065

Result Pictures

I²C Protocol Brief

The Inter-Integrated Circuit (I²C) protocol was developed by Philips. It needs few pins, is easy to implement in hardware, highly extensible, and does not require external transceivers like USART or CAN (level-shifters). It is now widely used for on-board communication among ICs.

I²C has only one data line SDA (Serial Data Line), so data must be sent bit by bit—serial, half-duplex.
Half-duplex: bidirectional but not simultaneous; direction must be switched. Only one data line is needed.

We divide I²C into the physical layer (hardware) and the protocol layer (software rules).

I²C Physical Layer

Typical I²C connection

  1. Multi-device bus: several devices share the same signal lines. One I²C bus can connect multiple masters and slaves.
  2. Two wires only: bidirectional SDA and serial clock SCL.
  3. Pull-up resistors to VCC. When idle, devices output high-impedance, so the resistors pull the bus high.

MCU GPIO must be configured as open-drain, otherwise a short-circuit may occur.

More STM32 I²C info: https://url.zeruns.com/JC0Ah — not detailed here.

AM2320 Temperature & Humidity Sensor

Introduction

AM2320 is a factory-calibrated digital sensor with excellent long-term stability. It combines a capacitive humidity element, a high-accuracy temperature element and a high-performance MCU. Features outstanding quality, ultra-fast response, strong anti-interference ability and high cost-performance. Supports both single-bus and standard I²C. Tiny size, ultra-low power, 20 m+ signal distance. Both interfaces output temperature-compensated humidity, temperature and CRC checksum; no extra calculation or compensation needed. 4-pin package, easy wiring.

Datasheet download: https://url.zeruns.com/74o6F



Key specs from the datasheet:

  • Temperature range: –40 °C ~ 80 °C
  • Temperature accuracy: ±0.5 °C
  • Humidity range: 0 % ~ 99.9 %
  • Humidity accuracy: ±3 %
  • Supply: 3.1 V ~ 5.5 V
  • Interface: I²C or single-bus
  • Clock ≤ 100 kHz

Device Address & R/W Command

The 7-bit address plus R/W bit form one byte.
To write: after START send 0xB8 (addr+W).
To read: after START send 0xB9 (addr+R).
In short: 0xB8 = write, 0xB9 = read.

Reading Temperature & Humidity




One read cycle has three steps:

  1. Wake sensor
  2. Send read command
  3. Read returned data

Summary:

  1. Wake: START + send 0xB8 + wait (>800 µs) + STOP
  2. Command: START + 0xB8 (SLA) + 0x03 (function) + 0x00 (start addr) + 0x04 (length) + STOP
  3. Receive: send read command (0xB9), read 8 bytes continuously:
    Length + Humidity_H + Humidity_L + Temp_H + Temp_L + CRC_L + CRC_H
  4. Convert the data.

Data Conversion

From the datasheet:


Example:
Humidity raw = 0x01F4 = 500 → 500 / 10 = 50.0 %
Temperature raw = 0x00FA = 250 → 250 / 10 = 25.0 °C

Required Parts

Code

Only main.c, AM2320.c and OLED.c are shown below; download the full project at the link.

Complete project: https://url.zeruns.com/AM2320

Wiring: AM2320 and OLED SCL → PB12, SDA → PB13.
If AM2320 uses other pins, add 5 kΩ pull-ups.

Using VS Code instead of Keil for STM32 & 51 development: https://blog.zeruns.com/archives/690.html

main.c```c

#include “stm32f10x.h” // Device header
#include “Delay.h”
#include “OLED.h”
#include “AM2320.h”
#include “IWDG.h”

int main(void)
{
IWDG_Configuration(); //Initialize watchdog
AM2320_I2C_Init();
OLED_Init();

OLED_ShowString(1, 1, "T:");
OLED_ShowString(2, 1, "H:");

uint16_t i = 0;
uint16_t err_count = 0;

while (1)
{
	OLED_ShowNum(4, 1, i, 5);
	float Temp, Hum; //Declare variables to store temperature and humidity data

	if (ReadAM2320(&Hum, &Temp)) //Read temperature and humidity data
	{
		if (Temp >= 0)
		{
			char String[10];
			sprintf(String, "+%.2fC", Temp); //Format string output to string variable
			OLED_ShowString(1, 3, String);	 //Display temperature

			sprintf(String, " %.2f%%", Hum); //Format string output to string variable
			OLED_ShowString(2, 3, String);	 //Display humidity
		}
		else
		{
			char String[10];
			sprintf(String, "-%.2fC", Temp); //Format string output to string variable
			OLED_ShowString(1, 3, String);	 //Display temperature

			sprintf(String, " %.2f%%", Hum); //Format string output to string variable
			OLED_ShowString(2, 3, String);	 //Display humidity
		}
	}
	else
	{
		err_count++;
		OLED_ShowNum(3, 1, err_count, 5); //Display error count
	}
	Delay_ms(100);
	i++;
	if (i >= 99999)
		i = 0;
	if (err_count >= 99999)
		err_count = 0;
	IWDG_FeedDog(); //Feed the dog (watchdog, auto-reset if not fed within 1 second)
}
// blog.zeruns.com

}


### AM2320.c

```c
#include "stm32f10x.h"
#include "Delay.h"
#include "OLED.h"

/*
Author blog: https://blog.zeruns.com
WeChat public account: zeruns-gzh
Bilibili homepage: https://space.bilibili.com/8320520
*/

/*AM2320 address*/
#define AM2320_ADDRESS 0xB8

/*Pin configuration*/
#define AM2320_SCL GPIO_Pin_12
#define AM2320_SDA GPIO_Pin_13
#define AM2320_W_SCL(x) GPIO_WriteBit(GPIOB, AM2320_SCL, (BitAction)(x))
#define AM2320_W_SDA(x) GPIO_WriteBit(GPIOB, AM2320_SDA, (BitAction)(x))
#define AM2320_R_SDA() GPIO_ReadInputDataBit(GPIOB, AM2320_SDA)
#define AM2320_R_SCL() GPIO_ReadInputDataBit(GPIOB, AM2320_SCL)
/*When STM32 GPIO is configured as open-drain output mode, it can still read
the input data register of the GPIO to get the external input level of the pin, meaning it also has the function of floating input mode*/

/**
 * @brief  CRC checksum calculation
 * @param  *ptr Byte data to be calculated (stored as array variable)
 * @param  len  Number of bytes to be calculated (array length)
 * @retval CRC checksum
 */
unsigned short CRC16(unsigned char *ptr, unsigned char len)
{
	unsigned short crc = 0xFFFF;
	unsigned char i;
	while (len--)
	{
		crc ^= *ptr++;
		for (i = 0; i < 8; i++)
		{
			if (crc & 0x01)
			{
				crc >>= 1;
				crc ^= 0xA001;
			}
			else
			{
				crc >>= 1;
			}
		}
	}
	return crc;
}

/**
 * @brief  I2C start
 * @param  None
 * @retval None
 */
void AM2320_I2C_Start(void)
{
	AM2320_W_SDA(1);
	Delay_us(2); //Delay 2 microseconds
	AM2320_W_SCL(1);
	Delay_us(4);
	AM2320_W_SDA(0);
	Delay_us(3);
	AM2320_W_SCL(0);
	Delay_us(5);
}

/**
 * @brief  I2C stop
 * @param  None
 * @retval None
 */
void AM2320_I2C_Stop(void)
{
	AM2320_W_SDA(0);
	Delay_us(3);
	AM2320_W_SCL(1);
	Delay_us(4);
	AM2320_W_SDA(1);
	Delay_us(4);
}

/**
 * @brief  I2C send one byte
 * @param  Byte One byte to be sent
 * @retval None
 */
void AM2320_I2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		AM2320_W_SDA((Byte << i) & 0x80);
		AM2320_W_SCL(1);
		Delay_us(4);
		AM2320_W_SCL(0);
		Delay_us(5);
	}
	AM2320_W_SDA(1); //Release SDA bus
}

/**
 * @brief  Wait for acknowledge signal
 * @param  None
 * @retval 1-NACK, 0-ACK
 */
uint8_t WaitAck(void)
{
	uint8_t ret;

	AM2320_W_SCL(1);
	Delay_us(4);
	if (AM2320_R_SDA())
	{
		ret = 1;
	}
	else
	{
		ret = 0;
	}
	AM2320_W_SCL(0);
	Delay_us(5);
	return ret;
}

/**
 * @brief  I2C read one byte
 * @param  NACK 1-NACK, 0-ACK
 * @retval Byte data read
 */
uint8_t AM2320_I2C_ReadByte(uint8_t NACK)
{
	uint8_t i, Byte = 0;
	AM2320_W_SDA(1); //Release SDA bus
	for (i = 0; i < 8; i++)
	{
		AM2320_W_SCL(1);
		Delay_us(4);
		Byte = Byte | (AM2320_R_SDA() << (7 - i));
		AM2320_W_SCL(0);
		Delay_us(5);
	}
	AM2320_W_SDA(NACK); //Send ACK/NACK signal
	AM2320_W_SCL(1);
	Delay_us(4);
	AM2320_W_SCL(0);
	Delay_us(5);
	AM2320_W_SDA(1); //Release SDA bus
	return Byte;
}

/*Wake up sensor*/
void AM2320_Wake(void)
{
	AM2320_I2C_Start();
	AM2320_I2C_SendByte(AM2320_ADDRESS);
	WaitAck();
	Delay_us(1000); //Delay 1000 microseconds
	AM2320_I2C_Stop();
}

/*Pin initialization*/
void AM2320_I2C_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //Enable GPIOB clock

	GPIO_InitTypeDef GPIO_InitStructure;		 //Define structure to configure GPIO
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //Open-drain output mode
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = AM2320_SCL;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = AM2320_SDA;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	AM2320_W_SCL(1);
	AM2320_W_SDA(1);
	AM2320_Wake(); //Wake up sensor
}

/**
 * @brief  Read AM2320 data
 * @param  *Hum Humidity
 * @param  *Temp Temperature
 * @retval 1 - Read success; 0 - Read failure
 */
uint8_t ReadAM2320(float *Hum, float *Temp)
{
	uint8_t Data[8];

	AM2320_I2C_Start(); //Send start signal
	AM2320_I2C_SendByte(AM2320_ADDRESS);
	if (WaitAck()) //Check ACK signal
	{
		AM2320_I2C_Stop(); //Send stop signal
		Delay_us(50);
		//Try reading again
		AM2320_I2C_Start(); //Send start signal
		AM2320_I2C_SendByte(AM2320_ADDRESS);
		if (WaitAck()) //Check ACK signal
		{
			Delay_us(20);
			AM2320_I2C_Stop(); //Send stop signal
			return 0;
		}
		else
		{
			Delay_us(20);//AM2320 will inexplicably pull SCL low for a while causing data transmission errors, so delay 20 microseconds to wait for AM2320 to release SCL before continuing
			AM2320_I2C_SendByte(0x03); //Send function code
			WaitAck();				   //Wait for ACK signal
			AM2320_I2C_SendByte(0x00); //Send register start address to read
			WaitAck();				   //Wait for ACK signal
			AM2320_I2C_SendByte(0x04); //Send register length to read
			WaitAck();				   //Wait for ACK signal
			Delay_us(20);//AM2320 will inexplicably pull SCL low for a while causing stop signal transmission failure, so delay 20 microseconds to wait for AM2320 to release SCL before continuing
			AM2320_I2C_Stop();		   //Send stop signal
		}
	}
	else
	{
		Delay_us(20);//AM2320 will inexplicably pull SCL low for a while causing data transmission errors, so delay 20 microseconds to wait for AM2320 to release SCL before continuing
		AM2320_I2C_SendByte(0x03); //Send function code
		WaitAck();				   //Wait for ACK signal
		AM2320_I2C_SendByte(0x00); //Send register start address to read
		WaitAck();				   //Wait for ACK signal
		AM2320_I2C_SendByte(0x04); //Send register length to read
		WaitAck();				   //Wait for ACK signal
		Delay_us(20);//AM2320 will inexplicably pull SCL low for a while causing stop signal transmission failure, so delay 20 microseconds to wait for AM2320 to release SCL before continuing
		AM2320_I2C_Stop();		   //Send stop signal
	}

	Delay_ms(2); //Delay 2 milliseconds

	AM2320_I2C_Start();
	AM2320_I2C_SendByte(AM2320_ADDRESS | 0x01); //Send read command
	WaitAck();
	Delay_us(35);
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		if (i != 7)
		{
			Data[i] = AM2320_I2C_ReadByte(0);
		}
		else
		{
			Data[i] = AM2320_I2C_ReadByte(1); //Send NACK when reading last byte
		}
	}
	AM2320_I2C_Stop();

	if (CRC16(Data, 6) == (Data[6] | (Data[7] << 8))) //Verify data
	{
		*Hum = ((((uint16_t)Data[2]) << 8) | Data[3]) / 10.0; //Calculate humidity data
		if (Data[4] >> 7)									  //Check if temperature value is negative
		{
			*Temp = ((((uint16_t)(Data[4] && 0x7F) << 8)) | Data[5]) / -10.0; //Calculate negative temperature
		}
		else
		{
			*Temp = ((((uint16_t)Data[4]) << 8) | Data[5]) / 10.0; //Calculate positive temperature
		}
		return 1;
	}
	return 0;
}
```### OLED.c

```c
#include "stm32f10x.h"
#include "OLED_Font.h"

/*Pin configuration*/
#define OLED_SCL GPIO_Pin_12
#define OLED_SDA GPIO_Pin_13
#define OLED_W_SCL(x) GPIO_WriteBit(GPIOB, OLED_SCL, (BitAction)(x))
#define OLED_W_SDA(x) GPIO_WriteBit(GPIOB, OLED_SDA, (BitAction)(x))

/*Pin initialization*/
void OLED_I2C_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Pin = OLED_SCL;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = OLED_SDA;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
 * @brief  I2C start
 * @param  None
 * @retval None
 */
void OLED_I2C_Start(void)
{
	OLED_W_SDA(1);
	OLED_W_SCL(1);
	OLED_W_SDA(0);
	OLED_W_SCL(0);
}

/**
 * @brief  I2C stop
 * @param  None
 * @retval None
 */
void OLED_I2C_Stop(void)
{
	OLED_W_SDA(0);
	OLED_W_SCL(1);
	OLED_W_SDA(1);
}

/**
 * @brief  I2C send one byte
 * @param  Byte byte to send
 * @retval None
 */
void OLED_I2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_W_SDA(Byte & (0x80 >> i));
		OLED_W_SCL(1);
		OLED_W_SCL(0);
	}
	OLED_W_SDA(1); //Release SDA bus
	OLED_W_SCL(1); //Extra clock, ignore ACK
	OLED_W_SCL(0);
}

/**
 * @brief  OLED write command
 * @param  Command command to write
 * @retval None
 */
void OLED_WriteCommand(uint8_t Command)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78); //Slave address
	OLED_I2C_SendByte(0x00); //Write command
	OLED_I2C_SendByte(Command);
	OLED_I2C_Stop();
}

/**
 * @brief  OLED write data
 * @param  Data data to write
 * @retval None
 */
void OLED_WriteData(uint8_t Data)
{
	OLED_I2C_Start();
	OLED_I2C_SendByte(0x78); //Slave address
	OLED_I2C_SendByte(0x40); //Write data
	OLED_I2C_SendByte(Data);
	OLED_I2C_Stop();
}

/**
 * @brief  OLED set cursor position
 * @param  Y coordinate from top-left, range: 0~7
 * @param  X coordinate from top-left, range: 0~127
 * @retval None
 */
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
	OLED_WriteCommand(0xB0 | Y);			 //Set Y position
	OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //Set X low nibble
	OLED_WriteCommand(0x00 | (X & 0x0F));		 //Set X high nibble
}

/**
 * @brief  OLED clear screen
 * @param  None
 * @retval None
 */
void OLED_Clear(void)
{
	uint8_t i, j;
	for (j = 0; j < 8; j++)
	{
		OLED_SetCursor(j, 0);
		for (i = 0; i < 128; i++)
		{
			OLED_WriteData(0x00);
		}
	}
}

/**
 * @brief  OLED partial clear
 * @param  Line row position, range: 1~4
 * @param  start column start position, range: 1~16
 * @param  end column end position, range: 1~16
 * @retval None
 */
void OLED_Clear_Part(uint8_t Line, uint8_t start, uint8_t end)
{
	uint8_t i, Column;
	for (Column = start; Column <= end; Column++)
	{
		OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //Set cursor to upper half
		for (i = 0; i < 8; i++)
		{
			OLED_WriteData(0x00); //Clear upper half
		}
		OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //Set cursor to lower half
		for (i = 0; i < 8; i++)
		{
			OLED_WriteData(0x00); //Clear lower half
		}
	}
}

/**
 * @brief  OLED show one character
 * @param  Line row position, range: 1~4
 * @param  Column column position, range: 1~16
 * @param  Char character to display, range: ASCII visible characters
 * @retval None
 */
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //Set cursor to upper half
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i]); //Display upper half
	}
	OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //Set cursor to lower half
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //Display lower half
	}
}

/**
 * @brief  OLED show string
 * @param  Line starting row, range: 1~4
 * @param  Column starting column, range: 1~16
 * @param  String string to display, range: ASCII visible characters
 * @retval None
 */
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i++)
	{
		OLED_ShowChar(Line, Column + i, String[i]);
	}
}

/**
 * @brief  OLED power function
 * @retval returns X to the power of Y
 */
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;
	while (Y--)
	{
		Result *= X;
	}
	return Result;
}

/**
 * @brief  OLED display number (decimal, positive)
 * @param  Line starting row, range: 1~4
 * @param  Column starting column, range: 1~16
 * @param  Number number to display, range: 0~4294967295
 * @param  Length length of number to display, range: 1~10
 * @retval None
 */
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
 * @brief  OLED display number (decimal, signed)
 * @param  Line starting row, range: 1~4
 * @param  Column starting column, range: 1~16
 * @param  Number number to display, range: -2147483648~2147483647
 * @param  Length length of number to display, range: 1~10
 * @retval None
 */
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
	uint8_t i;
	uint32_t Number1;
	if (Number >= 0)
	{
		OLED_ShowChar(Line, Column, '+');
		Number1 = Number;
	}
	else
	{
		OLED_ShowChar(Line, Column, '-');
		Number1 = -Number;
	}
	for (i = 0; i < Length; i++)
	{
		OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
	}
}

/**
 * @brief  OLED display number (hexadecimal, positive)
 * @param  Line starting row, range: 1~4
 * @param  Column starting column, range: 1~16
 * @param  Number number to display, range: 0~0xFFFFFFFF
 * @param  Length length of number to display, range: 1~8
 * @retval None
 */
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i, SingleNumber;
	for (i = 0; i < Length; i++)
	{
		SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
		if (SingleNumber < 10)
		{
			OLED_ShowChar(Line, Column + i, SingleNumber + '0');
		}
		else
		{
			OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
		}
	}
}

/**
 * @brief  OLED display number (binary, positive)
 * @param  Line starting row, range: 1~4
 * @param  Column starting column, range: 1~16
 * @param  Number number to display, range: 0~1111 1111 1111 1111
 * @param  Length length of number to display, range: 1~16
 * @retval None
 */
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)
	{
		OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
	}
}

/**
 * @brief  OLED initialization
 * @param  None
 * @retval None
 */
void OLED_Init(void)
{
	uint32_t i, j;

	for (i = 0; i < 1000; i++) //Power-on delay
	{
		for (j = 0; j < 1000; j++)
			;
	}

	OLED_I2C_Init(); //Port initialization

	OLED_WriteCommand(0xAE); //Display off

	OLED_WriteCommand(0xD5); //Set display clock divide ratio/oscillator frequency
	OLED_WriteCommand(0x80);

	OLED_WriteCommand(0xA8); //Set multiplex ratio
	OLED_WriteCommand(0x3F);

	OLED_WriteCommand(0xD3); //Set display offset
	OLED_WriteCommand(0x00);

	OLED_WriteCommand(0x40); //Set display start line

	OLED_WriteCommand(0xA1); //Set segment re-map, 0xA1 normal 0xA0 reversed

	OLED_WriteCommand(0xC8); //Set COM output scan direction, 0xC8 normal 0xC0 reversed

	OLED_WriteCommand(0xDA); //Set COM pins hardware configuration
	OLED_WriteCommand(0x12);

	OLED_WriteCommand(0x81); //Set contrast control
	OLED_WriteCommand(0xCF);

	OLED_WriteCommand(0xD9); //Set pre-charge period
	OLED_WriteCommand(0xF1);

	OLED_WriteCommand(0xDB); //Set VCOMH deselect level
	OLED_WriteCommand(0x30);

	OLED_WriteCommand(0xA4); //Set entire display on/off

	OLED_WriteCommand(0xA6); //Set normal/inverse display

	OLED_WriteCommand(0x8D); //Set charge pump
	OLED_WriteCommand(0x14);

	OLED_WriteCommand(0xAF); //Display on

	OLED_Clear(); // OLED clear screen
}

Timing Diagram

Actual AM2320 timing diagram for sending commands and reading data.

Recommended Reading

1 Like