SSD1306_OLED使用总结

本文是笔者的第一篇博客,写它的目的督促自己学习和同大家分享。文章若有纰漏,敬请指教。
本文主要是笔者在学习单片机过程中,所遇各种OLED屏幕的使用方式的总结归纳。
关于SSD1306驱动的OLED屏幕的程序有很多,其与单片机通信的方式主要有两种,一是SPI通信,二是I2C通信。其中每种通信方式又分为硬件和软件通信。
有几点说明,第一笔者所用硬件是基于STM32F1的。第二由于OLED的驱动函数都大同小异,所以本文只记录了各种驱动方式的初始化方法。方便我们根据手里的程序和OLED屏幕移植到到不同平台。

一、SPI通信

1、硬件SPI

待补充…

2、软件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 );
 }

之后还需要创建一个函数

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;   	  
} 

在这里插入图片描述
它是我们与设备通信的关键,可以根据对应通信方式的时序图来写。其中cmd参数为0时,函数将进行写命令操作,当cmd为1时,函数将进行写数据操作。
之后我们还需要调用该函数写命令操作对SSD1306进行一系列初始化操作。该步骤也可根据相应数据手册来写。

 	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

二、I2C通信

1、硬件I2C

硬件I2C有几点值得注意,一是配置引脚模式时,需要配置为开漏输出模式,二是通信函数需要调用库函数。
如下野火家的例程:

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、软件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);	
 }

同理根据I2C通信协议的时序图可以写一个写数据函数。
I2C完整数据传输时序图

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
}

猜你喜欢

转载自blog.csdn.net/weixin_44625313/article/details/103951928
今日推荐