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:
- Send measurement command
- Read data after measurement is complete.
The above measurement commands and read commands can be found in the datasheet.
Summary as follows:
- 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).
- Read data and wait for measurement completion: Send read instruction (0x89), wait for the slave to release the SCL bus.
- 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.
- 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
- High cost-performance and cheap VPS/cloud server recommendations: https://blog.vpszj.cn/archives/41.html
- Build an intranet penetration service server with NPS, with Web panel: https://blog.vpszj.cn/archives/748.html
- Linux website building tutorial, website building tutorial: https://blog.vpszj.cn/archives/1094.html
- Minecraft server building tutorial: https://blog.vpszj.cn/archives/tag/minecraft
- Ultrasonic distance measurement function based on STM32 and HC-SR04 module: https://blog.zeruns.com/archives/680.html
- ESP8266 development environment setup and project demonstration: https://blog.zeruns.com/archives/526.html






