单片机——IIC协议

该代码实现了一套I2C通信协议,用于向GME12864OLED显示屏发送数据和命令。通过ICC_Start()、ICC_Stop()、ICC_ACK()等函数处理开始信号、停止信号和应答信号。程序详细定义了写命令和写数据的操作,包括地址设置和数据传输时序。Oled_Init()和Oled_Clear()函数则分别用于初始化屏幕和清除显示内容。示例代码展示了如何显示特定的文字字符串。

手册是ssd1306

image.png

void ICC_Start()
{

	scl=0;//防止stop后scl没有变成低电平
	sda=1;
	scl=1;
	_nop_();//a->c
	sda=0;//b->c
	_nop_();//c->d

}

void ICC_Stop()
{
	scl=0;
	sda=0;

	scl = 1;
	_nop_();//a->b
	sda=1;//b->c
	_nop_();//c->d
}

应答信号

image.png

char ICC_ACK()
{

	char flag;
	sda = 1;//初始拉高
	_nop_();//延时等待
	scl = 1;//拉高
	_nop_();//等待sda变化
	flag = sda;//获得sda值
	_nop_();//确保获得完毕
	scl=0;//拉低
	_nop_();//这里我认为不用,但应该是确保scl拉低了

	return flag;
}

数据发送时序分析

image.png
数据发送是1bit1bit的发送的

void ICC_Send_Byte(char datas)
{
	int i=0;
	for(;i<8;i++)//有8位需要发送
	{
		scl=0;//拉低电平
		sda=datas & 0x80;//取得最高位
		_nop_();//数据建立延时
		scl=1;//拉高
		_nop_();//数据发送延时
		scl=0;//发送完毕
		_nop_();
		datas = datas<<1;
	}
	
}

写命令操作分析

image.png
由图片可知

  1. 先发送开始信号
  2. slave Address:由手册可知,有两种结果:“b0111100”或“b0111101”其中若R/W位为0,才是写入模式
  3. ACK
  4. 确定发送的是地址还是数据:根据手册可以知道,如果Co位需要为0,D/C位如果为0那么就是发送的是命令/地址否则为数据
  5. ACK
  6. 写入相应的地址/数据
  7. ACK
  8. STOP
void Oled_Write_Cmd(char cmd){
	//开始
	ICC_Start();
	//Slave Address 0111 1000 
	//对于SSD1306,
	//通过将SA0更改为LOW(低)或HIGH(高),
	//从属地址为“b0111100”或“b0111101”
	//(D/C引脚用作SA0)。
	ICC_Send_Byte(0x78);
	//ACK
	ICC_ACK();
	//指定写入的是命令还是数据
	//xx00 0000
	//写入命令:0000 0000
	ICC_Send_Byte(0x00);
	//ACK
	ICC_ACK();
	//写入命令
	ICC_Send_Byte(cmd);
	//ACK
	ICC_ACK();
	ICC_Stop();
}
//写数据
void Oled_Write_Data(char datas){
	//开始
	ICC_Start();
	//Slave Address 0111 1000 
	//对于SSD1306,
	//通过将SA0更改为LOW(低)或HIGH(高),
	//从属地址为“b0111100”或“b0111101”
	//(D/C引脚用作SA0)。
	ICC_Send_Byte(0x78);
	//ACK
	ICC_ACK();
	//指定写入的是命令还是数据
	//xx00 0000
	//指定为写入数据:0100 0000
	ICC_Send_Byte(0x40);
	//ACK
	ICC_ACK();
	//写入数据
	ICC_Send_Byte(datas);
	//ACK
	ICC_ACK();
	ICC_Stop();
}

在GME12864上显示一句话

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

sbit sda = P0^3;
sbit scl = P0^1;

void ICC_Start()
{
	scl=0;
	sda=1;
	scl=1;
	_nop_();
	sda=0;
	_nop_();
}

void ICC_Stop()
{
	scl=0;
	sda=0;
	scl=1;
	_nop_();
	sda=1;
	_nop_();
}

char ICC_ACK()
{

	char flag;
	
	sda = 1;//初始拉高
	_nop_();//延时等待
	scl = 1;//拉高
	_nop_();//等待sda变化
	flag = sda;
	_nop_();
	scl=0;
	_nop_();

	return flag;
}

void ICC_Send_Byte(char datas)
{
	int i=0;
	for(;i<8;i++)
	{
		scl=0;
		sda=datas & 0x80;
		_nop_();
		scl=1;
		_nop_();
		scl=0;
		_nop_();
		datas = datas<<1;
	}	
}
//写命令操作
void Oled_Write_Cmd(char cmd){
	//开始
	ICC_Start();
	//Slave Address 0111 1000 
	//对于SSD1306,
	//通过将SA0更改为LOW(低)或HIGH(高),
	//从属地址为“b0111100”或“b0111101”
	//(D/C引脚用作SA0)。
	ICC_Send_Byte(0x78);
	//ACK
	ICC_ACK();
	//指定写入的是命令还是数据
	
	//xx00 0000
	
	//写入命令:0000 0000
	ICC_Send_Byte(0x00);
	//ACK
	ICC_ACK();
	//写入地址
	ICC_Send_Byte(cmd);
	//ACK
	ICC_ACK();
	ICC_Stop();
}
//写数据
void Oled_Write_Data(char datas){
	//开始
	ICC_Start();
	//Slave Address 0111 1000 
	//对于SSD1306,
	//通过将SA0更改为LOW(低)或HIGH(高),
	//从属地址为“b0111100”或“b0111101”
	//(D/C引脚用作SA0)。
	ICC_Send_Byte(0x78);
	//ACK
	ICC_ACK();
	//指定写入的是命令还是数据
	
	//xx00 0000
	
	//指定为写入数据:0100 0000
	ICC_Send_Byte(0x40);
	//ACK
	ICC_ACK();
	//写入数据
	ICC_Send_Byte(datas);
	//ACK
	ICC_ACK();
	ICC_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
}
//清屏函数
void Oled_Clear()
{
	unsigned char i,j; //-128 --- 127
	for(i=0;i<8;i++){
		Oled_Write_Cmd(0xB0 + i);//page0--page7
		//每个page从0列
		Oled_Write_Cmd(0x00);
		Oled_Write_Cmd(0x10);
		//0到127列,依次写入0,每写入数据,列地址自动偏移
		for(j = 0;j<128;j++){
			Oled_Write_Data(0);
		}
	}
}

//点阵液晶工具自动生成
/*--  文字:  学  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char x1[16]={0x40,0x30,0x11,0x96,0x90,0x90,0x91,0x96,0x90,0x90,0x98,0x14,0x13,0x50,0x30,0x00};
code char x2[16]={0x04,0x04,0x04,0x04,0x04,0x44,0x84,0x7E,0x06,0x05,0x04,0x04,0x04,0x04,0x04,0x00};

/*--  文字:  习  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char xx1[16]={0x00,0x02,0x02,0x02,0x12,0x22,0xC2,0x02,0x02,0x02,0x02,0x02,0xFE,0x00,0x00,0x00};
code char xx2[16]={0x00,0x08,0x18,0x08,0x04,0x04,0x04,0x02,0x02,0x41,0x81,0x40,0x3F,0x00,0x00,0x00};

/*--  文字:  嵌  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char q1[16]={0x80,0x80,0xEE,0x88,0x88,0x88,0xE8,0x8F,0x08,0x88,0x78,0x48,0x4E,0x40,0xC0,0x00};
code char q2[16]={0x00,0x00,0x7F,0x24,0x24,0x24,0x7F,0x00,0x81,0x40,0x30,0x0F,0x30,0x41,0x80,0x00};

/*--  文字:  入  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char r1[16]={0x00,0x00,0x00,0x00,0x00,0x01,0xE2,0x1C,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
code char r2[16]={0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x00,0x03,0x0C,0x30,0x40,0x80,0x80,0x00};

/*--  文字:  式  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
code char s1[16]={0x10,0x10,0x90,0x90,0x90,0x90,0x90,0x10,0x10,0xFF,0x10,0x10,0x11,0x16,0x10,0x00};
code char s2[16]={0x00,0x20,0x60,0x20,0x3F,0x10,0x10,0x10,0x00,0x03,0x0C,0x10,0x20,0x40,0xF8,0x00};

void main(){
	int i;
	//初始化
	Oled_Init();
	//设置为页寻址模式
	Oled_Write_Cmd(0x20);
	Oled_Write_Cmd(0x02);
	Oled_Clear();
	Oled_Write_Cmd(0xB0);
    //这两个数据拼接起来就是第几列:
	Oled_Write_Cmd(0x00);//低4位
	Oled_Write_Cmd(0x10);//高4位
	
	for(i=0; i<16;++i){
		Oled_Write_Data(x1[i]);
	}
	for(i=0; i<16;++i){
		Oled_Write_Data(xx1[i]);
	}
	for(i=0; i<16;++i){
		Oled_Write_Data(q1[i]);
	}
	for(i=0; i<16;++i){
		Oled_Write_Data(r1[i]);
	}
	for(i=0; i<16;++i){
		Oled_Write_Data(s1[i]);
	}
	Oled_Write_Cmd(0xB1);
	Oled_Write_Cmd(0x00);//指定位置
	Oled_Write_Cmd(0x10);//指定位置
	
	for(i=0; i<16;++i){
		Oled_Write_Data(x2[i]);
	}
	for(i=0; i<16;++i){
		Oled_Write_Data(xx2[i]);
	}
	for(i=0; i<16;++i){
		Oled_Write_Data(q2[i]);
	}
	for(i=0; i<16;++i){
		Oled_Write_Data(r2[i]);
	}
	for(i=0; i<16;++i){
		Oled_Write_Data(s2[i]);
	}
	while(1);
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值