基于52单片机的I2C和OLED的使用

基于52单片机的OLED模块SS1306 和I2C的使用方法,用于日后再做参考使用,可能存在诸多不准确的地方。

1,I2C驱动程序

1.1 start:
在解决雪花问题中的视频是在起始程序加上了scl=0;scl=1.经过思考,每次stop之后衔接了star程序,在结束程序上需要表达完整,所以还可以在结束程序中加入 scl=0/sda=0; 这样终止和启动的界限清晰。也可以在启动程序中加上SDA=0,sda=1;

void I2C_start ()
{   
	SCL =0;
	SCL =1;
	SDA=1;
	_nop_();
	SDA=0;
	_nop_();
	SCL=0;
}

1.2 stop

void I2C_stop()
{
	SDA=0;
	SCL =0;
	SCL =1;
	_nop_();
	SDA=1;
	_nop_();
	
}

1.3 ack

char  I2C_ack()
{
  char  num=0;
	SCL=0;
  SDA=1;

  SCL=1;
  _nop_();
  while (SDA)//卡住等待接收数据方的接收成功反馈
  {
	if (++num>250)//等待250个机器周期
    {
	     I2C_stop();//250个机器周期后没有接收的响应,停止发送当前的8个字节。
	     return 1;
	  } 
  }
   return 0;
}

1.4 发送一个字节

void  I2C_sendbyte(char databyte)
{
	char i;
	for (i=0;i<8;i++)
	{
		SCL=0;
		SDA=databyte&0X80;//只保留最高位的数据,一次发送一位数据,每次发送最高位数据
		_nop_();
		SCL=1;
		_nop_();
		SCL=0;
		_nop_();
		databyte=databyte << 1;
	}
}

总结:上面是I2C的通用驱动程序。其他的模块就是基于此进行设计发送/接收数据,可以将其分包为OLED.h。

2,OLED SS1306的使用方法

在这里插入图片描述
2.1 向oled模块发送数据/指令的流程
这个流程的顺序:
启动start+发送连接地址slaver address+反馈ack +发送data/controy数据+反馈ack+终止stop
这里有两个新的东西,slaver address和ack +data/controy byte。

2.1.1向OLED发送一个command类型数据

(1)slaver address为7位地址,这里需要设置的程序员只有一个R/W选择位,模块的前7个从设备地址是说明书给出的,本模块的地址0111 100,还有一位是R/W选择位,这里是写数据R/W位设置位0,所以写入0x78。
代码如下:


void Oled_Write_Cmd(char CMD_data)
{
//1,start
	I2C_start ();
//2,先选择需要操作的从机,并告诉它是写入操作
	I2C_sendbyte(0x78);
//3,ack
	I2C_ack();
//4,写入的是指令还是数据,指令00000000数据01000000
	I2C_sendbyte(0x00);
//5,ack
	I2C_ack();
//6,写入指令
	I2C_sendbyte(CMD_data);
//7,ack
	I2C_ack();
//8,stop
	I2C_stop();

2.1.2向OLED发送一个DATA类型数据的流程

(2)data/controy byte,其组成为:C0+D/C+000000,C0在此处需设置为0,这里手册介绍写的设置为0,写入的只有数据。但是数据又分为指令和纯数据两种类型,云山雾绕不必纠结。所以真正需要关心的只有D/C位,置1就是写data,置0就是写command。所以 00000000:0x00是写指令,01000000:0x40是写数据。

代码如下:

void Oled_Write_Data(char DATA_data)
{
//1,start
	I2C_start ();
//2,先选择需要操作的从机,并告诉它是写入操作
	I2C_sendbyte(0x78);
//3,ack
	I2C_ack();
//4,写入的是指令还是数据,指令00000000数据01000000
	I2C_sendbyte(0x40);
//5,ack
	I2C_ack();
//6,写入数据
	I2C_sendbyte(DATA_data);
//7,ack
	I2C_ack();
//8,stop
	I2C_stop();
}

2.2 在OLED屏幕上正确的位置写入正确的内容的流程
2.2.1 最基本的案例就是在屏幕上显示一条线

void main ()
{
//1.led初始化,这是固定的,直接套用
OLED_init();
//2.设置显示位置
//2.1设置页模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
//清屏,清除上次的数据缓存
Oled_Clear();
//2.2设置行列位置
//页地址,可以设置
Oled_Write_Cmd(0xB0);
//列地址,可以设置
Oled_Write_Cmd(0x10);
Oled_Write_Cmd(0x00);
//3.写入数据,页模式每次写入的对象是纵向的8个像素点
Oled_Write_Data(0xff);
while (1);
}

Oled_Write_Cmd(0xB0+i); //页地址,一个页实际是8个纵向的像素点,SS1306有8个页分区,所以在一个纵列上有8*8=64个像素点
Oled_Write_Cmd(0x00); //写入命令0xH(避免混淆以H代替0X,这里的x表示0-f),分区内像素点的位置落定,分区内16个像素点0x00-0x0f
Oled_Write_Cmd(0x10); //写入命令1xH(避免混淆以H代替0X,这里的x表示0-f),列分区的位置落定,SS1306有8个列分区,每个列分区16个像素点

显示一条线已经基本可以理解OLED 模块的使用方法,不解析显示文字和图片的案例,直接参考显示文字和显示图片的代码案例。
显示文字,或者图片需要使用到取模软件,需要注意取模软件也会出现错误。

2.2.2 在OLED屏幕上显示文字,本案例中的文字是“小杨可以的”

(1)源文件
I.I2C.c

#include "reg52.h"
#include  "intrins.h"

sbit SCL=P0^1;
sbit SDA=P0^3;

//启动函数
void I2C_start ()
{   
	SCL =0;
	SCL =1;
	SDA=1;
	_nop_();
	SDA=0;
	_nop_();
	SCL=0;
}

//结束函数
void I2C_stop()
{
	SDA=0;
	SCL =0;
	SCL =1;
	_nop_();
	SDA=1;
	_nop_();
	
}
//应答函数
char  I2C_ack()
{
  char  num=0;
	SCL=0;
  SDA=1;

  SCL=1;
  _nop_();
  while (SDA)
  {
	if (++num>250)
    {
	     I2C_stop();
	     return 1;
	  } 
  }
   return 0;
}
//发送数据
void  I2C_sendbyte(char databyte)
{
	char i;
	for (i=0;i<8;i++)
	{
		SCL=0;
		SDA=databyte&0X80;
		_nop_();
		SCL=1;
		_nop_();
		SCL=0;
		_nop_();
		databyte=databyte << 1;
	}
}

II.OLED.c

#include "reg52.h"
#include "I2C.h"

//写入一个指令
void Oled_Write_Cmd(char CMD_data)
{
//1,start
	I2C_start ();
//2,oled子地址和选择读写
	I2C_sendbyte(0x78);
//3,ack
	I2C_ack();
//4,指令还是数据,指令00000000数据01000000
	I2C_sendbyte(0x00);
//5,ack
	I2C_ack();
//6,写入指令
	I2C_sendbyte(CMD_data);
//7,ack
	I2C_ack();
//8,stop
	I2C_stop();
}
//star 和stop 不需要ACK。


//写入一个数据
void Oled_Write_Data(char DATA_data)
{
//1,start
	I2C_start ();
//2,oled子地址和选择读写
	I2C_sendbyte(0x78);
//3,ack
	I2C_ack();
//4,指令还是数据,指令00000000数据01000000
	I2C_sendbyte(0x40);
//5,ack
	I2C_ack();
//6,写入数据
	I2C_sendbyte(DATA_data);
//7,ack
	I2C_ack();
//8,stop
	I2C_stop();
}

//OLED初始化
void OLED_Init()
{
Oled_Write_Cmd(0xAE);//--display off
Oled_Write_Cmd(0x00);//---set low column address
Oled_Write_Cmd(0x10);//---set high column address
Oled_Write_Cmd(0x40);//--set start line address
Oled_Write_Cmd(0xB0);//--set page address
Oled_Write_Cmd(0x81); // contract control
Oled_Write_Cmd(0xFF);//--128
Oled_Write_Cmd(0xA1);//set segment remap
Oled_Write_Cmd(0xA6);//--normal / reverse
Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
Oled_Write_Cmd(0x3F);//--1/32 duty
Oled_Write_Cmd(0xC8);//Com scan direction
Oled_Write_Cmd(0xD3);//-set display offset
Oled_Write_Cmd(0x00);//
Oled_Write_Cmd(0xD5);//set osc division
Oled_Write_Cmd(0x80);//
Oled_Write_Cmd(0xD8);//set area color mode off
Oled_Write_Cmd(0x05);//
Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
Oled_Write_Cmd(0xF1);//
Oled_Write_Cmd(0xDA);//set com pin configuartion
Oled_Write_Cmd(0x12);//
Oled_Write_Cmd(0xDB);//set Vcomh
Oled_Write_Cmd(0x30);//
Oled_Write_Cmd(0x8D);//set charge pump enable
Oled_Write_Cmd(0x14);//
Oled_Write_Cmd(0xAF);//--turn on oled panel
}

//oled设置为页模式
void I2C_Pagemode()
{
  Oled_Write_Cmd(0x20); 
	Oled_Write_Cmd(0x02); 
}
//OLED清屏
void Oled_Clear()
{
		unsigned char i;
		unsigned char j;
		for (i=0;i<8;i++)
		{
			  Oled_Write_Cmd(0xB0+i); 
				Oled_Write_Cmd(0x00); 
				Oled_Write_Cmd(0x10); 
      //写页
			//写列
				for(j=0;j<128;j++)
				{
				Oled_Write_Data(0);
				}
			

		}
}

(2)头文件
I.I2C.h

void I2C_start ();
void I2C_stop();
char  I2C_ack();
void  I2C_sendbyte(char databyte);

II.OLED.h

void Oled_Write_Cmd(char CMD_data);
void Oled_Write_Data(char DATA_data);
void Oled_Clear();
void OLED_Init();

(3). main.c

#include "reg52.h"
#include "I2C.h"
#include "OLED.h"
/*
使用的取模软件:“点阵液晶取模.EXE”
在实操中发现取模软件给到的信息存在排序错误?可能需要调整文字格式,本次问题是手工再排序解决的,
取模软件还存在本次的代码和上一次生成的代码关联的问题,关闭软件重启可以避免。
本次使用宋体常规14,软件提示原本宽高19x19,调整为宽高24x19,实际为16x19.
*/
code char XIAO[]= 
{
0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,0x40,0xFE,0xFE,0xFE,0x00,0xC0,0xC0,0x80,0x00,0x00,0x00,0x00,
0x00,0x30,0x18,0x1E,0x07,0x03,0x01,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x01,0x07,0x1F,0x1E,0x1C,0x00
};
code char YANG[]=
{

0x00,0x10,0x10,0xF0,0xFF,0xFF,0x90,0x18,0x96,0xC2,0xE2,0xF2,0xBA,0x9E,0x8E,0x86,0x80,0x80,0x00,
0x20,0x38,0x1E,0x07,0xFF,0xFF,0x27,0x37,0x9B,0xDD,0x6F,0x7B,0xBD,0x0F,0x87,0xFF,0xFF,0x3F,0x00
};
code char KE[]=
{
0x04,0x04,0x04,0xE4,0xE4,0x24,0x24,0x24,0xE4,0xE4,0xE4,0x04,0x04,0xFC,0xFC,0x04,0x06,0x06,0x00,
0x00,0x00,0x00,0x3F,0x3F,0x08,0x08,0x08,0x3F,0x3F,0x1F,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00
};
code char YI[]=
{
0x00,0x00,0x0C,0xFC,0xFC,0x04,0x00,0x18,0x78,0xF0,0x60,0x00,0x00,0xFE,0xFE,0x3E,0x00,0x00,0x00,
0x00,0x00,0x60,0xFF,0xFF,0x70,0x38,0x18,0x8C,0x84,0xC0,0xE0,0x7C,0x3F,0x7F,0xE0,0xE0,0xC0,0x00
};
code char DE[]=
{
0x00,0x00,0xF0,0xF0,0x1F,0x1F,0xF3,0xF0,0xF0,0xE0,0xFC,0x3F,0x1F,0x12,0x10,0xF0,0xF0,0xF0,0x00,
0x00,0x00,0xFF,0xFF,0x82,0x82,0xFF,0xFF,0xFF,0x01,0x03,0x1F,0x1E,0x08,0x80,0xFF,0xFF,0x03,0x00
};

void wenzi(char *WENZI,char mun1,char mun2)//mun2调整0X10改变分区,mun1调整0x00,改变分区内具体的16个像素的哪个起点。
{
  unsigned char i,j;
		  for (i=0;i<2;i++)
	  	{
						Oled_Write_Cmd(0xB0+i); //页地址,一个页实际是8个纵向的像素点,SS1306有8个页分区,所以在一个纵列上有8*8=64个像素点
						Oled_Write_Cmd(0x00+mun1); //写入命令0xH(避免混淆以H代替0X,这里的x表示0-f),分区内像素点的位置落定,分区内16个像素点0x00-0x0f
						Oled_Write_Cmd(0x10+mun2); //写入命令1xH(避免混淆以H代替0X,这里的x表示0-f),列分区的位置落定,SS1306有8个列分区,每个列分区16个像素点
						for(j=19*i;j<(19*(i+1));j++)
						{
						Oled_Write_Data( WENZI[j]);
						}

	  	}

  

}

void main ()
{
//1.led初始化
  OLED_init();
  2.设置页模式
	I2C_Pagemode();
	//模式设置好了可以进行清屏,清理上次的数据缓存
	Oled_Clear();
	//写数据,下面的函数内已经包含了重要的页地址,列地址。
  wenzi(XIAO,0,0);
  wenzi(YANG,5,1);
  wenzi(KE,12,2);
  wenzi(YI,0,4);
  wenzi(DE,5,5);
	while (1);
}

2.2.3 在OLED上显示图片
将像素与OLED模块匹配的图片投入取模软件生成数据代码,这里使用的是案例图片,像素为宽x长为128x64。
本案例对比显示文字的案例只在主程序main.c中有不同,引用的源文件和头文件与显示文字的案例相同,这里不再赘述。

#include "reg52.h"
#include "I2C.h"
#include "OLED.h"

code char Paint[]= 
{
0x00,0x00,0x80,0xC0,0xE0,0xF0,0xF0,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF0,0xF0,
0xF0,0xE0,0xE0,0x60,0x70,0x70,0x30,0x30,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x1C,
0x0C,0x1C,0x1C,0x1C,0x18,0x18,0x18,0x18,0x18,0x30,0x30,0x30,0x60,0x60,0xE0,0xE0,
0xE0,0xF0,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF8,0xF0,0xF0,0xE0,0xC0,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x3E,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x1F,0x1F,0x07,0x07,0x03,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x01,0x03,0x07,0x0F,0x1F,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,
0x7F,0x00,0x00,0x00,0x00,0x00,0xF0,0xF0,0x70,0x30,0x30,0x30,0xF0,0xE0,0x00,0x00,
0x40,0xE0,0x70,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0xF0,0xF0,0x70,0x30,
0x30,0x70,0xF0,0xE0,0x00,0x00,0xC0,0xE0,0x70,0x30,0x30,0x30,0x30,0x74,0xFF,0xFF,
0x00,0x00,0x00,0xE0,0xF0,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x03,0x07,0x0F,0x1F,0xFF,0xFF,0x0F,0x01,0x00,0x00,0x00,0x80,0xE0,0xF0,
0xF8,0xF8,0xFC,0xFC,0x7E,0x7E,0x7E,0xFE,0xFC,0xF8,0x60,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0xF8,0xFC,0xFC,0xFE,0x7E,0xFE,0xFC,0xF8,
0xF8,0xF0,0xE0,0x80,0x00,0x00,0x00,0x01,0x0F,0xFF,0xFF,0x1F,0x0F,0x07,0x03,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x60,0x60,0xE0,0x60,0x7F,0x3F,0x02,0x00,
0x38,0x7D,0xFE,0x66,0xE6,0x66,0x76,0x7F,0x7F,0x00,0x00,0x00,0x7F,0x7F,0x00,0x00,
0x00,0x00,0x7F,0x7F,0x00,0x00,0x1F,0x3F,0x7A,0x60,0xE0,0xE0,0x60,0x78,0x7F,0x7F,
0x00,0x00,0x38,0x7D,0x7F,0xE6,0x46,0x66,0x76,0x7F,0x7F,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xE0,0x00,0x00,0x00,0x3E,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0x1F,0x03,0x00,0x00,0x00,0x60,0xF0,0xF8,
0xF8,0xF8,0xF0,0xF0,0x70,0x00,0x00,0x00,0x07,0x3F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0x7F,0x00,0x00,0x80,0xE0,0xFF,0x3F,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x0F,0x1C,0x38,0x60,0xE0,0xC1,0x81,
0x83,0x03,0x03,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x03,0x83,
0x83,0x83,0xC1,0xE0,0x70,0x38,0x1C,0x0F,0x03,0x80,0x80,0xA0,0xB0,0xB8,0xFC,0xF7,
0xF7,0x92,0x94,0xDC,0xF8,0xD0,0xC0,0x40,0x00,0x00,0x00,0xC0,0xC2,0x46,0xFC,0x40,
0x00,0x10,0x70,0xC7,0x9E,0xC0,0xFE,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xF0,
0xA0,0xB0,0xB3,0xFF,0xB2,0x90,0xB0,0xF0,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x80,0x80,0x84,0x84,0x84,0x86,0xB6,0xE6,0x96,0x8E,0x86,0x86,0xC0,0xC0,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x3F,0xFF,0xFF,0x7F,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0x7C,0x0C,0x0C,0x0C,0x0C,0x0C,
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xFC,0xFC,0xFE,0xFE,0xFE,0xFE,0xFF,0x7F,0xFF,
0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x18,0x89,0x8C,0x96,0xB7,0xD5,0xD6,
0xD6,0xD6,0xDF,0xD7,0xCE,0x5C,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x40,0x7F,0xB0,
0xD8,0x6C,0x30,0x19,0x0F,0x1F,0x78,0xE0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x08,0x1F,
0x0C,0x0D,0x0C,0x7F,0xC4,0x84,0x86,0x87,0x80,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,
0x01,0x01,0x01,0x01,0x31,0x60,0xC0,0xFF,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x0F,0x7F,0xF8,0xE1,0xE1,0xC1,0xC1,0x81,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0xC1,0x81,0xC1,0xE1,0xF5,0xFE,0x1F,
0x01,0x00,0x00,0xE0,0xC0,0x60,0x60,0xC0,0xC0,0x00,0x01,0xE1,0xC1,0x61,0x61,0xC1,
0xC1,0x81,0x01,0x01,0xE1,0xE0,0x60,0x60,0xC0,0x80,0x00,0x60,0xF8,0xF8,0x40,0x01,
0xC1,0xE0,0x60,0x60,0xE0,0xC0,0x00,0x01,0xFD,0xF9,0x00,0xF8,0xFC,0x80,0xC0,0xE0,
0x60,0x00,0x00,0x00,0x01,0x01,0x01,0xC1,0xC1,0x61,0x61,0x61,0xE0,0xC0,0x00,0xC0,
0xE0,0x60,0x60,0x60,0xC0,0x00,0x01,0xE1,0xE0,0x60,0x60,0xE0,0xC0,0x60,0x60,0xE0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x03,0x0F,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x03,0x07,0x03,0x03,
0x03,0x03,0x02,0x03,0x03,0x07,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x0F,0x07,0x00,0x00,
0x00,0x00,0x00,0xFF,0xFF,0x10,0x30,0x1F,0x0F,0x00,0x00,0xFF,0xBC,0x10,0x30,0x1F,
0x1F,0x0F,0x00,0x22,0xFF,0x18,0x10,0x10,0x1F,0x0F,0x00,0x00,0x1F,0x1F,0x10,0x08,
0x1E,0x1E,0x13,0x1B,0x1F,0x1F,0x00,0x00,0x1F,0x1F,0x00,0x1F,0x1F,0x03,0x07,0x1E,
0x18,0x00,0x00,0x18,0x18,0x00,0x04,0x0F,0x1D,0x30,0x10,0x10,0x1C,0x1C,0x00,0x0F,
0x1F,0x10,0x30,0x18,0x1F,0x07,0x00,0x1F,0x1F,0x00,0x00,0x1F,0x1F,0x00,0x00,0x1F
};

void ShowPaint(char *WENZI)//mun2调整0X10改变分区,mun1调整0x00,改变分区内具体的16个像素的哪个起点。
{
   	unsigned char i; 
	unsigned int j;
		  for (i=0;i<8;i++)
	  	{
						Oled_Write_Cmd(0xB0+i); //页地址,一个页实际是8个纵向的像素点,SS1306有8个页分区,所以在一个纵列上有8*8=64个像素点
						Oled_Write_Cmd(0x00); //写入命令0xH(避免混淆以H代替0X,这里的x表示0-f),分区内像素点的位置落定,分区内16个像素点0x00-0x0f
						Oled_Write_Cmd(0x10); //写入命令1xH(避免混淆以H代替0X,这里的x表示0-f),列分区的位置落定,SS1306有8个列分区,每个列分区16个像素点
						for(j=128*i;j<(128*(i+1));j++)
						{
						Oled_Write_Data(WENZI[j]);
						}
	  	}
}

void main ()
{
//1.led初始化
   OLED_Init();
  //2.设置页模式
	I2C_Pagemode();
	//模式设置好了可以进行清屏,清理上次的数据缓存
	Oled_Clear();
	//写数据,下面的函数内已经包含了重要的页地址,列地址。
  ShowPaint(Paint);
	while (1);
}



下面内容为I2C slave address的参考文章

可以很好的了解它为何物。
一:I2C slave address

文章来源:https://blog.csdn.net/ranhui_xia/article/details/39494171

  1. 同一 I2C bus device 之 I2C slaver address 不可一样.
  2. 检查 这些 devices , 是否可以变更 I2C slaver address (hardware pin control or software register setting).
  3. 若相同 I2C slaver address 之 devices , 要一起使用, 则必须增加 IO pin (device enable signal, …) 以控制区隔 这些 devices.
    I2C设备地址
    协议格式中第一个字节(为slave address)由7位地址和一位R/W读写位组成的,这字节是个器件地址。

常用IIC接口通用器件的器件地址是由种类型号,及寻址码组成的,共7位。
如格式如下:
D7 D6 D5 D4 D3 D2 D1 D0
1、器件类型:D7-D4 共4位决定的。这是由半导公司生产时就已固定此类型的了,也就是说这4位已是固定的。

2、用户自定义地址码:D3-D1共3位。这是由用户自己设置的,通常的作法如EEPROM这些器件是由外部IC的3个引脚所组合电平决定的(用常用的名字如A0,A1,A2)。这也就是寻址码。所以为什么同一IIC总线上同一型号的IC只能最多共挂8片同种类芯片的原因了。

3、最低一位就是R/W位,,“0”表示写,“1”表示读(通常读写信号中写上面有一横线,表示低电平)。所以I2C设备通常有两个地址,即读地址和写地址
引用<<i2c 源代码情景分析>>里的话:“i2c 设备的7 位地址是就当前i2c 总线而言的,是“相对地址”。不同的i2c 总线上的设备可以使用相同的7 位地址,但是它们所在的i2c 总线不同。所以在系统中一个i2c 设备的“绝对地址”由二元组(i2c 适配器的ID 和设备在该总线上的7 位地址)表示。”,所以这个函数的作用主要是排除同一i2c总线上出现多个地址相同的设备。

二:I2C器件的从设备地址设置

文章来源:https://blog.csdn.net/zjy900507/article/details/79269952?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-1-79269952-blog-112313860.235%5Ev38%5Epc_relevant_anti_t3&spm=1001.2101.3001.4242.2&utm_relevant_index=4

I2C中24C02从地址设置
今天看了一下AT24C02的程序,发现“从设备地址”有点不明白,现在以AT24C02为例子说说我的见解。
首先,先看一下AT24C02的芯片资料,我们会发现AT24C02有三个地址A0,A1,A2。同时,我们会在资料的Device Address介绍发现I2C器件一共有七位地址码,还有一位是读/写(R/W)操作位,而在AT24C02的前四位已经固定为1010。R/W为1则为 读操作,为0则为写操作。R/W位我们要设置为0(写操作)
规则为:1010(A0)(A1)(A2)(R/W)
然后,看一下自己的设置PCB上的AT24C02的三位地址引脚的接法。
例子1:
那么对应的A0,A1,A2都是接的VCC,所以为A0=1,A1=1,A2=1;可以知道AT24C02的从设备写地址为10101110(0xae),读设备地址为10101111(0xaf);
在这里插入图片描述

例子2:
那么对应的A0,A1,A2都是接的GND,所以为A0=0,A1=0,A2=0;可以知道AT24C02的从设备写地址为10100000(0xa0),读设备地址为10100001(0xa1);
![在这里插入图片描述](https://img-blog.csdnimg.cn/53e56c4d95e4493bba5809ce5d7f9589.bmp#pic_center
在这里插入图片描述

哈哈,“从设备地址”就这么确定了,其实也很简单。

总结:
I2C的从机地址一般模块的说明书会给出,从机地址是模块的硬件工程师设定。
Slaver address的8位数据 :
D7-D4:固定的不可更改,芯片说明给出。
D3-D1:给模块的芯片A3-A1(管脚序号,一般对应D3-D1)的管脚接高/低电平来更改,所以同一种模块可以有8个从地址。
D0: 0是主设备向slaver写数据,1是从slaver中读数据。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值