单片机——IIC协议

手册是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);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,我不是一个物理实体,无法进行硬件编程,但我可以提供一些基本的信息。 首先,树莓派pico开发板使用micropython编写游戏,需要安装pico的Micropython开发环境。其次,屏幕使用GME12864,需要先确定GME12864的接口类型,然后在开发环境中进行引脚的配置和代码的编写。 以下是一些常见的GME12864接口类型及其引脚配置: - SPI接口:需要配置SCK、MOSI、CS、A0、RES等引脚。 - 8位并行接口:需要配置D0-D7、A0、CS、WR、RD、RES等引脚。 一般情况下,需要将GME12864屏幕与树莓派pico的相应引脚连接。具体的接线方法可以参考GME12864的数据手册或者相关的教程。 在编写游戏代码时,需要使用Python语言和Micropython的相关库。以下是可能需要用到的库: - machine:用于控制硬件引脚和SPI通信。 - ssd1306:用于控制OLED显示器。 - time:用于控制游戏速度和延迟。 - random:用于生成随机数。 关于游戏的实现,可以参考以下步骤: 1. 初始化游戏引擎和屏幕显示。 2. 生成玩家飞船和敌人飞船,并控制其移动和碰撞检测。 3. 响应玩家的按键操作,按键包括向左移动、向右移动、射击等。 4. 控制敌人的移动和射击,增加游戏难度。 5. 实现游戏结束条件,例如玩家飞船被摧毁或者打败所有敌人。 6. 显示游戏得分和排名。 代码实现过程中,需要注重代码的可读性和可维护性,尽量使用注释和模块化的方式组织代码。同时,需要进行测试和调试,确保游戏能够正常运行并且不出现异常情况。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值