STM32 microcontroller reads AHT10 temperature and humidity sensor data

Using STM32 Hardware I2C to Read AHT10 Temperature and Humidity Sensor Data and Display on 0.96-inch OLED Screen.

The MCU I use is STM32F103C8T6, and the program is written with the ST Standard Peripheral Library.

STM32 uses hardware I2C to read SHTC3 temperature and humidity sensor: https://blog.zeruns.com/archives/692.html

Electronics/MCU Technical Group: 2169025065

Implementation Effect Pictures


Brief Introduction to I2C Protocol

The I2C communication protocol (Inter-Integrated Circuit) was developed by Philips. Thanks to its few pins, simple hardware implementation, strong extensibility, and no need for external transceiver devices like USART or CAN (those level-shifting chips), it is now widely used for communication among multiple ICs within a system.

I2C has only one data bus line, SDA (Serial Data Line), a serial data bus that can only send data bit by bit, belonging to serial communication and using half-duplex communication.

Half-duplex communication: bidirectional communication is possible, but not simultaneously in both directions; it must alternate. It can also be understood as a switchable single-direction communication. At the same moment only one direction is allowed, requiring just one data line.

We divide the I2C protocol into the physical layer and the protocol layer. The physical layer specifies the mechanical and electronic characteristics of the communication system (hardware part), ensuring raw data transmission over the physical medium. The protocol layer mainly defines communication logic, unifying data packaging and unpacking standards for both sender and receiver (software level).

I2C Physical Layer

Common Connection Between I2C Devices

(1) It is a multi-device bus. “Bus” means signal lines shared by multiple devices. In one I2C bus, multiple I2C devices can be connected, supporting multiple masters and multiple slaves.

(2) An I2C bus uses only two lines: one bidirectional serial data line SDA (Serial Data Line), and one serial clock line SCL (Serial Clock Line). The data line represents data, and the clock line synchronizes data transmission.

(3) The bus is pulled up to the supply voltage through pull-up resistors. When an I2C device is idle it outputs high-impedance, and when all devices are idle and output high-impedance, the pull-up resistors pull the bus high.

During I2C communication, the MCU GPIO pins must be configured as open-drain outputs; otherwise a short circuit may occur.

For more STM32 I2C information and usage, see this article: https://url.zeruns.com/JC0Ah

I won’t go into detail here.

AHT10 Temperature and Humidity Sensor

Introduction

AHT10 is a domestic temperature and humidity sensor chip, cheap, accurate, and small.

AHT10 features a newly designed ASIC, an improved MEMS semiconductor capacitive humidity element, and a standard on-chip temperature element. Its performance has greatly surpassed the reliability of previous sensors. The new generation sensor is improved for more stable performance in harsh environments.

AHT10 datasheet download: https://url.zeruns.com/EDEwF


From the datasheet we can get a rough idea:

  • Temperature range: –40 °C ~ 85 °C
  • Temperature accuracy: ±0.3 °C
  • Humidity range: 0 % ~ 100 %
  • Humidity accuracy: ±2 %
  • Operating voltage: 1.8 V ~ 3.6 V
  • Communication: I2C
  • Clock frequency: 100 kHz and 400 kHz

Find the following key information

Temperature and Humidity Device Address and Read/Write Commands

In actual use, the AHT10 device address must be combined with the read/write direction bit into one byte sent together. The LSB is the read/write direction bit, and the upper 7 bits are the AHT10 device address.

To write data or commands to AHT10 via I2C, after the I2C start condition, send “0111 0000”, i.e. 0x70, to AHT10. The upper 7 bits “0111 000” address the device, and the LSB “0” tells AHT10 that the next operation is write.

To read data from AHT10 via I2C, after the I2C start condition, send “0111 0001”, i.e. 0x71, to AHT10. The upper 7 bits address the device, and the LSB “1” tells AHT10 that the next operation is read.

In short, 0x70 means write, 0x71 means read. However, when using STM32 hardware I2C, just enter 0x70; the LSB is handled by the standard library.

Reading Temperature and Humidity Data


From the datasheet, one measurement cycle includes three steps:

  1. Send measurement command
  2. Wait for measurement to complete
  3. Read measured data

Summary:

  1. Send measurement command: first send write command (0x70), then send trigger measurement command (0xAC), then send command parameters (0x33 and 0x00).
  2. Wait for measurement to complete: datasheet says 75 ms; wait longer than this.
  3. Receive data: send read command (0x71), continuously receive 6 bytes. The first received byte is the status byte. Check if bit 3 (calibration enable) is 1; if not, send initialization command. Check bit 7 (busy flag); if 0, measurement is complete, proceed.
  4. Convert and process the received data.

Data Calculation

From the AHT10 datasheet:

Example: collected humidity value is 0x0C6501, decimal 812289.
Then: humidity = 812289 × 100 / 1048576 = 77.46 (unit: %)
Collected temperature value is 0x056A00, decimal 354816.
Then: temperature = (354816 × 200 / 1048576) – 50 = 17.67 (unit: °C)

Required Components

STM32 minimum system board: https://s.click.taobao.com/bqMwZRu
AHT10 module: https://s.click.taobao.com/gIF09Ru
OLED module: https://s.click.taobao.com/aNlvZRu
Dupont wires: https://s.click.taobao.com/xAkAJRu
Breadboard: https://s.click.taobao.com/ShJAJRu
ST-LINK V2: https://s.click.taobao.com/C8ftZRu

Program

Here I only post the three main code files: main.c, AHT10.c and OLED.c. For the rest, please download the zip package below.

Complete project files: https://url.zeruns.com/AHT10

For AHT10 and OLED modules, connect SCL to PB6 and SDA to PB7.

Using VSCode instead of Keil for STM32 and 51 development: https://blog.zeruns.com/archives/690.html

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "IWDG.h"
#include "AHT10.h"


uint16_t numlen(uint16_t num);

int main(void)
{
	IWDG_Configuration();	// Initialize watchdog
	OLED_Init();			// Initialize OLED screen
	AHT10_Init();			// Initialize AHT10
	
	OLED_ShowString(1, 1, "T:");
	OLED_ShowString(2, 1, "H:");

	uint32_t a=0;
	uint16_t err_count=0;
	
	while (1)
	{
		a++;
		OLED_ShowNum(3, 1, a, 9); // Counter display, easy to see if program is running
		if(a==999999999)a=0;

		float Temp,Hum;			// Declare variables for temperature and humidity data
	
	/*
	https://blog.zeruns.com
	*/

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

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

		Delay_ms(100);	// Delay 100 ms

		IWDG_FeedDog();	// Feed the dog (watchdog, auto-reset if not fed within 1 second)
	}
}
```**AHT10.c**

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

/*AHT10 Address*/
#define AHT10_ADDRESS 0x38<<1 //The slave address is 7-bit, the last bit is the transfer direction bit, so shift left by 1

/*Set which I2C to use*/
#define I2Cx I2C1

/*
https://blog.zeruns.com
*/

/*Send start signal*/
void AHT10_I2C_START(){
    while( I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));//Wait for bus idle
	I2C_GenerateSTART(I2Cx, ENABLE);//Send start signal
	while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);//Check EV5 event
}

/*Send stop signal*/
void AHT10_I2C_STOP(){
    I2C_GenerateSTOP(I2Cx, ENABLE);//Send stop signal
}

/**
  * @brief  Send 3 bytes of data
  * @param  cmd Command byte
  * @param  DATA0 First parameter
  * @param  DATA1 Second parameter
  * @retval None
  */
void AHT10_WriteByte(uint8_t cmd, uint8_t DATA0, uint8_t DATA1)
{
	AHT10_I2C_START();  //Send start signal
	
	I2C_Send7bitAddress(I2Cx, AHT10_ADDRESS, I2C_Direction_Transmitter);    //Send device write address
	while(I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);  //Check EV6 event

    I2C_SendData(I2Cx, cmd);//Send command
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Check EV8 event

    I2C_SendData(I2Cx, DATA0);//Send high 8-bit data of command parameter
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Check EV8 event
   
	I2C_SendData(I2Cx, DATA1);//Send low 8-bit data of command parameter
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Check EV8 event
	
	I2C_GenerateSTOP(I2Cx, ENABLE);//Send stop signal	
}

/**
  * @brief  Send command to read AHT10 status
  * @retval Read status byte
  */
/*uint8_t AHT10_ReadStatus(void){
    AHT10_I2C_START();//Send start signal  
	I2C_Send7bitAddress(I2Cx,AHT10_ADDRESS,I2C_Direction_Receiver);//Send device read address
	while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR);//Check EV6 event
    while (!I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED));//Check EV7 event
	I2C_AcknowledgeConfig(I2Cx, DISABLE); //Disable acknowledge signal
	uint8_t status = I2C_ReceiveData(I2Cx);//Read data and return
	AHT10_I2C_STOP();   //Send stop signal
	I2C_AcknowledgeConfig(I2Cx,ENABLE);//Re-enable acknowledge signal
	return status;
}*/

/**
  * @brief  Read data
  * @retval Read byte data
  */
uint8_t AHT10_ReadData(void)
{
    while (!I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED));//Check EV7 event
	return I2C_ReceiveData(I2Cx);//Read data and return
}

/*Software reset AHT10*/
void AHT10_SoftReset(void)                    
{
    AHT10_I2C_START();  //Send start signal
	I2C_Send7bitAddress(I2Cx, AHT10_ADDRESS, I2C_Direction_Transmitter);    //Send device write address
	while(I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);  //Check EV6 event
    I2C_SendData(I2Cx, 0xBA);//Send soft reset command
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Check EV8 event
    I2C_GenerateSTOP(I2Cx, ENABLE);//Send stop signal
	Delay_ms(20);
}

/*Pin initialization*/
void AHT10_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);	//Enable I2C1 clock
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//Enable GPIOB clock
 
	/*STM32F103 chip hardware I2C1: PB6 -- SCL; PB7 -- SDA */
	GPIO_InitTypeDef  GPIO_InitStructure;               //Define structure to configure GPIO
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;		//Set output mode to open-drain output, pull-up resistor required
	GPIO_Init(GPIOB, &GPIO_InitStructure);              //Initialize GPIO
	
	I2C_DeInit(I2Cx);	//Reset I2C peripheral registers to default values
	I2C_InitTypeDef  I2C_InitStructure;                 //Define structure to configure I2C
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;			//Operating mode
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	//Clock duty cycle, Tlow/Thigh = 2
	I2C_InitStructure.I2C_OwnAddress1 = 0x88;	//Host I2C address, write randomly if not used, no effect
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;	//Enable acknowledge bit
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//Set address length to 7 bits
	I2C_InitStructure.I2C_ClockSpeed = 400000;	//I2C transfer speed, 400K, check chip datasheet for supported speed.
	I2C_Init(I2Cx, &I2C_InitStructure);         //Initialize I2C

	I2C_Cmd(I2Cx, ENABLE);  //Enable I2C
	Delay_ms(20);//Power-on delay
	AHT10_WriteByte(0XE1,0X08,0x00);//Send command to initialize
	Delay_ms(20);

}

/**
  * @brief  Read AHT10 data
  * @param  *Hum Humidity
  * @param  *Temp Temperature
  * @retval 1 - Read success; 0 - Read failure
  */
uint8_t ReadAHT10(float *Hum,float *Temp)
{
    uint8_t Data[5];//Declare variable to store read data

	AHT10_WriteByte(0XAC,0X33,0x00);//Send command to trigger measurement

	Delay_ms(70);	//Delay 70ms for measurement completion

    AHT10_I2C_START();//Send start signal  
	I2C_Send7bitAddress(I2Cx,AHT10_ADDRESS,I2C_Direction_Receiver);//Send device read address
	while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR);//Check EV6 event
	
	uint8_t i;
	for(i=0;i<6;i++)//Loop 6 times to read 6 bytes of data
	{
		if (i == 5)	//Disable acknowledge signal when reading the last byte
		{
			I2C_AcknowledgeConfig(I2Cx, DISABLE); //Disable acknowledge signal
		}
		Data[i] = AHT10_ReadData();	//Read data
		if (i == 5)
			I2C_GenerateSTOP(I2Cx, ENABLE); //Send stop signal
	}
	I2C_AcknowledgeConfig(I2Cx,ENABLE);//Re-enable acknowledge signal

	if( (Data[0]&0x08) == 0 )//0x08(00001000) Check if bit 3 of status byte (calibration enable bit) is 0
	{
		AHT10_WriteByte(0XE1,0X08,0x00);	//Send command to initialize
		Delay_ms(20);
		return 0;
	}
	else if( (Data[0]&0x80) == 0 )//0x80(10000000) Check if bit 7 of status byte (busy flag) is 0
	{
		
		uint32_t SRH = (Data[1]<<12) | (Data[2]<<4) | (Data[3]>>4);	//Humidity data processing
		uint32_t ST = ((Data[3]&0x0f)<<16) | (Data[4]<<8) | Data[5];//Temperature data processing

		*Hum = (SRH * 100.0) / 1024.0 / 1024;	   //Convert humidity data according to formula in datasheet
		*Temp = (ST * 200.0) / 1024.0 / 1024 - 50; //Convert temperature data according to formula in datasheet

		return 1;
	}

	I2C_GenerateSTOP(I2Cx, ENABLE);//Send stop signal
	return 0;	

}

/*
https://blog.zeruns.com
*/
```**OLED.c**

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

/*OLED screen address*/
#define OLED_ADDRESS 0x78

/*Which I2C to use*/
#define I2Cx I2C1

/*
https://blog.zeruns.com
*/

/*Pin initialization*/
void OLED_I2C_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);	//Enable I2C1 clock
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//Enable GPIOB clock
 
	/*STM32F103 hardware I2C: PB6 -- SCL; PB7 -- SDA */
	GPIO_InitTypeDef  GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;		//Set output mode to open-drain, pull-up resistor required
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	I2C_DeInit(I2Cx);	//Reset I2C peripheral registers to default values
	I2C_InitTypeDef  I2C_InitStructure;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;			//Operating mode
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	//Clock duty cycle, Tlow/Thigh = 2
	I2C_InitStructure.I2C_OwnAddress1 = 0x88;	//Host I2C address, unused so any value is fine, no effect
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;	//Enable acknowledge bit
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//Set address length to 7 bits
	I2C_InitStructure.I2C_ClockSpeed = 400000;	//I2C transfer speed, 400K, check chip datasheet for supported speeds.	
	I2C_Init(I2Cx, &I2C_InitStructure);

	I2C_Cmd(I2Cx, ENABLE);
}

void I2C_WriteByte(uint8_t addr,uint8_t data)
{
	
	while( I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
	
	//Send start signal
	I2C_GenerateSTART(I2Cx, ENABLE);
	//Check EV5 event
	while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);
	//Send device write address
	I2C_Send7bitAddress(I2Cx, OLED_ADDRESS, I2C_Direction_Transmitter);
	//Check EV6 event
	while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
	
	//Send internal address to operate
	I2C_SendData(I2Cx, addr);
	//Check EV8_2 event
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	
	I2C_SendData(I2Cx, data);//Send data
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

	//Send stop signal
	I2C_GenerateSTOP(I2Cx, ENABLE);
}
 
/**
  * @brief  OLED write command
  * @param  Command command to write
  * @retval none
  */
void OLED_WriteCommand(unsigned char Command)//write command
{
	I2C_WriteByte(0x00, Command);
}
 
/**
  * @brief  OLED write data
  * @param  Data data to write
  * @retval none
*/
void OLED_WriteData(unsigned char Data)//write data
{
	I2C_WriteByte(0x40, Data);
}

/**
  * @brief  OLED set cursor position
  * @param  Y coordinate from top-left origin, down direction, range: 0~7
  * @param  X coordinate from top-left origin, right direction, 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 position low 4 bits
	OLED_WriteCommand(0x00 | (X & 0x0F));			//Set X position high 4 bits
}

/**
  * @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 content
		}
		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 content
		}
	}
}

/**
  * @brief  OLED display a 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 content
	}
	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 content
	}
}

/**
  * @brief  OLED display string
  * @param  Line starting row position, range: 1~4
  * @param  Column starting column position, 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 position, range: 1~4
  * @param  Column starting column position, 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 position, range: 1~4
  * @param  Column starting column position, 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 position, range: 1~4
  * @param  Column starting column position, 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 position, range: 1~4
  * @param  Column starting column position, 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
}

Recommended Reading

1 Like