项目训练营模块学习---Oled屏幕

声明:本专题主要针对训练营的同学开设的,因为了解到大家对于一些常用模块还是不会使用,因此开设次专栏去给大家讲解,如何在项目中来快速入门一些模块,转载请注明出处。
作者:渣渣鑫

专题:OLED的使用说明

OLED介绍

OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。

OLED显示技术具有自发光的特性,采用非常薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,而且OLED显示屏幕可视角度大,并且能够节省电能,从2003年开始这种显示设备在MP3播放器上得到了应用。

LCD都需要背光,而OLED不需要,因为它是自发光的。这样同样的显示,OLED效果要来得好一些。以目前的技术,OLED的尺寸还难以大型化,但是分辨率确可以做到很高。

硬件配置

主要使用的IIC总线上的SDA数据线和SCL时钟线,这里接上拉电阻的目的是当iic总线处于空闲状态的时候,能够处于高电平状态。从图中我们可以看出来iic总线是支持多设备的。
在这里插入图片描述

软件配置(IIC协议层)

在配置IIC总线之前,我们需要先把相应的GPIO端口控制线打开

/***********************************  重写IIC时序  *****************************************************/
//初始化GPIO
/*SDA输出模式 PA3*/
void OLED_SDA_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_OLED_SDA, ENABLE);	/* 打开GPIO时钟 */
	GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	/* 开漏输出 */
	GPIO_Init(OLED_SDA_PORT, &GPIO_InitStructure);
}

/*SDA输入模式 PA3*/
void OLED_SDA_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_OLED_SDA, ENABLE);	/* 打开GPIO时钟 */
	GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  	/* // 浮空输入 */
	GPIO_Init(OLED_SDA_PORT, &GPIO_InitStructure);
}


先要简单了解SDA与SCL的作用:当SCL处于高电平的时候,SDA上面的数据必须保持稳定。只有当SCL为低电平的时候,才允许SDA线的数据发生变化。

时序图必须要能看懂!
大家要学会看时序图

1、启动信号配置:SCL高电平期间,SDA电平由高到低跳变,我们代码就是去模拟这个过程。

/*i2c 起始信号*/
void OLED_Start(void)
{
	OLED_SDA_OUT(); //sda线输出
	OLED_SCL_HIGH;
	OLED_SDA_HIGH;
	i2c_delay();
	/*当CLK为高时,SDA由高变为低*/
  	OLED_SDA_L0W;
	i2c_delay();
	/*将SCL电位拉低,钳住SCL线,准备发送地址数据*/
	OLED_SCL_L0W;
}

2、停止信号:当SCL为高电平期间,SDA由低电平变为高电平

/*i2c 停止信号*/
void OLED_Stop(void)
{
	OLED_SDA_OUT(); //sda线输出
	/*scl为高电平时,SDA由低电平变为高电平*/
	OLED_SDA_L0W;
	OLED_SCL_L0W;
	i2c_delay();
	OLED_SCL_HIGH;
	OLED_SDA_HIGH;
	i2c_delay();
}

3、空闲状态:当IIC总线的数据线SDA和时钟线SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

4、应答信号:发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。
应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
应答信号为高电平时,规定为非应答位NACK),一般表示接收器接收该字节没有成功。
在这里插入图片描述
检测应答:

  • SCL为高电平的时候可以读取SDA的状态,因此可以将SDA模式切换为输入模式,读取SDA引脚状态,0位应答,1位非应答

  • SCL为低电平允许数据发生变化

  • SDA:为高电平的时候可以占用总线,此时将SDA拉低,开始通信。当为低电平的时候,SDA已经被占用。
    SCL: SCL为高电平的时候要求数据稳定 SCL为低电平的时候允许数据改变
    在这里插入图片描述

等待应答的作用就是来判断SDA传给的是低电平还是高电平。


/*等待应答信号到来 (有效应答:从机第9个 SCL=0 时 SDA 被从机拉低,
                            并且 SCL = 1时 SDA依然为低)
返回值: 1,接收应答失败
         0,接收应答成功*/

uint8_t OLED_WaitAck(void)
{
	uint8_t ucErrTime=0;
	OLED_SDA_IN(); //SDA设置为输入模式  (从机给一个低电平做为应答) 
	OLED_SDA_HIGH;i2c_delay();	   
	OLED_SCL_HIGH;i2c_delay();	
	//读取SDA的电平状态 
	while(OLED_SDA_Read)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			OLED_Stop();
			return 1;//接收应答失败
		}
	}
	OLED_SCL_L0W; //时钟输出0 	   
	return 0;  //接收应答成功
} 

有效应答和无效应答:

void OLED_Ack(void)
{
	OLED_SCL_L0W;
	OLED_SDA_OUT();
	OLED_SDA_L0W;
	i2c_delay();	
	OLED_SCL_HIGH;
	i2c_delay();	
	OLED_SCL_L0W;
}

void OLED_NAck(void)
{
	OLED_SCL_L0W;
	OLED_SDA_OUT();
	OLED_SDA_HIGH;
	i2c_delay();	
	OLED_SCL_HIGH;
	i2c_delay();	
	OLED_SCL_L0W;
}		

5、字节格式:
SDA数据线上的每个字节必须是8位,每次传输的字节数量没有限制。每个字节后必须跟一个响应位(ACK)。首先传输的数据是最高位(MSB),SDA上的数据必须在SCL高电平周期时保持稳定,数据的高低电平翻转变化发生在SCL低电平时期。

  • 每一个字节后面跟着一个ACK,有ACK就可以继续写或读。NACK,就停止

  • ACK:主机释放总线,传输完字节最后1位后的SCL的高电处,从机拉低电平。

  • NACK:主机释放总线,传输完字节最后1位后的SCL的高电处,从机无响应,总线为高电平。

发送数据:
在这里插入图片描述

/******************************************************************************
*函  数:void IIC_SendByte(uint8_t txd)
*功  能:IIC发送一个字节
*参  数:data 要写的数据
*返回值:无
*备  注:主机往从机发
*******************************************************************************/		  
void OLED_SendByte(uint8_t data)
{                        
    uint8_t t;   
	  OLED_SDA_OUT(); 	    
    OLED_SCL_L0W; //拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
      if((data&0x80)>>7)//0x80=1000 0000
				OLED_SDA_HIGH;
			else
				OLED_SDA_L0W;
      data<<=1;
			i2c_delay();			
		  OLED_SCL_HIGH;
		  i2c_delay();	
			OLED_SCL_L0W;	
		  i2c_delay();	
    }	 
} 	 

读取数据:

uint8_t OLED_ReadByte(uint8_t ack)
{
	uint8_t i,receive=0;
	OLED_SDA_IN(); //SDA设置为输入模式 等待接收从机返回数据
  for(i=0;i<8;i++ )
	{
     OLED_SCL_L; 
     i2c_delay();
		 OLED_SCL_H;
     receive<<=1;
     if(OLED_SDA_Read)receive++; //从机发送的电平
	   i2c_delay();
   }					 
    if(ack)
        OLED_Ack(); //发送ACK 
    else
        OLED_NAck(); //发送nACK  
    return receive;
}

总结:最难的时序部分代码完成后,就可以使用模拟的iic代码来完成oled屏幕代码的初始化了

oled配置代码(这个大家直接移植就行)

//初始化SSD1306		
// 端口用PA5,PA6
void OLED_Init(void)
{ 	
	
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能A端口时钟
	GPIO_InitStructure.GPIO_Pin = OLED_SCL_PIN|OLED_SDA_PIN;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOA, &GPIO_InitStructure);	  //初始化
 	GPIO_SetBits(GPIOA,OLED_SCL_PIN|OLED_SDA_PIN);
	
	
	delay_ms(800);
	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
}  


/********************************************
// fill_Picture
********************************************/
void fill_picture(unsigned char fill_Data)
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		OLED_WR_Byte(0xb0+m,0);		//page0-page1
		OLED_WR_Byte(0x00,0);		//low column start address
		OLED_WR_Byte(0x10,0);		//high column start address
		for(n=0;n<128;n++)
			{
				OLED_WR_Byte(fill_Data,1);
			}
	}
}


/***********************Delay****************************************/
void Delay_50ms(unsigned int Del_50ms)
{
	unsigned int m;
	for(;Del_50ms>0;Del_50ms--)
		for(m=6245;m>0;m--);
}

void Delay_1ms(unsigned int Del_1ms)
{
	unsigned char j;
	while(Del_1ms--)
	{	
		for(j=0;j<123;j++);
	}
}



//坐标设置

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); 
}   	  
//开启OLED显示    
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}		   			 
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		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_On(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA); 
	} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示				 
//size:选择字体 16/12 
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{      	
	unsigned char c=0,i=0;	
		c=chr-' ';//得到偏移后的值			
		if(x>Max_Column-1){x=0;y=y+2;}
		if(Char_Size ==16)
			{
			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 {	
				OLED_Set_Pos(x,y);
				for(i=0;i<6;i++)
				OLED_WR_Byte(F6x8[c][i],OLED_DATA);
				
			}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}				  
//显示2个数字
//x,y :起点坐标	
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); 
	}
} 




void OLED_Float(unsigned char Y,unsigned char X,double real,unsigned char N) 
{
   unsigned char   i_Count=1;
   unsigned char   n[12]={0};
   long   j=1;  
   int    real_int=0;
   double decimal=0;
   unsigned int   real_decimal=0;
   if(real<0)
	 {
		 real_int=(int)(-real);
	 }
	 else
	 {
		 real_int=(int)real;
   }
	 decimal=real-real_int;
   real_decimal=decimal*1e4;
   while(real_int/10/j!=0)
   {
      j=j*10;i_Count++;  
   } 
   n[0]=(real_int/10000)%10; 
   n[1]=(real_int/1000)%10;
   n[2]=(real_int/100)%10;
   n[3]=(real_int/10)%10;
   n[4]=(real_int/1)%10; 
   n[5]='.';
   n[6]=(real_decimal/1000)%10;
   n[7]=(real_decimal/100)%10;
   n[8]=(real_decimal/10)%10;
   n[9]=real_decimal%10;
   n[6+N]='\0'; 
   for(j=0;j<10;j++) n[j]=n[j]+16+32;
	 if(real<0) 
	 {		 
		 i_Count+=1;
		 n[5-i_Count]='-';
	 }
   n[5]='.';
   n[6+N]='\0';   
   OLED_ShowString(X,Y,&n[5-i_Count],12); 
}





//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
	unsigned char j=0;
	while (chr[j]!='\0')
	{		OLED_ShowChar(x,y,chr[j],Char_Size);
			x+=8;
		if(x>120){x=0;y+=2;}
			j++;
	}
}
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{      			    
	u8 t,adder=0;
	OLED_Set_Pos(x,y);	
    for(t=0;t<16;t++)
		{
				OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
				adder+=1;
     }	
		OLED_Set_Pos(x,y+1);	
    for(t=0;t<16;t++)
			{	
				OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
				adder+=1;
      }					
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{ 	
 unsigned int j=0;
 unsigned char x,y;
  
  if(y1%8==0) y=y1/8;      
  else y=y1/8+1;
	for(y=y0;y<y1;y++)
	{
		OLED_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
	    {      
	    	OLED_WR_Byte(BMP[j++],OLED_DATA);	    	
	    }
	}
} 

这里会用到一个子模库:
在这里插入图片描述

简单讲一下字模软件的使用吧(没有的找我要)

配置要正确
在这里插入图片描述
最后我把完整的工程代码给大家!如果前面都看不懂的,就按我这个配置来!

#include "./OLED/oled.h"
#include "oledfont.h" 
#include "./systick/bsp_systick.h"
#include "stdlib.h"	 

/*因为oled与6050的I2C引脚相同,所以oled要单独模拟I2C来用
	SCL----PA4
	SDA----PA5*/
	

/*宏定义*/
/*********************************************************************************/
#define RCC_OLED_SCL         RCC_APB2Periph_GPIOA  //端口时钟
#define OLED_SCL_PORT        GPIOA
#define OLED_SCL_PIN         GPIO_Pin_4

#define RCC_OLED_SDA         RCC_APB2Periph_GPIOA  //端口时钟
#define OLED_SDA_PORT        GPIOA
#define OLED_SDA_PIN         GPIO_Pin_5

/*********************************************************************************/
/*操作IO口*/
/*********************************************************************************/
#define OLED_SCL_L0W          (OLED_SCL_PORT->BRR = OLED_SCL_PIN)
#define OLED_SCL_HIGH         (OLED_SCL_PORT->BSRR = OLED_SCL_PIN)

#define OLED_SDA_L0W          (OLED_SDA_PORT->BRR = OLED_SDA_PIN)
#define OLED_SDA_HIGH         (OLED_SDA_PORT->BSRR = OLED_SDA_PIN)
/*读取电平状态,低电平返回0,高电平返回非0*/
#define OLED_SDA_Read         ((OLED_SDA_PORT->IDR &OLED_SDA_PIN) != 0)
/*********************************************************************************/

/*********************************************************************************/
/*简单的延时函数*/
static void i2c_delay(void)
{
   delay_us(4);
}	
/*********************************************************************************/

/*********************************************************************************/
/*先将SDA,SCL配置成开漏输出模式,再配置SDA的输入输出模式*/
/*i2c端口模式初始化
  SDA---->PA3
  SCL---->PA2
*/
//void i2c_MoniConfig(void)
//{
//	GPIO_InitTypeDef GPIO_InitStructure;
//	RCC_APB2PeriphClockCmd(RCC_OLED_SCL, ENABLE);	/* 打开GPIO时钟 */
//	GPIO_InitStructure.GPIO_Pin = OLED_SCL_PIN ;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	/* 开漏输出 */
//	GPIO_Init(OLED_SCL_PORT, &GPIO_InitStructure);
//	OLED_SCL_HIGH;
//	
//	RCC_APB2PeriphClockCmd(RCC_OLED_SDA, ENABLE); 	/* 打开GPIO时钟 */
//	GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	/* 开漏输出 */
//	GPIO_Init(OLED_SDA_PORT, &GPIO_InitStructure);
//	OLED_SDA_HIGH;
//}

/*SDA输出模式 PA3*/
void OLED_SDA_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_OLED_SDA, ENABLE);	/* 打开GPIO时钟 */
	GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	/* 开漏输出 */
	GPIO_Init(OLED_SDA_PORT, &GPIO_InitStructure);
}

/*SDA输入模式 PA3*/
void OLED_SDA_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_OLED_SDA, ENABLE);	/* 打开GPIO时钟 */
	GPIO_InitStructure.GPIO_Pin = OLED_SDA_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  	/* // 浮空输入 */
	GPIO_Init(OLED_SDA_PORT, &GPIO_InitStructure);
}
/*********************************************************************************/

/*i2c 起始信号*/
void OLED_Start(void)
{
	OLED_SDA_OUT(); //sda线输出
	OLED_SCL_HIGH;
	OLED_SDA_HIGH;
	i2c_delay();
	/*当CLK为高时,SDA由高变为低*/
  OLED_SDA_L0W;
	i2c_delay();
	/*将SCL电位拉低,钳住SCL线,准备发送地址数据*/
	OLED_SCL_L0W;
}

/*i2c 停止信号*/
void OLED_Stop(void)
{
	OLED_SDA_OUT(); //sda线输出
	/*scl为高电平时,SDA由低电平变为高电平*/
	OLED_SDA_L0W;
	OLED_SCL_L0W;
	i2c_delay();
	OLED_SCL_HIGH;
	OLED_SDA_HIGH;
	i2c_delay();
}

/*等待应答信号到来 (有效应答:从机第9个 SCL=0 时 SDA 被从机拉低,
                            并且 SCL = 1时 SDA依然为低)
返回值: 1,接收应答失败
         0,接收应答成功*/

uint8_t OLED_WaitAck(void)
{
	uint8_t ucErrTime=0;
	OLED_SDA_IN(); //SDA设置为输入  (从机给一个低电平做为应答) 
	OLED_SDA_HIGH;i2c_delay();	   
	OLED_SCL_HIGH;i2c_delay();	 
	while(OLED_SDA_Read)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			OLED_Stop();
			return 1;
		}
	}
	OLED_SCL_L0W; //时钟输出0 	   
	return 0;  
} 

void OLED_Ack(void)
{
	OLED_SCL_L0W;
	OLED_SDA_OUT();
	OLED_SDA_L0W;
	i2c_delay();	
	OLED_SCL_HIGH;
	i2c_delay();	
	OLED_SCL_L0W;
}

void OLED_NAck(void)
{
	OLED_SCL_L0W;
	OLED_SDA_OUT();
	OLED_SDA_HIGH;
	i2c_delay();	
	OLED_SCL_HIGH;
	i2c_delay();	
	OLED_SCL_L0W;
}		

/******************************************************************************
*函  数:void IIC_SendByte(uint8_t txd)
*功  能:IIC发送一个字节
*参  数:data 要写的数据
*返回值:无
*备  注:主机往从机发
*******************************************************************************/		  
void OLED_SendByte(uint8_t data)
{                        
    uint8_t t;   
	  OLED_SDA_OUT(); 	    
    OLED_SCL_L0W; //拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
      if((data&0x80)>>7)
				OLED_SDA_HIGH;
			else
				OLED_SDA_L0W;
      data<<=1;
			i2c_delay();			
		  OLED_SCL_HIGH;
		  i2c_delay();	
			OLED_SCL_L0W;	
		  i2c_delay();	
    }	 
} 	 

#define OLED_SCL_L   OLED_SCL_L0W
#define OLED_SCL_H   OLED_SCL_HIGH

/******************************************************************************
*函  数:uint8_t IIC_ReadByte(uint8_t ack)
*功  能:IIC读取一个字节
*参  数:ack=1 时,主机数据还没接收完 ack=0 时主机数据已全部接收完成
*返回值:无
*备  注:从机往主机发
*******************************************************************************/	
uint8_t OLED_ReadByte(uint8_t ack)
{
	uint8_t i,receive=0;
	OLED_SDA_IN(); //SDA设置为输入模式 等待接收从机返回数据
  for(i=0;i<8;i++ )
	{
     OLED_SCL_L; 
     i2c_delay();
		 OLED_SCL_H;
     receive<<=1;
     if(OLED_SDA_Read)receive++; //从机发送的电平
	   i2c_delay();
   }					 
    if(ack)
        OLED_Ack(); //发送ACK 
    else
        OLED_NAck(); //发送nACK  
    return receive;
}

void Write_IIC_Command(unsigned char IIC_Command)
{
	OLED_Start();
	OLED_SendByte(0x78);            //Slave address,SA0=0
	OLED_WaitAck();	
	OLED_SendByte(0x00);			//write command
	OLED_WaitAck();	
	OLED_SendByte(IIC_Command); 
	OLED_WaitAck();	
	OLED_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data)
{
	OLED_Start();
	OLED_SendByte(0x78);			//D/C#=0; R/W#=0
	OLED_WaitAck();	
	OLED_SendByte(0x40);			//write data
	OLED_WaitAck();	
	OLED_SendByte(IIC_Data);
	OLED_WaitAck();	
	OLED_Stop();
}
/*******************************************************************************************************************/





void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
	if(cmd)
			{

   Write_IIC_Data(dat);
   
		}
	else {
   Write_IIC_Command(dat);
		
	}
}


//初始化SSD1306		
// 端口用PA5,PA6
void OLED_Init(void)
{ 	
	
	GPIO_InitTypeDef  GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能A端口时钟
	GPIO_InitStructure.GPIO_Pin = OLED_SCL_PIN|OLED_SDA_PIN;	 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
 	GPIO_Init(GPIOA, &GPIO_InitStructure);	  //初始化
 	GPIO_SetBits(GPIOA,OLED_SCL_PIN|OLED_SDA_PIN);
	
	
	delay_ms(800);
	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
}  


/********************************************
// fill_Picture
********************************************/
void fill_picture(unsigned char fill_Data)
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		OLED_WR_Byte(0xb0+m,0);		//page0-page1
		OLED_WR_Byte(0x00,0);		//low column start address
		OLED_WR_Byte(0x10,0);		//high column start address
		for(n=0;n<128;n++)
			{
				OLED_WR_Byte(fill_Data,1);
			}
	}
}


/***********************Delay****************************************/
void Delay_50ms(unsigned int Del_50ms)
{
	unsigned int m;
	for(;Del_50ms>0;Del_50ms--)
		for(m=6245;m>0;m--);
}

void Delay_1ms(unsigned int Del_1ms)
{
	unsigned char j;
	while(Del_1ms--)
	{	
		for(j=0;j<123;j++);
	}
}



//坐标设置

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); 
}   	  
//开启OLED显示    
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}		   			 
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		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_On(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA); 
	} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示				 
//size:选择字体 16/12 
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{      	
	unsigned char c=0,i=0;	
		c=chr-' ';//得到偏移后的值			
		if(x>Max_Column-1){x=0;y=y+2;}
		if(Char_Size ==16)
			{
			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 {	
				OLED_Set_Pos(x,y);
				for(i=0;i<6;i++)
				OLED_WR_Byte(F6x8[c][i],OLED_DATA);
				
			}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;	 
	while(n--)result*=m;    
	return result;
}				  
//显示2个数字
//x,y :起点坐标	
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
				continue;
			}else enshow=1; 
		 	 
		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); 
	}
} 




void OLED_Float(unsigned char Y,unsigned char X,double real,unsigned char N) 
{
   unsigned char   i_Count=1;
   unsigned char   n[12]={0};
   long   j=1;  
   int    real_int=0;
   double decimal=0;
   unsigned int   real_decimal=0;
   if(real<0)
	 {
		 real_int=(int)(-real);
	 }
	 else
	 {
		 real_int=(int)real;
   }
	 decimal=real-real_int;
   real_decimal=decimal*1e4;
   while(real_int/10/j!=0)
   {
      j=j*10;i_Count++;  
   } 
   n[0]=(real_int/10000)%10; 
   n[1]=(real_int/1000)%10;
   n[2]=(real_int/100)%10;
   n[3]=(real_int/10)%10;
   n[4]=(real_int/1)%10; 
   n[5]='.';
   n[6]=(real_decimal/1000)%10;
   n[7]=(real_decimal/100)%10;
   n[8]=(real_decimal/10)%10;
   n[9]=real_decimal%10;
   n[6+N]='\0'; 
   for(j=0;j<10;j++) n[j]=n[j]+16+32;
	 if(real<0) 
	 {		 
		 i_Count+=1;
		 n[5-i_Count]='-';
	 }
   n[5]='.';
   n[6+N]='\0';   
   OLED_ShowString(X,Y,&n[5-i_Count],12); 
}





//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
	unsigned char j=0;
	while (chr[j]!='\0')
	{		OLED_ShowChar(x,y,chr[j],Char_Size);
			x+=8;
		if(x>120){x=0;y+=2;}
			j++;
	}
}
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{      			    
	u8 t,adder=0;
	OLED_Set_Pos(x,y);	
    for(t=0;t<16;t++)
		{
				OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
				adder+=1;
     }	
		OLED_Set_Pos(x,y+1);	
    for(t=0;t<16;t++)
			{	
				OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
				adder+=1;
      }					
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{ 	
 unsigned int j=0;
 unsigned char x,y;
  
  if(y1%8==0) y=y1/8;      
  else y=y1/8+1;
	for(y=y0;y<y1;y++)
	{
		OLED_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
	    {      
	    	OLED_WR_Byte(BMP[j++],OLED_DATA);	    	
	    }
	}
} 

总结

以上就是oled屏幕和iic时序的全部讲解啦!
我想对训练营的同学说一下,态度决定成败!我为大家付出这么多,希望各位不要辜负我的努力。希望大家都能够将我安排的任务认真完成。

点赞+再看是对我最大的鼓励!!!

想学习更多知识可以加入我的公众号哈!
在这里插入图片描述
有想加入训练营的小伙伴可以私聊我哦!

  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仰望星空的鑫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值