STM32 microcontroller beginner 5-IIC communication drive OLED screen

In my last article ( STM32-Software Simulation IIC Communication ) I explained software simulation IIC communication. This article will explain in detail how to use software to simulate IIC to control a 0.96-inch OLED screen (as shown in the figure below) to display strings. This article will no longer explain the principle of IIC communication in detail, so if you are not familiar with the principle of IIC communication, you can refer to my previous article (click the link above to jump directly).

The above screen is one of the most commonly used products in MCU learning. It can be seen in many MCU works. First, briefly introduce this OLED screen:

Resolution : 64*128 (can display up to 8 lines of ASCII characters or 4 lines of Chinese characters)

Screen size : 0.96 inches

Communication method : IIC

Port: GND, VCC, SCL, SDA (ground, 3V-5V power supply, IIC clock line, IIC data line)

Driver chip : SSD1306


To use a screen, you must first start with its driver chip. Find its manual on the Internet, and you generally know how to use it.

Here I will briefly introduce its working process. Inside the SSD1306, there is a display SRAM buffer area , and the state of each storage unit corresponds to the state of the pixel on the screen (0 or 1). The control chip scans the OLED screen according to the data of the SRAM (dynamic scanning, its principle can refer to the article dynamic scanning display principle ). Therefore, the microcontroller only needs to write the data into the SRAM through the IIC, and all the refreshing of the screen can be done by the driver chip. Like the SRAM (static random access memory) inside the single-chip microcomputer, once the power is turned off, its data will be lost, so the OLED screen is turned on after the power is turned off, and the SRAM is blank.

---------------------------------------------------------

Let's first understand its screen partition. 

 The whole screen is divided into 8 large areas, which are called pages (from top to bottom, Page0-to Page7), each page is divided into 128 columns, and each column is divided into 8 small blocks. Each small block corresponds to a pixel point, which has two states of 0 and 1 (representing the off and on of the pixel point), which can be represented by 1bit data. Each column is 8 small blocks, which is 8bit, or 1Byte. During IIC data transmission, it happens that 1Byte is a data frame, so sending data once just refreshes the state of 8 pixels in SRAM.

When setting the initial coordinates of the OLED, it is positioned through a certain column on a certain page, and the commands for positioning are described below.

Common OLED screens are as shown above, only 4 pins, but here I am using a 7-pin OLED screen, which not only supports IIC communication, but also supports 4-wire SPI, 3-wire SPI. as shown in the picture

 The factory default of this OLED is 4-wire SPI, so if you want to use IIC communication, you have to change the line (as shown in the silk screen above), that is, remove the 4.7K resistor of R3 and install it in the position of R1, and short R8 or In addition, find a 0603 4.7K resistance and weld it on.

Its pins are defined as follows:

GND: connected to the power ground

VCC: connected to the power supply VCC (3V-5V)

D0: IIC-SCL/SPI-CLK. Connect the IIC_SCL of the microcontroller here

D1: IIC-SDA/MOSI. Connect the IIC-SDA of the microcontroller here

RES: reset pin. Can be controlled by a GPIO

DC: screen IIC address selection line (low level: address is 0x78; high level: 0x7A), generally directly grounded

CS: SPI chip selection SPI-CS, directly grounded here

If it is a 4-wire OLED screen, the connection method is much simpler. It can be connected to the MCU correspondingly, and the last three pins are omitted. The DC is connected to the ground inside, and the address is fixed at 0x78.

Not much else to say, while watching the program, while explaining.


1. Header file and function declaration

Here I use PB10 as the analog SCL of IIC, PB11 as the analog SDA of IIC, and PC13 as the reset pin of OLED. And declare their reset, easy to use. (The reason for this statement is because STM32 does not have sbit and cannot directly map variables to pins)

#include<stm32f10x.h>
#include<stm32f10x_gpio.h>
#include<stm32f10x_rcc.h>

#define Read_IIC_SDA GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)	//Read_IIC_SDA读取PB11的值

#define OLED_RES_H() GPIO_SetBits(GPIOC, GPIO_Pin_13)	//OLED RES脚置高电平
#define OLED_RES_L() GPIO_ResetBits(GPIOC, GPIO_Pin_13)	//OLED RES置低电平

#define IIC_SCL_H() GPIO_SetBits(GPIOB,GPIO_Pin_10)			//    IIC_SCL置高
#define IIC_SCL_L() GPIO_ResetBits(GPIOB,GPIO_Pin_10)		//	 IIC_SCL置低

#define IIC_SDA_H() GPIO_SetBits(GPIOB,GPIO_Pin_11)			//    IIC_SDA置高
#define IIC_SDA_L() GPIO_ResetBits(GPIOB,GPIO_Pin_11)		//    IIC_SDA置低

2. ASCII font and OLED cache

ASCII has a total of 127 characters, and the first 32 are special functions (carriage return, line feed, tab, etc.). We put the font library in a 127x6 array, the elements inside are unsigned 8-bit binary numbers (u8 or unsigned char), and each line of the array constitutes exactly one ASCII character (the minimum resolution required to fully display all ASCII characters It is 8x6, which is described in detail in the article Dynamic Scanning Display Principle ). Here I simplified the special functions, all displayed as blanks, or spaces.

Here you also need to declare an array as the cache of OLED's internal SRAM. Improve refresh performance.

unsigned char Dictionary_ASCII8x6[127][6]=
{
	0,0,0,0,0,0,//0	
	0,0,0,0,0,0,//1	
	0,0,0,0,0,0,//2	
	0,0,0,0,0,0,//3	
	0,0,0,0,0,0,//4	
	0,0,0,0,0,0,//5	
	0,0,0,0,0,0,//6	
	0,0,0,0,0,0,//7	
	0,0,0,0,0,0,//8	
	0,0,0,0,0,0,//9	
	0,0,0,0,0,0,//10	
	0,0,0,0,0,0,//11	
	0,0,0,0,0,0,//12	
	0,0,0,0,0,0,//13	
	0,0,0,0,0,0,//14	
	0,0,0,0,0,0,//15	
	0,0,0,0,0,0,//16	
	0,0,0,0,0,0,//17	
	0,0,0,0,0,0,//18	
	0,0,0,0,0,0,//19	
	0,0,0,0,0,0,//20	
	0,0,0,0,0,0,//21	
	0,0,0,0,0,0,//22	
	0,0,0,0,0,0,//23	
	0,0,0,0,0,0,//24	
	0,0,0,0,0,0,//25	
	0,0,0,0,0,0,//26	
	0,0,0,0,0,0,//27	
	0,0,0,0,0,0,//28	
    0,0,0,0,0,0,//29	
	0,0,0,0,0,0,//30	
	0,0,0,0,0,0,//31                    0-31为特殊功能,如换行、回车
	
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//32	空格
	0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,//33 !	
	0x00, 0x00, 0x07, 0x00, 0x07, 0x00,//34 "	
	0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14,//35 #	
	0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12,//36 $	
	0x00, 0x23, 0x13, 0x08, 0x64, 0x62,//37 %	
	0x00, 0x36, 0x49, 0x55, 0x22, 0x50,//38 &	
	0x00, 0x00, 0x05, 0x03, 0x00, 0x00,//39 '	
	0x00, 0x00, 0x1c, 0x22, 0x41, 0x00,//40 (	
	0x00, 0x00, 0x41, 0x22, 0x1c, 0x00,//41 )	
	0x00, 0x14, 0x08, 0x3E, 0x08, 0x14,//42 *	
	0x00, 0x08, 0x08, 0x3E, 0x08, 0x08,//43 +	
	0x00, 0x00, 0x00, 0xA0, 0x60, 0x00,//44 ,	
	0x00, 0x08, 0x08, 0x08, 0x08, 0x08,//45 -	
	0x00, 0x00, 0x60, 0x60, 0x00, 0x00,//46 .	
	0x00, 0x20, 0x10, 0x08, 0x04, 0x02,//47 /	
	0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,//48 0
	0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,//49 1	
	0x00, 0x42, 0x61, 0x51, 0x49, 0x46,//50 2	
	0x00, 0x21, 0x41, 0x45, 0x4B, 0x31,//51 3	
	0x00, 0x18, 0x14, 0x12, 0x7F, 0x10,//52 4	
	0x00, 0x27, 0x45, 0x45, 0x45, 0x39,//53 5	
	0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30,//54 6	
	0x00, 0x01, 0x71, 0x09, 0x05, 0x03,//55 7	
	0x00, 0x36, 0x49, 0x49, 0x49, 0x36,//56 8	
	0x00, 0x06, 0x49, 0x49, 0x29, 0x1E,//57 9	
	0x00, 0x00, 0x36, 0x36, 0x00, 0x00,//58 :	
	0x00, 0x00, 0x56, 0x36, 0x00, 0x00,//59 ;	
	0x00, 0x08, 0x14, 0x22, 0x41, 0x00,//60 <	
	0x00, 0x14, 0x14, 0x14, 0x14, 0x14,//61 =	
	0x00, 0x00, 0x41, 0x22, 0x14, 0x08,//62 >	
	0x00, 0x02, 0x01, 0x51, 0x09, 0x06,//63 ?	
	0x00, 0x32, 0x49, 0x59, 0x51, 0x3E,//64 @	
	0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,//65 A	
	0x00, 0x7F, 0x49, 0x49, 0x49, 0x36,//66 B	
	0x00, 0x3E, 0x41, 0x41, 0x41, 0x22,//67 C	
	0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C,//68 D	
	0x00, 0x7F, 0x49, 0x49, 0x49, 0x41,//69 E	
	0x00, 0x7F, 0x09, 0x09, 0x09, 0x01,//70 F	
	0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A,//71 G	
	0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,//72 H	
	0x00, 0x00, 0x41, 0x7F, 0x41, 0x00,//73 I	
	0x00, 0x20, 0x40, 0x41, 0x3F, 0x01,//74 J	
	0x00, 0x7F, 0x08, 0x14, 0x22, 0x41,//75 K	
	0x00, 0x7F, 0x40, 0x40, 0x40, 0x40,//76 L	
	0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F,//77 M	
	0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F,//78 N	
	0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E,//79 O	
	0x00, 0x7F, 0x09, 0x09, 0x09, 0x06,//80 P	
	0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E,//81 Q	
	0x00, 0x7F, 0x09, 0x19, 0x29, 0x46,//82 R	
	0x00, 0x46, 0x49, 0x49, 0x49, 0x31,//83 S	
	0x00, 0x01, 0x01, 0x7F, 0x01, 0x01,//84 T	
	0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F,//85 U	
	0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F,//86 V	
	0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F,//87 W	
	0x00, 0x63, 0x14, 0x08, 0x14, 0x63,//88 X	
	0x00, 0x07, 0x08, 0x70, 0x08, 0x07,//89 Y	
	0x00, 0x61, 0x51, 0x49, 0x45, 0x43,//90 Z	
	0x00, 0x00, 0x7F, 0x41, 0x41, 0x00,//91 [	
	0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55,/*92 \	*/
	0x00, 0x00, 0x41, 0x41, 0x7F, 0x00,//93 ]	
	0x00, 0x04, 0x02, 0x01, 0x02, 0x04,//94 ^	
	0x00, 0x40, 0x40, 0x40, 0x40, 0x40,//95 _	
	0x00, 0x00, 0x01, 0x02, 0x04, 0x00,//96 '	
	0x00, 0x20, 0x54, 0x54, 0x54, 0x78,//97 a	
	0x00, 0x7F, 0x48, 0x44, 0x44, 0x38,//98 b	
	0x00, 0x38, 0x44, 0x44, 0x44, 0x20,//99 c	
	0x00, 0x38, 0x44, 0x44, 0x48, 0x7F,//100 d	
	0x00, 0x38, 0x54, 0x54, 0x54, 0x18,//101 e	
	0x00, 0x08, 0x7E, 0x09, 0x01, 0x02,//102 f	
	0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,//103 g	
	0x00, 0x7F, 0x08, 0x04, 0x04, 0x78,//104 h	
	0x00, 0x00, 0x44, 0x7D, 0x40, 0x00,//105 i	
	0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,//106 j	
	0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,//107 k	
	0x00, 0x00, 0x41, 0x7F, 0x40, 0x00,//108 l	
	0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,//109 m	
	0x00, 0x7C, 0x08, 0x04, 0x04, 0x78,//110 n	
	0x00, 0x38, 0x44, 0x44, 0x44, 0x38,//111 o	
	0x00, 0xFC, 0x24, 0x24, 0x24, 0x18,//112 p	
	0x00, 0x18, 0x24, 0x24, 0x18, 0xFC,//113 q	
	0x00, 0x7C, 0x08, 0x04, 0x04, 0x08,//114 r	
	0x00, 0x48, 0x54, 0x54, 0x54, 0x20,//115 s	
	0x00, 0x04, 0x3F, 0x44, 0x40, 0x20,//116 t	
	0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C,//117 u	
	0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,//118 v	
	0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C,//119 w	
	0x00, 0x44, 0x28, 0x10, 0x28, 0x44,//120 x	
	0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,//121 y	
	0x00, 0x44, 0x64, 0x54, 0x4C, 0x44,//122 z	
	0x00, 0x08, 0x77, 0x41, 0x00, 0x00,//123	{
	0x00, 0x08,	0x7F, 0x00,	0x00, 0x00,//124	|
	0x00, 0x41,	0x77, 0x08,	0x00, 0x00,//125	}
	0x00, 0x08,	0x04, 0x08,	0x10, 0x08 //126	~
};
u8 SDRAM[8][128]={0};		//SRAM缓存

3. GPIO initialization

Here I define a function to initialize the software analog pins SCL (PB10), SDA (PB11) and res of IIC. All modes are push-pull outputs.

void IIC_UserInit(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOC, ENABLE);
   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10 | GPIO_Pin_11; //10--SCL   11--SDA
   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
   GPIO_Init(GPIOB, &GPIO_InitStructure);
	 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; 			//作为屏幕的RSE脚,4线OLED屏幕可省略
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOC,&GPIO_InitStructure);	
}

4. Delay function

For the convenience of understanding, the timer is not used here, and the Delay is directly

void Delay_us(int Time)    //us延时函数
{
	int i=0;
	while(Time--)
	{
		i=8;
		while(i--);
	}
	return;
}

5. IIC-SDA input and output mode switching function

During IIC communication, the microcontroller needs to wait for a response after sending data. At this time, the analog SDA must switch to the input mode (pull-up input), and switch back to the output mode (push-pull output) after receiving the response. The specific process can refer to the article software simulation IIC communication , which has a detailed introduction.

void SDA_OUT(void)    //输出模式
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin= GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;        //推挽输出
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}


void SDA_IN(void)    //输入模式
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin= GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;			//上拉输入模式
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

6.IIC software analog signal

Software simulation start signal, stop signal, response signal, data transmission


void IIC_Start(void)    //起始信号
{
    SDA_OUT();		//SDA切换输出模式
    IIC_SDA_H();		//SDA置高
    IIC_SCL_H();		//SCL置高
    Delay_us(1);
    IIC_SDA_L();		//SDA置低
    Delay_us(1);
    IIC_SCL_L();		//SCL置低
    Delay_us(1);
}

void IIC_Stop(void)    //停止信号
{
    IIC_SCL_H();		
    IIC_SDA_L();		
    Delay_us(1);
    IIC_SDA_H();		
    Delay_us(1);
}


u8 IIC_Wait_Ask(void)    //应答信号
{
    int count=0;
    IIC_SDA_H();
		SDA_IN();
    IIC_SCL_H();
    Delay_us(1);
    while(Read_IIC_SDA)
    {
        count++;
        if(count>250)
        {
            IIC_Stop();				//无应答则发停止信号,停止通信
            return 1;
        }   
    }
    IIC_SCL_L();
    Delay_us(1);
    return 0;
}


void IIC_WriteByte(u8 data)			//发送1Byte数据
{
    u8 i;
    SDA_OUT();			
    for(i=0;i<8;i++)		//循环传输,一次传输1bit数据,循环8次		
    {
        IIC_SCL_L();				
        if(data & 0x80)        //如果最高位为1 
            IIC_SDA_H();		//SDA置高
        else
            IIC_SDA_L();	    //否则置低
        IIC_SCL_H();				
        Delay_us(1);				
        IIC_SCL_L();				
        data<<=1;				//Deta左移一位		
    }
}

7. Write command and write data

Because there are both commands (OLED parameter settings) and data (display cache) inside the OLED screen, they need to be distinguished.

It is stated in the SSD1306 user manual:

If the chip receives a byte message of 0x00, it means that the next received data is a command;

If the chip receives a byte information of 0x40, it means that the next received data is to display SRAM data.

void WriteCmd(u8 command)    //写命令
{
    IIC_Start();
    IIC_WriteByte(0x78);//OLED地址
    IIC_Wait_Ask();
    IIC_WriteByte(0x00);写了0x00后代表后面发送的信息都是参数信息
    IIC_Wait_Ask();
    IIC_WriteByte(command);
    IIC_Wait_Ask();
    IIC_Stop();
}


void WriteDat(u8 data)    //写数据
{
    IIC_Start();
    IIC_WriteByte(0x78);//OLED地址
    IIC_Wait_Ask();
    IIC_WriteByte(0x40);//写了0x40后代表后面发送的信息都是数据信息
    IIC_Wait_Ask();
    IIC_WriteByte(data);
    IIC_Wait_Ask();
    IIC_Stop();
}

8. OLED initialization

Set the basic parameters of OLED, please refer to the SSD1306 user manual for specific parameter settings, only set the available ones here

void OLED_Init(void)
{
	OLED_RES_L();
	Delay_ms(100); //复位OLED 
	OLED_RES_H();
	
    WriteCmd(0x20); //Set Memory Addressing Mode  设置内存地址模式
    WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	
	WriteCmd(0xc8); //Set COM Output Scan 设置行扫描顺序为从上到下,c0为从下到上
    WriteCmd(0xa1); //--set segment re-map 0 to 设置列扫描顺序为从左到右,a0为从右到左

	WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7    设置页地址0-7
	WriteCmd(0x00); //---set low column address				列低位00-0F	
    WriteCmd(0x10); //---set high column address				列高位10-1F
    WriteCmd(0x40); //--set start line address				起始行
    
	WriteCmd(0x81); //--set contrast control register    对比度调节
    WriteCmd(0xff); //00-ff 由暗到亮
	  
    WriteCmd(0xa6); //--set normal display
    WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
    WriteCmd(0x3F); //
   
	WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
		
    WriteCmd(0xd3); //-set display offset显示便宜
    WriteCmd(0x00); //-not offset  00为无偏移
		
    WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency时钟分频率、振荡器频率
    WriteCmd(0xf0); //--set divide ratio	f0刷新率最大
   
	WriteCmd(0xd9); //--set pre-charge period
    WriteCmd(0x22); //
   
	WriteCmd(0xda); //--set com pins hardware configuration
    WriteCmd(0x12);
    
	WriteCmd(0xdb); //--set vcomh
    WriteCmd(0x20); //0x20,0.77xVcc
    
	WriteCmd(0x8d); //--set DC-DC enable		DC-DC使能
    WriteCmd(0x14); //			
	
	OLED_FullScreen_Refresh();					//
    WriteCmd(0xaf); //--turn on oled panel,打开显示		,0xAE 关闭显示
}

Generally, the OLED must be initialized before refreshing the OLED display SRAM. To put it bluntly, it is to set the parameters of the OLED. Of course, it can also be initialized during use. This is because the OLED parameters set last time will be lost after power off.

The reset OLED in the function is for 7-pin OLED screen, if it is 4-pin, it will reset automatically when power on, so you don’t need to reset it yourself, you can omit this step.

Parameter setting method : Each setting of SSD1306 corresponds to a command. After sending a specific command, the next or more commands indicate the value to be set. For example: memory mode address setting, this setting corresponds to the command 0x20. If the microcontroller wants to set this parameter, first send the command 0x20, indicating that I want to set the parameter of 0x20, and then send another command, which corresponds to the value to be set. The above program means to set the memory address mode corresponding to 0x20 to 0x10.

Memory address mode setting (0x20): There are three modes to choose from

00, Horizontal Addressing Mode (horizontal mode), refresh the screen in the order from right to right and from top to bottom (as follows), after scanning one line, it will return to the beginning of the next line to continue scanning. In this mode, there is no page the concept of

01, Vertical Addressing Mode (Vertical Mode) Refreshes the screen from top to bottom and from left to right. After refreshing a column, it returns to the beginning of the next column to continue scanning. The complete columns are not drawn in the figure.

10, Page Addressing Mode (RESET), starting from the first page, from top to bottom, from left to right, after scanning one page, return to the beginning of the next page to continue scanning. This is the default mode, which is what I use here;

 Which mode to adopt, get the font in a corresponding way. Otherwise it will be garbled.

11, Invalid (invalid settings)

----------------------------------------------------------------------

Row scanning order (0xc_): Set whether the screen scanning is from top to bottom (0xc8) or bottom to top (0xc0), which can realize the screen flipping up and down

Column scanning order (0xa_): Set whether the screen scanning is from left to right (0xa1) or from right to left (0xa0), which can realize the left and right flip of the screen (mirror effect)

---------------------------------------------------------------------

-Set the page address (0xb0); b0-b7 correspond to page1-page7 respectively, effectively
set the low bit of the column address (0x00) in page mode ; the low bits of the column 00-0F respectively represent the lower four bits of the column address as 0-F    
set the high bit of the column address (0x10); Column high bits 10-1F respectively represent the high four bits of the column address are 0-F    

These two parameters are used together, for example, 0x01, 0x1A, take the low bit 1, high bit A, the combination is 0xA1, corresponding to 161 in decimal, that is, to locate the 161st column.

Set start line (0x40);  

The above address parameters are used to set the coordinates of the starting point of refreshing the screen. After setting, the data sent later will refresh the display SRAM from this address.

----------------------------------------------------------------------

Contrast adjustment (0x81), this parameter is used to set the screen contrast, it can also be said to adjust the brightness, from 00-FF a total of 128 levels can be set, the larger the value, the higher the contrast

Other parameters will not be introduced in detail, please refer to the user manual. At the end of the function, a full-screen refresh function is called, which is declared below. The function is to clear the screen every time the OLED is started, so as to avoid the last picture remaining on the screen.

9. Full screen refresh function and partial refresh function

The full-screen refresh function is used to refresh the entire screen, and the partial refresh function only refreshes a certain area. Because the refreshed pixels are less than the global one, the refresh time is shorter.

void OLED_FullScreen_Refresh(void)		//全屏刷新
	{
		unsigned char Page,Column;
		for(Page=0;Page<8;Page++)		//按页循环刷新,8次循环,刷新8页
		{
			WriteCmd(0xb0+Page);       //page0-page7定位到第Page页
			WriteCmd(0x00);    			 //定位到第一列
			WriteCmd(0x10);     //
			
			IIC_Start();
			IIC_WriteByte(0x78);//OLED地址
			IIC_Wait_Ask();
			IIC_WriteByte(0x40);//写数据
			IIC_Wait_Ask();
			
			for(Column=0;Column<128;Column++)	//按列循环,128列,128次循环
			{
				IIC_WriteByte(SDRAM[Page][Column]);//将缓存数组的数据全部发送过去
				IIC_Wait_Ask();
			}
			IIC_Stop();    //发送完则发出停止信号
		}		
	}	

	void OLED_PartScreen_Refresh(u8 Page,u8 Column,u8 Length)		//局部刷新函数(输入页,列,宽度)
	{
		unsigned char i;
		WriteCmd(0xb0+Page);       //page0-page7,定位到第page页
		WriteCmd(Column%16);    			 //low column start address	  定位到列
		WriteCmd((Column/16)+16);     //high column start address 
		
		IIC_Start();
		IIC_WriteByte(0x78);
		IIC_Wait_Ask();
		IIC_WriteByte(0x40);
		IIC_Wait_Ask();
		
		for(i=Column;i<(Column+Length);i++)	//按列刷新
		{
				IIC_WriteByte(SDRAM[Page][i]);    //将缓存数组的数据部分发送过去
				IIC_Wait_Ask();
		}
		IIC_Stop();
	}	
	

10. Self-encapsulated Printf and Printf_part functions

The Printf function is used to output characters on a certain page, which will change the content displayed on the entire page. Printf_part is used to output characters in a certain part without affecting the content of other parts of the page.

Note that this function can only display ASCII characters. If you want to display Chinese characters, you need to add a Chinese font library, and Chinese needs to occupy two pages, that is, 8 lines.

void Printf(u8 Page,char Word_ASCII[])		//在某一页输出字符串
{
	u8 w,x;
	for(w=0;w<21;w++)
	{
		for(x=0;x<6;x++)
		{
			SDRAM[Page-1][6*w+x]=Dictionary_ASCII8x6[Word_ASCII[w]][x];		//将字库写入到缓存数组
		}
	}
	OLED_PartScreen_Refresh(Page-1,0,128);	//刷新整页

}

void Printf_part(u8 Page,u8 Column,u8 Words,char Word_ASCII[])		//在某一区域输出字符串
{
	u8 w,x;
	for(w=0;w<Words;w++)
	{
		for(x=0;x<6;x++)
		{
			SDRAM[Page-1][Column+w*6+x]=Dictionary_ASCII8x6[Word_ASCII[w]][x];
		}
	}
	OLED_PartScreen_Refresh(Page-1,Column,Words*6);				//刷新该区域的内容
}

11. Dynamic variable output function for displaying changing numbers

void Printf_Dynamic(u8 Page,u8 Column,u8 Words,u16 Variable)		//显示变化的数字
{
	u8 w,x,Date[5];				//Date5位 0-65535 Date[0, 1,  2,  3,  4]														
	Date[4]=Variable/10000;						//65535/10000=6				计算各位的值
	Date[3]=Variable/1000-Date[4]*10;				//	65535/1000=65,65-6*10=5
	Date[2]=Variable/100-Date[3]*10-Date[4]*100;			//	655-50-600=5
	Date[1]=Variable/10-Date[2]*10-Date[3]*100-Date[4]*1000;		//6553-50-500-6000=3
	Date[0]=Variable-Date[1]*10-Date[2]*100-Date[3]*1000-Date[4]*10000;		//65535-30-500-5000-60000=5
	
	for(w=0;w<Words;w++)		
	{
		for(x=0;x<6;x++)
		{
			SDRAM[Page-1][Column+w*6+x]=Dictionary_ASCII8x6[Date[Words-w-1]+48][x];
		}	
	}
	OLED_PartScreen_Refresh(Page-1,Column,Words*6);
}

12. Function to move up the screen as a whole

When the screen is not enough to display the content, you can move all the content up, and then continue to use Printf on the last line. According to this idea, you can also customize the overall downward movement, which will not be shown here.

void MoveUP(u8 Line)				//整体上移Line行
{
	u8 x,y;
	for (y=0;y<(8-Line);y++)				
	{
		for(x=0;x<128;x++)
		{
			SDRAM[y][x]=SDRAM[y+Line][x];
		}
	}
	for(y=(8-Line);y<8;y++)	
	{
		for(x=0;x<128;x++)
			{
				SDRAM[y][x]=0;
			}
	OLED_FullScreen_Refresh();				//全屏刷新
}

13. Main function

Call the subfunction, initialize GPIO, and initialize OLED.

Output Hello world... (the string should be included with " ")

void main(void)
{
    IIC_UserInit();    //GPIO初始化
    OLED_Init();        //OLED初始化
    Printf(1,"Hello world...");    //输出Hello world...

}

The final effect is as follows:

You can also add various custom icons and animations, compare and output ASCII codes, and just turn the font library into a graphics library.

For the convenience of understanding, here I put all the functions in a .c file. In actual projects, functions other than the main function are generally placed in different .c files according to their functions.


If you find this article useful, you can give it a thumbs up~

Guess you like

Origin blog.csdn.net/qq_55203246/article/details/124082182