SSD1306_OLED use summary

This article is the author's first blog. The purpose of writing it is to urge myself to learn and share with everyone. Please advise if there are any inaccuracies in the article.
This article is mainly a summary of the use of various OLED screens encountered by the author in the process of learning the single-chip microcomputer.
There are many programs for the OLED screen driven by SSD1306. There are two main ways to communicate with the microcontroller, one is SPI communication, and the other is I2C communication. Each communication method is divided into hardware and software communication.
There are a few explanations, the hardware used by the first author is based on STM32F1. Second, because the drive functions of OLEDs are similar, this article only records the initialization methods of various drive modes. It is convenient for us to transplant to different platforms according to the programs and OLED screens in our hands.

1. SPI communication

1. Hardware SPI

To be added…

2. Software SPI

#define SCLK_PIN  GPIO_Pin_6
#define SDIN_PIN  GPIO_Pin_7
#define RST_PIN   GPIO_Pin_0
#define DC_PIN    GPIO_Pin_1
#define CS_PIN    GPIO_Pin_10  
//引脚宏定义 可根据实际电路连接方式更改
void OLED_Init(void) //OLED初始化函数
{
    
    
    GPIO_InitTypeDef  GPIO_InitStructure;
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
 	
	GPIO_InitStructure.GPIO_Pin = SCLK_PIN| SDIN_PIN;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
 	GPIO_SetBits(GPIOA, SCLK_PIN| SDIN_PIN| CS_PIN);	
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = RST_PIN |DC_PIN| CS_PIN ;
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOB, &GPIO_InitStructure);
 	GPIO_SetBits(GPIOB,RST_PIN| DC_PIN| CS_PIN );
 }

Then you need to create a function

void OLED_WR_Byte(u8 dat,u8 cmd)
{
    
    	
	u8 i;			  
	OLED_DC=cmd;  			  
	OLED_CS=0;
	for(i=0;i<8;i++)
	{
    
    			  
		OLED_SCL=0;
		if(dat&0x80)
			OLED_SDA=1;
		else 
		   	OLED_SDA=0;
		OLED_SCL=1;
		dat<<=1;   
	}				 		  
	OLED_CS=1;
	OLED_DC=1;   	  
} 

Insert picture description here
It is the key to our communication with the device, and can be written according to the timing diagram of the corresponding communication method. When the cmd parameter is 0, the function will perform a write command operation, when cmd is 1, the function will perform a write data operation.
After that, we need to call this function to write a command to perform a series of initialization operations on the SSD1306. This step can also be written according to the corresponding data sheet.

 	OLED_WR_Byte(0xAE,OLED_CMD);//--display off
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  
	OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
	OLED_WR_Byte(0x81,OLED_CMD); // contract control
	OLED_WR_Byte(0xFF,OLED_CMD);//--128   
	OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap 
	OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1to64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00,OLED_CMD);//
	OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
	OLED_WR_Byte(0x80,OLED_CMD);//
	OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
	OLED_WR_Byte(0x05,OLED_CMD);//
	OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
	OLED_WR_Byte(0xF1,OLED_CMD);//
	OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
	OLED_WR_Byte(0x12,OLED_CMD);//
	OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
	OLED_WR_Byte(0x30,OLED_CMD);//
	OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
	OLED_WR_Byte(0x14,OLED_CMD);//
	OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel

Second, I2C communication

1. Hardware I2C

There are several points worth noting about hardware I2C. One is that when configuring the pin mode, it needs to be configured as an open-drain output mode, and the other is that the communication function needs to call library functions.
The routine of the wildfire family is as follows:

void OLED_Init(void)
{
    
    
	I2C_InitTypeDef  I2C_InitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure; 

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	//硬件I2C: PB6--SCL; PB7--SDA
	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;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	I2C_DeInit(I2C1);
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = 0x30;//主机的I2C地址
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = 400000;

	I2C_Cmd(I2C1, ENABLE);
	I2C_Init(I2C1, &I2C_InitStructure);
}
void OLED_WR_Byte(uint8_t data, uint8_t addr)
{
    
    
	while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
	I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/
	I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
	I2C_SendData(I2C1, addr);//寄存器地址
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	I2C_SendData(I2C1, data);//发送数据
	while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
	I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线
}

2. Software I2C

#define SCL_PIN   GPIO_Pin_6
#define SDA_PIN   GPIO_Pin_7
void OLED_Init(void)
{
    
     		 
 	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = SCL_PIN | SDA_PIN ;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
 	GPIO_SetBits(GPIOA,GPIO_SCL|GPIO_SDA);	
 }

Similarly, a write data function can be written according to the timing diagram of the I2C communication protocol.
I2C complete data transmission timing diagram

void Write_IIC_Byte(unsigned char dat)
{
    
    
	unsigned char i;
	unsigned char m,da;
	da=IIC_Byte;
	OLED_SCLK_Clr();
	for(i=0;i<8;i++)		
	{
    
    
		m=da;
		m=m&0x80;
		if(m==0x80)
		{
    
    OLED_SDIN_Set();}
		else OLED_SDIN_Clr();
		da=da<<1;
		OLED_SCLK_Set();
		OLED_SCLK_Clr();
	}
}
void OLED_WR_Byte(u8 dat,u8 cmd)
{
    
    
	OLED_SCLK_Set();
	OLED_SDIN_Set();
	OLED_SDIN_Clr();
	OLED_SCLK_Clr();  //I2C_start
    Write_IIC_Byte(0x78);
    OLED_SCLK_Set();
	OLED_SCLK_Clr();  //I2C_ack
    if(cmd) Write_IIC_Byte(0x40);
	else Write_IIC_Byte(0x00);	
    OLED_SCLK_Set();
	OLED_SCLK_Clr();  //I2C_ack
    Write_IIC_Byte(dat); 
    OLED_SCLK_Set();
	OLED_SCLK_Clr();  //I2C_ack
    OLED_SCLK_Set() ;
    OLED_SDIN_Clr();
	OLED_SDIN_Set();  //I2C_stop
}

Guess you like

Origin blog.csdn.net/weixin_44625313/article/details/103951928