IIC 通信协议之stm32 驱动OLED

前言

    使用stm32 驱动4 Pin 的OLED, 现在网上开源的资料多的是,但是为了锻炼自己使用第一手资料的能力,今天我还是从数据手册开始,从头造一波轮子,同时也是为了加深自己对 IIC 协议的理解 ,本系列内容我会从单片机和linux两个板子做一些OLED的 验证,希望后面大家在学习IIC 相关内容的时候,可以少走一些弯路。为了大家学习方面,这些文章也会在我的微信公众号同步,方便大家随时查看,欢迎大家扫码关注。

在这里插入图片描述

1. 查阅数据手册

   在我们实际工作中,需要我们从头造轮子的机会其实并不多,但是作为搞嵌入式这个行业的,阅读一些简单的数据手册的能力还是要有的,万一碰到碰到一个比较棘手的问题,说不定就需要我们不得不去看芯片的参考手册了。本篇我就以4Pin 的OLED 使用的SSD1306为例,通过stm32 实现对他的驱动。

  我们 打开他的数据手册,首先不要被全英文的吓到了,现在网上各种的翻译软件都比较给力。再说了,这个手册其实并不需要从头到尾一字不落的读完,首先我们看一下芯片的简单说明,了解芯片的大致的特性。
  
  其次:根据自己选择的芯片,使用的通讯方式,着重去看相对应的章节,比如我们本次使用的就是4 Pin的 IIC通信的,所以我们直接去找参考手册中介绍IIC 的.

在这里插入图片描述
a. IIC 从机地址是有SA0 决定的,并且R/W# 决定是读取数据还是写入数据。R/W# = 0 为写模式,R/W# = 1 为读数据。

IIC 通信协议:
在这里插入图片描述
S 信号 和 P 信号:
在这里插入图片描述
ACK 信号 和NAck 信号:
在这里插入图片描述
数据传输的时候要保证SDA 总线上数据稳定:
在这里插入图片描述
发送数据还是命令室友D/C# 引脚决定的: D/C# = 1 发送data , D/C# = 0 发送的是命令;

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

SSD 1306 显存大小: 128列 * 64行

在这里插入图片描述
如果要驱动SSD1306 首先要实现IIC 总线的驱动代码,即IIC 协议的实现,如果使用的是stm32单片机 来驱动的话,其实可以直接使用硬件IIC,当然了软件IIC也是可以的,本篇我们就先以软件模拟IIC来驱动他。

2. 软件模拟IIC 实现

2.1

#define SCL_Pin GPIO_Pin_6
#define SDA_Pin GPIO_Pin_7
#define IIC_GPIO_Port GPIOB


#define OLED_SCLK_LOW   GPIO_ResetBits(GPIOB,GPIO_Pin_6)
#define OLED_SCLK_HIGH  GPIO_SetBits(GPIOB,GPIO_Pin_6)
#define OLED_SDA_LOW    GPIO_ResetBits(GPIOB,GPIO_Pin_7)
#define OLED_SDA_HIGH   GPIO_SetBits(GPIOB,GPIO_Pin_7)

void OLED_Config(void)
{              
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, 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(IIC_GPIO_Port, &GPIO_InitStructure);
}

/*IIC  起始信号*/
void i2c_start()
{
    OLED_SCLK_HIGH;

    OLED_SDA_HIGH;
    OLED_SDA_LOW;

    OLED_SCLK_LOW;
}

/*IIC 停止信号*/
void i2c_stop()
{
    OLED_SCLK_HIGH;

    OLED_SDA_LOW;
    OLED_SDA_HIGH;
    
}

/*等待应答:提供一个scl 时钟周期*/
void i2c_wait_ack(void)
{
    OLED_SCLK_HIGH;
    OLED_SCLK_LOW;
}

void Write_IIC_Byte(unsigned char IIC_Byte)
{
	unsigned char i;
	unsigned char m,da;
	da=IIC_Byte;
	OLED_SCLK_LOW;
	for(i=0;i<8;i++)		
	{
		m=da;
		m=m&0x80;
		if(m==0x80)
		{
			OLED_SDA_HIGH;
		}
		else 
			OLED_SDA_LOW;
		da=da<<1;
		OLED_SCLK_HIGH;
		OLED_SCLK_LOW;
	}
}

/**********************************************
// IIC Write Command
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command)
{
	i2c_start();
	Write_IIC_Byte(0x78);       //Slave address,SA0=0
	i2c_wait_ack();	
	Write_IIC_Byte(0x00);		//write command
	i2c_wait_ack();	
	Write_IIC_Byte(IIC_Command); 
	i2c_wait_ack();	
	i2c_stop();
}

/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
	i2c_start();
	Write_IIC_Byte(0x78);			//D/C#=0; R/W#=0
	i2c_wait_ack();	
	Write_IIC_Byte(0x40);			//write data
	i2c_wait_ack();	
	Write_IIC_Byte(IIC_Data);
	i2c_wait_ack();	
	i2c_stop();
}

void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
	if(cmd)
	{
		Write_IIC_Data(dat);
	}
	else 
	{
		Write_IIC_Command(dat);	
	}
}

3. OLED 设备驱动程序


void OLED_Init(void)
{ 
 	OLED_Config();
 	GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);	

	delay_ms(100);
	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(1 to 64)
	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
}  


void OLED_Set_Pos(unsigned char x, unsigned char y)
{
	OLED_WR_Byte(0xb0+y,OLED_CMD);
	OLED_WR_Byte(((x&0xF0) >> 4)|0x10, OLED_CMD);
	OLED_WR_Byte( (x&0x0F), OLED_CMD);
}

void OLED_Display_On(void)
{
	OLED_WR_Byte(0x8D,OLED_CMD);  //设置电荷泵
	OLED_WR_Byte(0x14,OLED_CMD);  //开启电荷泵
	OLED_WR_Byte(0xAF,OLED_CMD);  //OLED唤醒
}

void OLED_Display_Off(void)
{
	OLED_WR_Byte(0x8D,OLED_CMD);	//设置电荷泵
	OLED_WR_Byte(0x10,OLED_CMD);    //关闭电荷泵
	OLED_WR_Byte(0xAE,OLED_CMD);    //关闭屏幕显示
}
				    
void OLED_Clear(void)
{
	u8 i = 0, n = 0; 
	
	for(i = 0; i < 8; i++)
	{
		OLED_WR_Byte(0xb0+i,OLED_CMD);	//设置页地址
		OLED_WR_Byte(0x00,OLED_CMD);    // 设置显示位置-列低地址
		OLED_WR_Byte(0x10,OLED_CMD);    // 设置显示位置-列高地址
		for(n = 0; n < 128; n++) OLED_WR_Byte(0,OLED_DATA);
	}
}


void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 Char_size)
{
	unsigned char c = 0, i = 0;
	c = chr - ' ';
	
	if(x > 128 - 1)
	{
		x = 0;
		y += 2;
	}
	
	if(Char_size == 8)
	{
	    OLED_Set_Pos(x,y);
		for(i = 0; i < 8; i++)
		 OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);		//显示低字节
		
		OLED_Set_Pos(x,y+1);
		for(i = 0; i < 8; i++ )
		  OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);   //显示高字节
	}
	else 
	{
		 字体为6号
		OLED_Set_Pos(x,y);
		for(i=0;i<6;i++)
			OLED_WR_Byte(F6x8[c][i],OLED_DATA);
	}
}

void OLED_ShowString(u8 x, u8 y,u8* chr, u8 Char_size)
{
	while(*chr != '\0')
	{
		OLED_ShowChar(x,y,*chr, Char_size);
		x+=Char_size;
		
		if(x > 120)
		{
			x = 0;
			y += 2;
		}	
		chr++;
	}
}


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值