0.96OLED显示屏C51_IIC例程

一、iic总线概述

  1. iic总线只有两根双向信号线,一根是数据线SDA,一根是时钟线SCL

  2. iic总线是通过上拉电阻接正电源。当总线空闲时,两根线均为高电平

  3. 当连接到总线的任一器件输出低电平,都将使总线的信号拉低,即各器件的SDA和SCL到是线“与”关系
    在这里插入图片描述

二、iic通信流程

  1. 主设备发送起始信号
  2. 主设备接着发送8bit数据,其中高7位是从设备的地址,低一位 置一代表 读,置零 代表写
  3. 主设备读取从设备响应信号
  4. 数据传输
  5. 主设备读取从设备响应信号
  6. 循环N个4和5步骤完成通信
  7. 主设备发送停止信号

三、起始信号

SCL为高电平期间,SDA线由高电平向低电平变化
在这里插入图片描述

void iic_start()
{
	SCL = 1;
	SDA = 1;
	iic_delay();//5us
	SDA = 0;
	iic_delay();
}

四、终止信号

SCL为高电平期间,SDA线由低电平向高电平变化
在这里插入图片描述

void iic_stop()
{
	SCL = 1;
	SDA = 0;
	iic_delay();//5us
	SDA = 1;
	iic_delay();
}

五、应答信号

应答: SDA=0,可继续通信
非应答: SDA=1,结束通信
在这里插入图片描述
应答: ack等于1,应答; ack等于0,非应答

void iic_ack(bit ack)
{
	SCL = 0; // 拉低使SDA数据线可以变化
	_nop_(); 

	if (ack == ACK)	//应答ACK=1
	{
		SDA = 0;
		_nop_(); //确保确保总线处于释放状态
	}
	else //非应答
	{
	 	SDA = 1;
		_nop_(); //确保确保总线处于释放状态
	}
	
	SCL = 1;	//产生一个大于4us的脉冲
	iic_delay();//5us
	SCL = 0;
}

等待应答信号:

unsigned char iic_wait_ack()
{
	SDA = 1;
	SCL = 1;
	_nop_();
	
	while (!SCL)//等待SCL拉高
	if (SDA)
	{
		SCL = 0; //必须有一个时钟脉冲
		return 1; //非应答
	}

	
	SCL = 0; //必须有一个时钟脉冲
	
	return 0; //应答
}

六、数据收发

  1. IIC总线进行数据传输时,时钟信号SCL高电平器件,数据线SDA上的数据必须保持稳定
  2. 只有在时钟线SCL位低电平期间,数据线SDA上的高、低电平状态才允许数据变化
  3. 输出到SDA线上的每个字节必须是8位,按位传输,从高位到低位,每一个被传送的字节后面都必须跟随一位应答位
    在这里插入图片描述

数据收发过程:先拉低SCL,在改变SDA,最后拉高SCL
4. SCL = 0;
5. SDA = 0; 或 SDA = 1;
6. SCL = 1;

void iic_send_byte(unsigned char da)
{
	char i;

	for(i = 0; i < 8; i++)
	{
		SCL = 0;
		_nop_();
		if (da & 0x80) //获取最高位
		{
			SDA = 1;
		}
		else
		{
			SDA = 0;
		}
			
		_nop_();

		SCL = 1;
		_nop_();
		SCL = 0;
		
		da <<= 1; //丢弃已传输的最高位
	}	
}

七、OLED发送数据

在这里插入图片描述
高七位为从机地址;低一位为1,读模式,为0,写模式

在这里插入图片描述

SA0: 通过将SA0更改为低或高的SA0,从机地址为“b0111100”或“b0111101”,(D/C引脚充当SA0)。可实现两个设备,显示不同内容
Co: 如果Co位被设置为逻辑“0”,则以下信息的传输将只包含数据字节
D/C:如果D/C#位设置为逻辑“0”,则会将以下数据字节定义为命令。如果D/C#位被设置为逻辑“1”,那么它会将以下数据字节定义为将存储在GDDRAM中的数据 (显示数据)
数据发送流程
1.发送 起始信号
2. 发送 从机地址(0x78 : 0111 1000)(0:写模式)
3. 等待应答信号
4. 发送数据内容标志 (命令:0x00:0(Co)0(D/C)00 0000,显示数据:0x40:0(Co)1(D/C)00 0000
5. 发送数据
6. 发送 终止信号

//addr: 从机地址 0.96OLED: 0x78(写模式)
//da: 数据
//mode: 1 写数据;0 写命令
void oled_send_byte(unsigned int addr, unsigned char da, char mode)
{
	iic_start();
	send_byte(addr);//从机地址

	iic_wait_ack(); 
	if (mode) {send_byte(0x40);}//写数据
  	else {send_byte(0x00);}  //写命令

	iic_wait_ack();
	send_byte(da);
	iic_wait_ack();
	iic_stop();
}

八、OLED选址模式

OLED分辨率为128*64,每8行作为一个PAGE

页选址模式
在页面寻址模式下,读写显示RAM后,列地址指针自动递增1。如果列地址指针到达列结束地址,则列地址指针被重置为列起始地址,并且页面地址指针不被更改。用户需要设置新的页面和列地址,以访问下一页的RAM内容。(页地址重置后,列地址不会自动重置,列保持递增)
在这里插入图片描述
水平选址模式
在水平寻址模式下,读写显示RAM后,列地址指针自动递增1。如果列地址指针到达列结束地址,则列地址指针重置为列起始地址,页地址指针增加1。
在这里插入图片描述
垂直选址模式
在垂直寻址模式下,读写显示RAM后,页面地址指针自动递增1。如果页面地址指针到达页面结束地址,则页面地址指针将重置页面开始地址,列地址指针将增加1。
在这里插入图片描述

在这里插入图片描述
发送两个命令指定选址模式:
页选址: 发送命令0x20和0x02 (默认)

oled_send_byte(0x78, 0x20, 0);
oled_send_byte(0x78, 0x02, 0);

水平选址: 发送命令 0x20和0x00

oled_send_byte(0x78, 0x20, 0);
oled_send_byte(0x78, 0x00, 0);

垂直选址: 发送命令 0x20和0x01

oled_send_byte(0x78, 0x20, 0);
oled_send_byte(0x78, 0x01, 0);

九、OLED位置选择

1. 页选址模式 设置 页起始地址

在这里插入图片描述
PAGE0~PAGE7 页地址使用 X[2:0] 指定

例:指定第一页,发送指令 0xB0

oled_send_byte(0x78, 0xB0, 0);
2. 页选址模式 设置 列起始地址

在这里插入图片描述
设置的列数 = Lower + Higher * 16
例:设置列数为100 = 4 + 6*16
即发送指令 0x04 和 0x16

3. 位置选择
void oled_set_pos(unsigned char x, unsigned char y) 
{ 
	oled_send_byte(0x78, 0xb0+y, 0);
	oled_send_byte(0x78, ((x&0xf0)>>4)|0x10, 0);
	oled_send_byte(0x78, (x&0x0f), 0);
} 

十、OLED清屏(页选址模式)

void oled_clear()  
{  
	unsigned char i,n;		    
	for(i = 0; i < 8; i++)  
	{  
		oled_send_byte(0x78, 0xb0+i, 0);    //设置页地址(0~7)
		oled_send_byte(0x78, 0x00, 0);      //设置显示位置—列低地址
		oled_send_byte(0x78, 0x10, 0);      //设置显示位置—列高地址   
		for(n = 0; n < 128; n++)oled_send_byte(0x78, 0, 0); //更新显示
	} 
}

十一、OLED显示函数参考

//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63				 
//sizey:选择字体 6x8  8x16
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey)
{      	
	u8 c=0,sizex=sizey/2;
	u16 i=0,size1;
	if(sizey==8)size1=6;
	else size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
	c=chr-' ';//得到偏移后的值
	OLED_Set_Pos(x,y);
	for(i=0;i<size1;i++)
	{
		if(i%sizex==0&&sizey!=8) OLED_Set_Pos(x,y++);
		if(sizey==8) OLED_WR_Byte(asc2_0806[c][i],OLED_DATA);//6X8字号
		else if(sizey==16) OLED_WR_Byte(asc2_1608[c][i],OLED_DATA);//8x16字号
//		else if(sizey==xx) OLED_WR_Byte(asc2_xxxx[c][i],OLED_DATA);//用户添加字号
		else return;
	}
}
				  
//显示数字
//x,y :起点坐标
//num:要显示的数字
//len :数字的位数
//sizey:字体大小		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey)
{         	
	u8 t,temp,m=0;
	u8 enshow=0;
	if(sizey==8)m=2;
	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+(sizey/2+m)*t,y,' ',sizey);
				continue;
			}else enshow=1;
		}
	 	OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);
	}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey)
{
	u8 j=0;
	while (chr[j]!='\0')
	{		
		OLED_ShowChar(x,y,chr[j++],sizey);
		if(sizey==8)x+=6;
		else x+=sizey/2;
	}
}
//显示汉字
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey)
{
	u16 i,size1=(sizey/8+((sizey%8)?1:0))*sizey;
	for(i=0;i<size1;i++)
	{
		if(i%sizey==0) OLED_Set_Pos(x,y++);
		if(sizey==16) OLED_WR_Byte(Hzk[no][i],OLED_DATA);//16x16字号
//		else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号
		else return;
	}				
}


//显示图片
//x,y显示坐标
//sizex,sizey,图片长宽
//BMP:要显示的图片
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[])
{ 	
  u16 j=0;
	u8 i,m;
	sizey=sizey/8+((sizey%8)?1:0);
	for(i=0;i<sizey;i++)
	{
		OLED_Set_Pos(x,i+y);
    for(m=0;m<sizex;m++)
		{      
			OLED_WR_Byte(BMP[j++],OLED_DATA);	    	
		}
	}
} 

取模软件及参考资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值