STM32 reading SHT3x series temperature and humidity sensors, standard library and HAL library

STM32 Reading SHT3x Series (SHT30, SHT31, SHT35) Temperature and Humidity Sensor Data and Displaying on 0.96-inch OLED Screen.

I provide two sets of code below, one using the Standard Library with Hardware I2C, and another using the HAL Library with Software Simulated I2C.

The microcontroller I use is STM32F103C8T6, and the temperature and humidity sensor is SHT30.

STM32 Software I2C Reading AM2320 Temperature and Humidity Sensor Data: https://blog.zeruns.com/archives/695.html
STM32 Using Hardware I2C to Read SHTC3 Temperature and Humidity Sensor: https://blog.zeruns.com/archives/692.html
STM32 Microcontroller Reading AHT10 Temperature and Humidity Sensor Data: https://blog.zeruns.com/archives/693.html

Electronics/Microcontroller Technology Exchange Group: 2169025065

Implementation Effect


I2C Protocol Introduction

The I2C communication protocol (Inter-Integrated Circuit) was developed by Philips. Due to its few pins, simple hardware implementation, and strong scalability, it does not require external transceiver devices (such as level conversion chips) like USART and CAN communication protocols. It is now widely used for communication between multiple integrated circuits (ICs) within a system.

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

Half-duplex communication: Can achieve bidirectional communication, but cannot proceed simultaneously in both directions. It must be done alternately and sequentially. It can also be understood as a type of simplex communication with switchable direction. At any given moment, only one direction can transmit, requiring only one data line.

For the I2C communication protocol, it is divided into the physical layer and protocol layer. The physical layer specifies the characteristics of the mechanical and electronic functional parts in the communication system (hardware part), ensuring the transmission of raw data over the physical medium. The protocol layer mainly specifies the communication logic, unifying the data packaging and unpacking standards of both transmitter and receiver (software level).

I2C Physical Layer

Common Connection Methods Between I2C Communication Devices

(1) It is a bus that supports multiple devices. “Bus” refers to signal lines shared by multiple devices. In an I2C communication bus, multiple I2C communication devices can be connected, supporting multiple communication masters and multiple communication slaves.

(2) An I2C bus uses only two bus lines: one bidirectional serial data line SDA (Serial Data Line), and one serial clock line SCL (Serial Clock Line). The data line is used to represent data, and the clock line is used to synchronize data transmission and reception.

(3) The bus is connected to the power supply through pull-up resistors. When an I2C device is idle, it outputs a high-impedance state. When all devices are idle and output high-impedance states, the pull-up resistors pull the bus to a high level.

During I2C communication, the microcontroller GPIO port must be configured as open-drain output, otherwise it may cause a short circuit.

For more information about STM32 I2C and usage methods, you can refer to this article: https://url.zeruns.com/JC0Ah

I won’t go into detail here.

SHT3x Temperature and Humidity Sensor

SHT3x Datasheet Download Address:

Original: https://url.zeruns.com/uWNnP Extraction Code: icqu

Chinese Version (Machine Translation): https://url.zeruns.com/n9b9t Extraction Code: vedy

By reviewing the datasheet, you can get a general understanding that the SHT30 is a sensor that can detect temperature and humidity.
Temperature Range: -40℃ ~ 125℃
Humidity Range: 0% ~ 100%
Operating Voltage: 2.4V ~ 5.5V
Communication Method: I2C
Clock Frequency: 0 ~ 1000kHz

The following key information was found:

SHT3x Device Address and Read/Write Commands

The SHT3x address can be set by connecting the 2nd pin to high or low level. The sensor on the module I bought from Taobao has pin 2 connected to VCC through a resistor, which means the default is 0x44.

In actual use, the SHT3x device address needs to be combined with the read/write data/command direction bit to form a byte that is sent simultaneously. The least significant bit of the byte is the read/write data/command direction bit, and the upper 7 bits are the SHT3x device address.

To write data or commands to SHT3x via I2C, after the I2C start signal, you need to send “1000 1000”, which is 0x88 to SHT3x. In addition to addressing through the upper 7 bits “1000 100” (0x44) device address, the least significant bit “0” notifies SHT3x that the following is a write data or command operation.

To read data from SHT3x via I2C, after the I2C start signal, you need to send “1000 1001”, which is 0x89 to SHT3x. In addition to addressing through the upper 7 bits “1000 100” device address, the least significant bit “1” notifies SHT3x that the following is a data read operation.

In short, 0x88 means write data, and 0x89 means read data. However, when using STM32 hardware I2C, you only need to input 0x88, and the least significant bit will be handled by the standard library.

Reading Temperature and Humidity Data

As you can see, different commands result in different data acquisition methods, including single measurement and periodic measurement modes, as well as differences between Clock Stretching Enable and Disable.

Clock Stretching refers to clock stretching. If you use the Clock Stretching Enable command, after sending the measurement command, during the process of SHT3x measuring temperature and humidity data, SHT3x will pull the I2C clock line SCL low, thereby prohibiting the master from sending commands to SHT3x. Only when SHT3x completes the temperature and humidity data measurement will it release the clock line SCL.

If you use the Clock Stretching Disable command, during the data measurement process of SHT3x, SHT3x will not pull the I2C clock line SCL low. However, if the master sends commands or data during SHT3x’s data measurement process, sending a read instruction will cause SHT3x to return a non-acknowledgment signal. Only after measurement is complete will sending a read instruction return an acknowledgment signal.

Periodic measurement mode allows the sensor to automatically measure and save data. You can set the measurement frequency to 0.5/1/2/4/10 times per second, and then read the latest measurement results through the read instruction 0xE000.

From the datasheet, a measurement cycle includes 2 steps:

  1. Send measurement command
  2. Read data after measurement is complete.

The above measurement commands and read commands can be found in the datasheet.

Summary as follows:

  1. Send measurement command: First send the write instruction (0x88), then send the wake-up instruction high byte (0x2C), then send the wake-up instruction low byte (0x0D).
  2. Read data and wait for measurement completion: Send read instruction (0x89), wait for the slave to release the SCL bus.
  3. Receive data: Continuously receive 6 bytes of data. The 1st-2nd bytes of these 6 bytes are the temperature value, the 3rd byte is the temperature checksum. The 4th-5th bytes are the humidity value, and the 6th byte is the humidity checksum. After receiving the last byte, send a non-acknowledgment signal.
  4. Process data: Perform CRC verification and processing on the data.

Data Calculation

From the SHT3x datasheet:

For example: If the collected humidity value is 0x6501, converted to decimal is 25857.
Then: Humidity = 100 * 25857 / (65536 - 1) = 39.45 (Unit: %)
If the collected temperature value is 0x6600, converted to decimal is 26112.
Then: Temperature = -45 + 175 * 26112 / (65536 - 1) = 24.72 (Unit: ℃)

Required Components

STM32 Minimum System Board: https://s.click.taobao.com/AJEGiNu
SHT3x Module: https://s.click.taobao.com/55xGiNu
OLED Module: https://s.click.taobao.com/0dlG0Ou
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 provide the main code files for the standard library version: main.c, SHT3x.c, and oled.c. Please download the compressed package from the link below for the rest.

Standard Library Version: https://url.zeruns.com/a49EX Extraction Code: 8nn5

HAL Library Version: https://url.zeruns.com/p3og4 Extraction Code: v9wc

The SCL of SHT3x and OLED modules are connected to PB6, and SDA is connected to PB7.

Using VSCode Instead of Keil for STM32 and 51 Microcontroller 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 "SHT3x.h"


uint16_t numlen(uint16_t num);

int main(void)
{
	IWDG_Configuration();	//Initialize watchdog
	OLED_Init();	 		//Initialize OLED screen
	SHT3x_Init();	 		//Initialize SHT3x
	
	/*OLED_ShowString(1, 1, "T:");
	OLED_ShowString(3, 1, "H:");*/
	
	uint8_t Chinese[]={0,1};
  	OLED_ShowChinese(1,1,Chinese,2);//Temperature
  	uint8_t Chinese1[]={2,3};
	OLED_ShowChinese(3,1,Chinese1,2);//Humidity
  	uint8_t Chinese2[]={4};
	OLED_ShowChinese(1,11,Chinese2,1);//℃

	uint32_t a=0;
	uint16_t err_count=0;
	
	while (1)
	{
		a++;
		OLED_ShowNum(2, 14, a, 2);
		if(a==99)a=0;

		float Temp,Hum;	 		//Declare variables to store temperature and humidity data

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

			sprintf(String, " %.2f%%", Hum);	//Format string output to string variable
			OLED_ShowString(3, 5, String);	//Display humidity
		}else
		{
			char String[10];
			sprintf(String, "%.2f", Temp);//Format string output to string variable
			OLED_ShowString(1, 5, String);	//Display temperature
			
			sprintf(String, " %.2f%%", Hum);	//Format string output to string variable
			OLED_ShowString(3, 5, String);	//Display humidity
		}
	}
	else
	{
		err_count++;
		OLED_ShowNum(1,14, err_count, 2);	//Display error count
	}
	
	/*
	https://blog.zeruns.com
	*/

	Delay_ms(200);	//Delay 200 milliseconds

	IWDG_FeedDog();	//Feed dog (watchdog, automatic reset if not fed within 1 second)
}
}

/**
  * @brief  Calculate integer length
  * @param  num Integer whose length is to be calculated
  * @retval Length value
  */
uint16_t numlen(uint16_t num)
{
    uint16_t len = 0;        // Initial length is 0
    for(; num > 0; ++len)    // Check if num is greater than 0, otherwise length + 1
        num /= 10;	         // Use division for calculation until num is less than 1
    return len;              // Return the length value
}

SHT3x.c

#include "stm32f10x.h"
#include "Delay.h"

/*SHT3x address*/
#define SHT3x_ADDRESS 0x44<<1	//Slave address is 7 bits, so shift left by one bit

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

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

/**
  * @brief  CRC check, CRC polynomial is: x^8+x^5+x^4+1, i.e. 0x31
  * @param  DAT Data to be checked
  * @retval Check code
  */
uint8_t SHT3x_CRC_CAL(uint16_t DAT)
{
	uint8_t i,t,temp;
	uint8_t CRC_BYTE;

	CRC_BYTE = 0xFF;
	temp = (DAT>>8) & 0xFF;

	for(t = 0; t < 2; t++)
	{
		CRC_BYTE ^= temp;
		for(i = 0;i < 8;i ++)
		{
			if(CRC_BYTE & 0x80)
			{
				CRC_BYTE <<= 1;
				CRC_BYTE ^= 0x31;
			}
			else
			{
				CRC_BYTE <<= 1;
			}
		}

		if(t == 0)
		{
			temp = DAT & 0xFF;
		}
	}

	return CRC_BYTE;
}

/*Send start signal*/
void SHT3x_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);//Detect EV5 event
}

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

/**
  * @brief  Send two bytes of data
  * @param  MSB High 8 bits
  * @param  LSB Low 8 bits
  * @retval None
  */
void SHT3x_WriteByte(uint8_t MSB,uint8_t LSB)
{
	SHT3x_I2C_START();  //Send start signal
	
	I2C_Send7bitAddress(I2Cx, SHT3x_ADDRESS, I2C_Direction_Transmitter);    //Send device write address
	while(I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);  //Detect EV6 event

    I2C_SendData(I2Cx, MSB);//Send high 8 bits of data
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Detect EV8 event
   
	I2C_SendData(I2Cx, LSB);//Send low 8 bits of data
	while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Detect EV8 event
	
	I2C_GenerateSTOP(I2Cx, ENABLE);//Send stop signal
	
}

/**
  * @brief  Read data
  * @retval Byte data read
  */
uint8_t SHT3x_ReadData()
{
    while (!I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED));//Detect EV7 event
	return I2C_ReceiveData(I2Cx);//Read and return data
}

/*Software reset SHT3x*/
void SHT3x_SoftReset(void)                    
{
    SHT3x_WriteByte(0x30,0xA2);    //Reinitialize SHT3x
}

/*Pin initialization*/
void SHT3x_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, requires pull-up resistor
	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;			//Working mode
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	//Clock duty cycle, Tlow/Thigh = 2
	I2C_InitStructure.I2C_OwnAddress1 = 0x30;	//Master I2C address, irrelevant if not used
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;	//Enable acknowledgment bit
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//Set address length to 7 bits
	I2C_InitStructure.I2C_ClockSpeed = 400000;	//I2C transfer speed, 400K, check your chip manual for supported speeds.	
	I2C_Init(I2Cx, &I2C_InitStructure);         //Initialize I2C

	I2C_Cmd(I2Cx, ENABLE);  //Enable I2C

	//SHT3x_WriteByte(0X27,0X21); //Periodic data acquisition mode (10 times per second, Medium Repeatability)

	Delay_us(300);//Delay 300 microseconds
}

/**
  * @brief  Read SHT3x data
  * @param  *Hum Humidity
  * @param  *Temp Temperature
  * @retval 1 - Read successful; 0 - Read failed
  */
uint8_t ReadSHT3x(float *Hum,float *Temp)
{
    uint16_t HumData,TempData,HumCRC,TempCRC;//Declare variables to store read data
    
    //SHT3x_WriteByte(0XE0,0X00);   //Send command to get data, used for periodic data acquisition mode

    SHT3x_WriteByte(0X2C,0X0D); //Send single measurement command (enable clock stretching, Medium Repeatability)
	
    SHT3x_I2C_START();//Send start signal
    
	I2C_Send7bitAddress(I2Cx,SHT3x_ADDRESS,I2C_Direction_Receiver);//Send device read address
	
	while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR);//Detect EV6 event

    TempData = SHT3x_ReadData();//Read temperature high 8 bits
    TempData=TempData<<8;       //Shift left by 8 bits
	TempData |= SHT3x_ReadData();//Read temperature low 8 bits
    TempCRC = SHT3x_ReadData(); //Read temperature CRC check data
	
    HumData = SHT3x_ReadData(); //Read humidity high 8 bits
    HumData=HumData<<8;         //Shift left by 8 bits
	HumData |= SHT3x_ReadData();//Read humidity low 8 bits
    I2C_AcknowledgeConfig(I2Cx,DISABLE);    //Disable acknowledgment signal
    HumCRC = SHT3x_ReadData();  //Read humidity CRC check data

    SHT3x_I2C_STOP();   //Send stop signal
    I2C_AcknowledgeConfig(I2Cx,ENABLE); //Enable acknowledgment signal
	

    if( SHT3x_CRC_CAL(HumData)==HumCRC && SHT3x_CRC_CAL(TempData)==TempCRC ){   //Perform CRC check on received data
       *Hum = (float)HumData*100/(65536-1);        //Convert received 16-bit binary data to decimal humidity data
       *Temp = (float)TempData*175/(65536-1)-45;   //Convert received 16-bit binary data to decimal temperature data
       return 1;
    }
    return 0;
}

oled.c

#include "stm32f10x.h"
#include "OLED_Font.h"

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

/*Set 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 chip 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 output, requires pull-up resistor
	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;			//Working mode
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;	//Clock duty cycle, Tlow/Thigh = 2
	I2C_InitStructure.I2C_OwnAddress1 = 0x30;	//Master I2C address, irrelevant if not used
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;	//Enable acknowledgment bit
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//Set address length to 7 bits
	I2C_InitStructure.I2C_ClockSpeed = 400000;	//I2C transfer speed, 400K, check your chip manual 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);
	//Detect EV5 event
	while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_MODE_SELECT)==ERROR);
	//Send device write address
	I2C_Send7bitAddress(I2Cx, OLED_ADDRESS, I2C_Direction_Transmitter);
	//Detect EV6 event
	while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR);
	
	//Send the address of the device internal register to operate
	I2C_SendData(I2Cx, addr);
	//Detect 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 in the downward direction with the top-left corner as origin, range: 0~7
  * @param  X Coordinate in the rightward direction with the top-left corner as origin, 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);
		}
	}
}
``````c
/**
  * @brief  OLED partial screen clear
  * @param  Line Line 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 position in upper half
		for (i = 0; i < 8; i++)
		{
			OLED_WriteData(0x00);			//Display upper half content
		}
		OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8);	//Set cursor position in lower half
		for (i = 0; i < 8; i++)
		{
			OLED_WriteData(0x00);		//Display lower half content
		}
	}
}

/**
  * @brief  OLED display a single character
  * @param  Line Line 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 position in 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 position in lower half
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]);		//Display lower half content
	}
}

/**
  * @brief  OLED display a Chinese character
  * @param  Line Line position, range: 1~4
  * @param  Column Column position, range: 1~16
  * @param  Chinese Position of the Chinese character in the font library array
  * @retval None
  */
void OLED_ShowWord(uint8_t Line, uint8_t Column, uint8_t Chinese)
{      	
	uint8_t i;
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8);
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F16x16[Chinese][i]);	
	}
	OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8 + 8);
	for (i = 1; i < 8; i++)
	{
		OLED_WriteData(OLED_F16x16[Chinese][i+8]);	
	}
	OLED_SetCursor((Line - 1) * 2 +1, (Column - 1) * 8);
	for (i = 0; i < 8; i++)
	{
		OLED_WriteData(OLED_F16x16[Chinese][i+16]);
	}
	OLED_SetCursor((Line - 1) * 2 +1, (Column - 1) * 8 + 8);
	for (i = 1; i < 8; i++)
	{
		OLED_WriteData(OLED_F16x16[Chinese][i+16+8]);
	}
}

/**
  * @brief  OLED display a string of Chinese characters
  * @param  Line Line position, range: 1~4
  * @param  Column Column position, range: 1~16
  * @param  Chinese[] Position of Chinese characters in the font library array, array stores the position of each character
  * @param	Length Length of Chinese characters to display, range: 1~8
  * @retval None
  */
void OLED_ShowChinese(uint8_t Line, uint8_t Column, uint8_t *Chinese,uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i++)
	{
		OLED_ShowWord(Line, Column + i*2,Chinese[i]);
	}
}

/**
  * @brief  OLED display string
  * @param  Line Starting line 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 Return value equals 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 line 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 line 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 line 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 line 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);	//Turn off display
	
	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 left-right direction, 0xA1 normal, 0xA0 left-right reversed
	
	OLED_WriteCommand(0xC8);	//Set up-down direction, 0xC8 normal, 0xC0 up-down reversed

	OLED_WriteCommand(0xDA);	//Set COM pin 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/inverted display

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

	OLED_WriteCommand(0xAF);	//Turn on display
		
	OLED_Clear();				//OLED clear screen
}

Recommended Reading

1 Like