32开发板实现硬件I2C及OLED显示

IIC通信原理

IIC总线物理层特点

 总线通过上拉电阻接到电源。当IIC设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态,由上拉电阻把总线拉成高电平。        

多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定哪个设备占用总线。      

 具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模式下可达3.4M/s,但目前大多IIC设备尚不支持高速模式。一般情况下使用的都是400kbit/s

硬件IIC

 硬件IIC:对应芯片上的IIC外设,有相对应的IIC驱动电路,其所使用的IIC管教也是专用的;      

软件IIC

  软件IIC:一般是用GPIO管教,用软件控制管脚状态以及模拟IIC通信波形;

区别

硬件IIC的效率要远高于软件的,而软件IIC不受引脚限制,接口比较灵活。            

软件IIC是通过GPIO,软件模拟寄存器的工作方式,而硬件IIC是直接调用内部寄存器进行配置。

如果要从具体硬件上来看,可以去看下芯片手册。因为固件IIC的端口是固定的,所以会有所区别。

区分

1.硬件IIC用法复杂,模拟IIC流程更加清楚

2.硬件IIC速度比模拟快,并且可以用DMA

3.模拟IIC可以在任何管脚上,硬件IIC在固定管脚上

IIC总线协议层

S:数据由主机传输至从机                 

P :数据传输结束                              

SLAVE ADDRESS : 从机地址 起始信号产生后,所有从机就开始紧接下来广播的从机地址信号。IIC总线,每个设备的地址都是唯一的,当主机广播的地址与某个设备的地址相同时,这个设备就被选中了,没被选中的设备讲会忽略之后的数据信号。根据IIC协议,这个从机地址可以是7位或10位。      

地址位之后,传输方向选择位,为0:表示数据传输方向是由主机传输至从机,即主机向从机写数据。为1:则相反。从机接收传输方向选择位后,主机或从机会返回一个应答(ACK)或非应答(NACK)信号,只有接收到应答信号后,主机才能继续发送或接收数据。

读数据:          配置方向传输位为”读数据”方向。广播完地址后,接收到应答信号后,从机开始向主机返回数据(DATA),数据包大小也为8位,从机每发送完一个数,都会等待主机的应答信号(ACK),重复这个过程,可以返回N个数据,N没有限制大小。当主机希望停止接收数据时,就向从机返回一个非应答信号(NCAK),则从机自动停止数据传输。

复合格式,该传输过程有两次起始信号(S),在第一次传输过程中,主机通过SLAVE_ADDRESS寻找到从设备后,发送一段”数据”,这段数据通常用于表示从设备内部的寄存器或存储器地址;第二次传输中,对该地址的内容进行读或写。也就是说,第一次通讯是告诉从机读写地址,第二次则是读写的实际内容。

IIC通信

空闲状态

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

开始信号

起始信号:当SCL为高电平期间,SDA有高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。

停止信号

停止信号:当SCL为高电平期间,SDA由低到高的跳变;停止信号也是一种高电平跳变时序信号,而不是一个电平信号

应答信号

发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位) 表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。      对于反馈有效应答位ACK的要求是,接收器在第九个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。      如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。

数据的有效性

 IIC总线进行数据传输时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。SDA数据线在SCL的每个时钟周期传输一位数据。    

即:数据在SCL的上升沿到来之前就需准备好。并在下降沿到来之前必须稳定  

数据传输

在IIC总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。

主发送器

控制产生起始信号(S),当发生起始信号后,它产生事件”EV5”,并会对SR1寄存器的 SB 位置1,表示起始信号已经发生。      ·

发生设备地址并等待应答信号,若有从机应答,则产生时间 EV6 及 EV8 ,这时SR1寄存器的 ADDR位及 TXE位被置1,ADDR位1 表示地址已经发送,TEX表示数据寄存器为空。 

OLED屏幕 

OLED即有机发光管(Organic Light-Emitting Diode,OLED)。OLED显示技术具有自发光、广视角、几乎无穷高的对比度、较低功耗、极高反应速度、可用于绕曲性面板、使用温度范围广、构造及制程简单等有点,被认为是下一代的平面显示屏新兴应用技术。 ·   OLED显示和传统的LCD显示不同,其可以自发光,所以不需要背光灯,这使得OLED显示屏相对于LCD显示屏尺寸更薄,同时显示效果更优。 常用的OLED屏幕有蓝色、黄色、白色等几种。屏的大小为0.96寸,像素点为 128*64,所以我们称为0.96oled屏或者12864屏。

OLED屏幕特点

1.模块尺寸:23.7 *23.8mm 2.电源电压:3.3-5.5V 3.驱动芯片:SSD1306 4.测试平台:提供       k60/k10,9s12XS128,51,stm32,stm8等单片机  

OLED屏幕常用指令

命令0X81: 设置对比度。包含两个字节,第一个0X81为命令,随后方法是的一个字节要设置这个对比度,值越大屏幕越亮。     ·

命令0XAE/0XAF: 0XAE为关闭显示命令,0XAF为开启显示命令    

0X8D: 包含两个字节,第一个为命令字,第二个为设置值,第二个字节的BIT2表示电荷泵的开关状态,该位为1开启电荷泵,为0则关闭。模块初始化的时候,这个必须要开启,否则看不到屏幕显示。    

命令0XB0~B7:用于设置页地址,其低三位的值对应GRAM页地址。     ·

命令0X00~0X0F:用于设置显示时的起始列地址低四位。    

命令0X10~0X1F: 用于设置显示时的起始列地址高四位。

代码实现

GPIO初始化

void I2C_Configuration(void)
{

    I2C_InitTypeDef   I2C_InitStructure;
    GPIO_InitTypeDef   GPIO_InitStructure;
	
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,  ENABLE);
   RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE );
	
	//PB6 --SCL ;PB7 --SDA
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Pin   =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

	
  I2C_DeInit(I2C1);
  I2C_InitStructure.I2C_Ack  =  I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress =  I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = 400000 ; 
	I2C_InitStructure.I2C_DutyCycle  = I2C_DutyCycle_2 ;
	I2C_InitStructure.I2C_Mode =  I2C_Mode_I2C;
	I2C_InitStructure.I2C_OwnAddress1 = 0X30 ;
	I2C_Init(I2C1,&I2C_InitStructure );
  I2C_Cmd(I2C1,ENABLE);

}

写一个字节

void I2C_WriteByte(uint8_t addr,uint8_t data)
{

    while (I2C_GetFlagStatus(I2C1,  I2C_FLAG_BUSY));  //¼ì²éI2C×ÜÏßÊÇ·ñ·±Ã¦
	
    I2C_GenerateSTART(I2C1,  ENABLE);                //¿ªÆôI2C1
    while( !I2C_CheckEvent(I2C1,  I2C_EVENT_MASTER_MODE_SELECT)); //EV5,Ö÷ģʽ
	
	 I2C_Send7bitAddress(I2C1,OLED_ADDRESS, I2C_Direction_Transmitter); //·¢ËÍÆ÷¼þµØÖ·
	 while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

	 I2C_SendData(I2C1,  addr);   //¼Ä´æÆ÷µØÖ·
   while(!I2C_CheckEvent(I2C1,  I2C_EVENT_MASTER_BYTE_TRANSMITTING));

	I2C_SendData(I2C1,  data);   //·¢ËÍÊý¾Ý
	 while(!I2C_CheckEvent(I2C1,  I2C_EVENT_MASTER_BYTE_TRANSMITTING));

  I2C_GenerateSTOP( I2C1,  ENABLE); //¹Ø±ÕI2C×ÜÏß


}

写数据

void WriteDat(unsigned char I2C_Data)
{

   I2C_WriteByte(0x40,I2C_Data);


}

写命令

void WriteCmd(unsigned char I2C_Command)
{
  
   I2C_WriteByte(0X00,I2C_Command);


}

OLED屏幕初始化

这个是厂家提供的代码直接使用即可

void OLED_Init(void)
{
  delay_ms(100);
	WriteCmd(0xAE); //display off
	WriteCmd(0x20);	//Set Memory Addressing Mode	
	WriteCmd(0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	WriteCmd(0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
	WriteCmd(0xc8);	//Set COM Output Scan Direction
	WriteCmd(0x00); //---set low column address
	WriteCmd(0x10); //---set high column address
	WriteCmd(0x40); //--set start line address
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //ÁÁ¶Èµ÷½Ú 0x00~0xff
	WriteCmd(0xa1); //--set segment re-map 0 to 127
	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
	WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
	WriteCmd(0xf0); //--set divide ratio
	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
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--turn on oled panel


}

设置起始坐标

void OLED_SetPos(unsigned char x,unsigned char y)
{
   WriteCmd(0xb0 +y);
	 WriteCmd((x&0xf0)>>4|0x10);
	 WriteCmd((x&0x0f)|0x01);

}

全屏填充

void OLED_Fill(unsigned char Fill_Data)
{
    unsigned char m,n;
	 for(m=0;m<8;m++)
	{
		WriteCmd(0xb0+m);
		WriteCmd(0x00);
		WriteCmd(0x10);
		
			for(n=0;n<128;n++)
			{
					WriteDat(Fill_Data);
			}
	}
}

清屏

void OLED_CLS(void)
{
   OLED_Fill(0x00);
}

OLED打开

void OLED_ON(void)
{
   WriteCmd(0X8D);  //ÉèÖõçºÉ±Ã
	 WriteCmd(0X14);  //¿ªÆôµçºÉ±Ã
	 WriteCmd(0XAF);  //OLED»½ÐÑ
  

}

OLED关闭

void OLED_OFF(void)
{
   WriteCmd(0X8D);  //ÉèÖõçºÉ±Ã
	 WriteCmd(0X10);  //¹Ø±ÕµçºÉ±Ã
	 WriteCmd(0XAE);  //¹Ø±ÕOLED


}

 显示字符串

void OLED_ShowStr(unsigned char x,unsigned y,unsigned char ch[],unsigned TextSize)
{
    unsigned char c = 0,i = 0,j = 0;
	  switch(TextSize)
		{
			case 1:
			{
				while(ch[j] != '\0')
				{
				   c = ch[j] - 32;
					if(x>126)
					{
					    x= 0;
						  y++;
					
					}
					OLED_SetPos(x,y);
					for(i=0;i<6;i++)
           WriteDat( F6x8[c][i] );
					x+=6 ;
					j++;
					
					}
				
				}break;
			case 2:
			{
			   while(ch[j] !='\0')
				 {
						 c= ch[j] - 32;
					 if(x >120)
					 {
							 x = 0;
							 y++ ;
					 }
					 OLED_SetPos(x,y);
					 for(i = 0;i<8;i++)
					 WriteDat( F8X16[c*16+i] );
					 OLED_SetPos(x,y+1);
					 for(i = 0;i<8;i++)
					 WriteDat( F8X16[c*16+i+8] );
					 x+=8;
					 j++;
			 }
				 
		}break;
			
		}
}		  

显示汉字

这个需要一个软件PCtoLCD2002,128x64取字软件

点击模式选择字符模式

点击选项,按照以下方式配置

完成后,点击确定

输入你想生成的内容,并点击生成字模

将其复制到自己的代码中,

void OLED_ShowCN(unsigned char x,unsigned char y,unsigned char N)
{
    unsigned char wm=0;
	  unsigned int addr = 32*N;//Ò»¸ö×ÖÓÐ32λ±íʾ
		OLED_SetPos(x,y);
    for(wm=0;wm<16;wm++)
	{
		WriteDat( F16X16[addr]);
    addr +=1;
		
	}
	 OLED_SetPos(x,y+1);
   for(wm=0;wm<16;wm++)
	{
		WriteDat( F16X16[addr]);
    addr +=1;
		
	}


}

注意显示文字,主要看有几个字,在主函数的for循环中就循环几次,我这里显示是五个字,就循环五次

显示图片

随机选一张图片,最好是黑白的

右键点击编辑,画图

重新调整一下大小(统称为128x64),再点击文件另存为.bmp格式

点击打开,设置完成后,点击保存,把生成的txt文档当中的内容复制到自己的代码中

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)//È·¶¨ÊDz»ÊÇ8µÄ±¶Êý
		y = y1/8;
	else
		y = y1/8 +1;
	for(y=y0;y<y1;y++)
	{
				OLED_SetPos(x0,y);
       for(x=x0;x<x1;x++)
		{
		
				WriteDat(BMP[j++]);

		}
		
		
	}
	
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值