STM32 uses hardware I²C to read SHTC3 temperature & humidity sensor data and display it on a 0.96-inch OLED screen.
I’m using an STM32F103C8T6 and the ST Standard Peripheral Library.
Electronics / MCU discussion group: 2169025065
Result Photos
I²C Protocol Brief
The I²C (Inter-Integrated Circuit) bus was developed by Philips. It needs few pins, is easy to implement in hardware, scales well, and does not require external transceivers like USART or CAN (level-shifters), so it is widely used for on-board communication between ICs.
I²C has only one data line—SDA (Serial Data Line). Data are sent bit by bit, so it is serial and half-duplex.
Half-duplex: bidirectional, but only one direction at a time; essentially a switchable simplex link. One data line is enough.
We divide I²C into the physical layer (hardware) and the protocol layer (software rules).
I²C Physical Layer
Typical I²C bus connection
- Multi-device bus: several devices share the same signal lines. One I²C bus can contain multiple masters and slaves.
- Only two wires: bidirectional SDA (Serial Data) and SCL (Serial Clock). SDA carries data; SCL synchronizes it.
- Pull-up resistors tie the bus to VCC. When idle, devices go high-Z; with all devices idle the resistors pull the lines high.
MCU GPIOs must be configured as open-drain; otherwise a short-circuit may occur.
For more STM32 I²C details see: https://url.zeruns.com/JC0Ah
SHTC3 Temperature & Humidity Sensor
SHTC3 datasheet: https://url.zeruns.com/WpLDy
From the datasheet:
Temperature range: –40 °C ~ 125 °C
Humidity range: 0 % ~ 100 %
Supply: 1.6 V ~ 3.6 V
Interface: I²C
Clock: 0–100 kHz, 0–400 kHz, 0–1 MHz
Device Address & R/W Command
The 7-bit slave address plus R/W bit form one byte.
LSb = 0 → write, LSb = 1 → read.
Write: 0xE0 (1110 0000)
Read: 0xE1 (1110 0001)
With STM32 hardware I²C you only pass 0xE0; the library handles the R/W bit.
Reading Temperature & Humidity
Commands differ in data order and Clock-Stretching Enable/Disable.
Clock stretching: after the measurement command SHTC3 may hold SCL low until conversion is done (Enable), or simply NACK any access while busy (Disable).
One measurement cycle:
- Send wake-up command.
- Send measurement command.
- Read 6 bytes of data.
- Send sleep command.
Summary:
- Wake: 0xE0, 0x35, 0x17.
- Wait ≥ 240 µs.
- Start measurement: 0xE0, CommandHigh, CommandLow (choose one).
- Read: 0xE1, receive 6 bytes.
If temp first: bytes 1-2 = temp, 3 = temp-CRC, 4-5 = RH, 6 = RH-CRC.
If RH first the order is reversed. - Sleep: 0xE0, SleepCommand.
Data Conversion
Per datasheet:
Humidity = 100 × raw / 65536 [%]
Temperature = –45 + 175 × raw / 65536 [°C]
Example:
RH raw = 0x6501 = 25857 → 100 × 25857 / 65536 = 39.45 %
Temp raw = 0x6600 = 26112 → –45 + 175 × 26112 / 65536 = 24.72 °C
Required Parts
STM32 minimum system board: https://s.click.taobao.com/bqMwZRu
SHTC3 module: https://s.click.taobao.com/WxACJRu
OLED module: https://s.click.taobao.com/aNlvZRu
Jumper wires: https://s.click.taobao.com/xAkAJRu
Breadboard: https://s.click.taobao.com/ShJAJRu
ST-LINK V2: https://s.click.taobao.com/C8ftZRu
Code
Only main.c, shtc3.c and oled.c are shown below; download the full project from the link.
Complete project: https://url.zeruns.com/EXCvo
Wire SHTC3 and OLED SCL → PB6, SDA → PB7.
Using VS Code instead of Keil for STM32 & 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 "SHTC3.h"
uint16_t numlen(uint16_t num);
int main(void)
{
IWDG_Configuration(); // Init independent watchdog
OLED_Init(); // Init OLED
SHTC3_I2C_Init(); // Init SHTC3
OLED_ShowString(1, 1, "T:");
OLED_ShowString(2, 1, "H:");
OLED_ShowString(4, 1, "err_count:");
uint32_t a=0;
uint16_t err_count=0;
while (1)
{
a++;
OLED_ShowNum(3, 1, a, 9);
if(a==999999999)a=0;
float Temp,Hum; // Variables for temp & RH
if(ReadSHTC3(&Hum,&Temp)) // Read sensor
{
if(Temp>=0)
{
char String[10];
sprintf(String, "%.2fC", Temp); // Format to string
OLED_ShowString(1, 3, String); // Display temperature
/*
OLED_ShowNum(1,3, (uint8_t)Temp, numlen((uint8_t)Temp));// Integer part
OLED_ShowChar(1, 3+numlen((uint8_t)Temp), '.'); // Decimal point
OLED_ShowNum(1,3+numlen((uint8_t)Temp)+1, (uint8_t)(Temp*100)%100, 2); // Fraction
OLED_ShowChar(1, 3+numlen((uint8_t)Temp)+1+2, 'C'); // Unit
*/
```sprintf(String, "%.2f%%", Hum); //Format string output to string variable
OLED_ShowString(2, 3, String); //Display humidity
/*
OLED_ShowNum(2,3, (uint8_t)Hum, numlen((uint8_t)Hum)); //Display humidity integer part
OLED_ShowChar(2, 3+numlen((uint8_t)Hum), '.'); //Display decimal point
OLED_ShowNum(2,3+numlen((uint8_t)Hum)+1, (uint8_t)(Hum*100)%100, 2); //Display humidity decimal part
OLED_ShowChar(2, 3+numlen((uint8_t)Hum)+1+2, '%'); //Display symbol
*/
}else
{
char String[10];
sprintf(String, "-%.2fC", Temp);//Format string output to string variable
OLED_ShowString(1, 3, String); //Display temperature
/*
OLED_ShowChar(1, 3, '-'); //Display negative sign
OLED_ShowNum(1,3+1, (uint8_t)Temp, numlen((uint8_t)Temp)); //Display temperature integer part
OLED_ShowChar(1, 3+1+numlen((uint8_t)Temp), '.'); //Display decimal point
OLED_ShowNum(1,3+1+numlen((uint8_t)Temp)+1, (uint8_t)(Temp*100)%100, 2); //Display temperature decimal part
OLED_ShowChar(1, 3+1+numlen((uint8_t)Temp)+1+2, 'C'); //Display symbol
*/
sprintf(String, "%.2f%%", Hum); //Format string output to string variable
OLED_ShowString(2, 3, String); //Display humidity
/*
OLED_ShowNum(2,3, (uint8_t)Hum, numlen((uint8_t)Hum)); //Display humidity integer part
OLED_ShowChar(2, 3+numlen((uint8_t)Hum), '.'); //Display decimal point
OLED_ShowNum(2,3+numlen((uint8_t)Hum)+1, (uint8_t)(Hum*100)%100, 2); //Display humidity decimal part
OLED_ShowChar(2, 3+numlen((uint8_t)Hum)+1+2, '%'); //Display symbol
*/
}
}
else
{
err_count++;
OLED_ShowNum(4,11, err_count, numlen(err_count)); //Display error count
}
/*
https://blog.zeruns.com
*/
Delay_ms(100); //Delay 100 milliseconds
IWDG_FeedDog(); //Feed the dog (watchdog, auto-reset if not fed within 1 second)
}
}
/**
* @brief Calculate integer length
* @param num Integer to calculate length
* @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 until num is less than 1
return len; // Return length value
}
SHTC3.c
#include "stm32f10x.h"
#include "Delay.h"
/*SHTC3 address*/
#define SHTC3_ADDRESS 0xE0
/*Set which I2C to use*/
#define I2Cx I2C1
/*
https://blog.zeruns.com
*/
/**
* @brief CRC check, CRC polynomial: x^8+x^5+x^4+1, i.e. 0x31
* @param DAT Data to be verified
* @retval Check code
*/
uint8_t SHTC3_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 SHTC3_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 SHTC3_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 SHTC3_WriteByte(uint8_t MSB,uint8_t LSB)
{
SHTC3_I2C_START(); //Send start signal
I2C_Send7bitAddress(I2Cx, SHTC3_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, MSB);//Send high 8 bits data
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Check EV8 event
I2C_SendData(I2Cx, LSB);//Send low 8 bits data
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//Check EV8 event
I2C_GenerateSTOP(I2Cx, ENABLE);//Send stop signal
}
/**
* @brief Read data
* @retval Read byte data
*/
uint8_t SHTC3_ReadData()
{
while (!I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_BYTE_RECEIVED));//Check EV7 event
return I2C_ReceiveData(I2Cx);//Read data and return
}
/*Software reset SHTC3*/
void SHTC3_SoftReset(void)
{
SHTC3_WriteByte(0x80,0x5D); //Reset SHTC3
}
/*Pin initialization*/
void SHTC3_I2C_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, needs 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; //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 7 bits
I2C_InitStructure.I2C_ClockSpeed = 400000; //I2C transfer speed, 400K, check supported speed in your chip manual.
I2C_Init(I2Cx, &I2C_InitStructure); //Initialize I2C
I2C_Cmd(I2Cx, ENABLE); //Enable I2C
SHTC3_WriteByte(0X35,0X17);//Wake up SHTC3
Delay_us(200);
}
/**
* @brief Read SHTC3 data
* @param *Hum Humidity
* @param *Temp Temperature
* @retval 1 - Read success; 0 - Read failure
*/
uint8_t ReadSHTC3(float *Hum,float *Temp)
{
uint16_t HumData,TempData,HumCRC,TempCRC;//Declare variables to store read data
/*SHTC3_WriteByte(0X35,0X17);//Wake up SHTC3
Delay_us(300);*/
SHTC3_WriteByte(0X5C,0X24);//Send command, read humidity data first, clock stretching (pull SCL clock line low during measurement, occupy bus)
SHTC3_I2C_START();//Send start signal
I2C_Send7bitAddress(I2Cx,SHTC3_ADDRESS,I2C_Direction_Receiver);//Send device read address
while( I2C_CheckEvent(I2Cx,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR);//Check EV6 event
HumData = SHTC3_ReadData(); //Read humidity high 8 bits data
HumData=HumData<<8; //Left shift 8 bits
HumData |= SHTC3_ReadData();//Read humidity low 8 bits data
HumCRC = SHTC3_ReadData(); //Read humidity CRC check data
TempData = SHTC3_ReadData();//Read temperature high 8 bits data
TempData=TempData<<8; //Left shift 8 bits
TempData |= SHTC3_ReadData();//Read temperature low 8 bits data
TempCRC = SHTC3_ReadData(); //Read temperature CRC check data
SHTC3_I2C_STOP(); //Send stop signal
//SHTC3_WriteByte(0XB0,0X98);//Send sleep command
if( SHTC3_CRC_CAL(HumData)==HumCRC && SHTC3_CRC_CAL(TempData)==TempCRC ){ //CRC check received data
*Hum = (float)HumData*100/65536; //Convert received 16-bit binary data to decimal humidity data
*Temp = (float)TempData*175/65536-45; //Convert received 16-bit binary data to decimal temperature data
return 1;
}
else{
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, needs 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; //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 7 bits
I2C_InitStructure.I2C_ClockSpeed = 400000; //I2C transfer speed, 400K, check supported speed in your chip manual.
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 address inside device 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);
}
``````c
/**
* @brief OLED write data
* @param Data data to be written
* @retval none
*/
void OLED_WriteData(unsigned char Data) // write data
{
I2C_WriteByte(0x40, Data);
}
/**
* @brief OLED set cursor position
* @param Y coordinate downward from top-left origin, range: 0~7
* @param X coordinate rightward from top-left 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 high 4 bits of X
OLED_WriteCommand(0x00 | (X & 0x0F)); // set low 4 bits of X
}
/**
* @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 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
}
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 raised 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, unsigned)
* @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, unsigned)
* @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, unsigned)
* @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 remap, 0xA1 normal 0xA0 reverse
OLED_WriteCommand(0xC8); // set COM output scan direction, 0xC8 normal 0xC0 reverse
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
}
Some content referenced from the following two articles:
https://blog.csdn.net/mj475002864/article/details/114027993
https://blog.csdn.net/k666499436/article/details/124686559
Recommended Reading
- Cost-effective and cheap VPS/cloud server recommendations: https://blog.vpszj.cn/archives/41.html
- Build an intranet penetration server with NPS, with web panel: https://blog.vpszj.cn/archives/748.html
- Linux website building tutorial: https://blog.vpszj.cn/archives/1094.html
- Minecraft server setup tutorial: https://blog.vpszj.cn/archives/tag/minecraft
- Ultrasonic distance measurement with STM32 and HC-SR04 module: https://blog.zeruns.com/archives/680.html
- ESP8266 development environment setup and project demo: https://blog.zeruns.com/archives/526.html





