0.96OLED显示屏C51_IIC例程

本文详细介绍了IIC总线的基本原理与通信流程,并针对OLED显示器的应用场景,阐述了如何利用IIC总线进行数据传输、设置显示模式、进行屏幕定位与清屏等操作。此外还提供了丰富的示例代码,帮助读者快速掌握IIC与OLED的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、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);	    	
		}
	}
} 

取模软件及参考资料

### 0.96OLED显示屏在IT应用中的开发与驱动 #### 显示屏特性概述 0.96英寸OLED屏幕是一种自发光显示技术,具有高对比度、低功耗以及快速响应时间等特点[^1]。这种尺寸的显示器通常采用IIC/I2C或SPI接口连接到微控制器单元(MCU),适用于嵌入式项目和个人电子产品。 #### 开发环境搭建 为了实现对0.96OLED显示屏的有效控制,在开始编程之前需先设置好相应的硬件和软件平台: - **硬件准备**:确保拥有支持所需通信协议(如I2C/SPI)的MCU板卡;准备好必要的连线工具来建立从计算机至目标设备的数据传输路径。 - **软件安装**:对于Arduino IDE这样的集成开发环境来说,可以通过库管理器轻松获取官方或其他第三方提供的图形化界面库文件用于简化绘图操作[^2]。 ```cpp #include <Wire.h> #include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_SSD1306.h>// Hardware-specific library for SSD1306 drivers #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration required for using the Wire library functionality. #if (SSD1306_LCDHEIGHT != 64) #error("Height incorrect, please fix Adafruit_SSD1306.h!"); #endif ``` #### 驱动程序下载及配置 针对不同操作系统下的PC端应用程序开发需求,可以从制造商官方网站上查找并下载对应型号的OLED模块驱动包。这些资源往往包含了详细的API文档说明和技术支持材料以便开发者更好地理解和运用该组件的功能特性[^3]。 例如,如果使用的是基于Linux系统的Raspberry Pi,则可以利用Python语言配合`luma.oled`库来进行高效便捷的操作处理。 ```bash pip install luma.oled ``` ```python from luma.core.interface.serial import i2c from luma.core.render import canvas from luma.oled.device import ssd1306 serial = i2c(port=1, address=0x3C) device = ssd1306(serial) with canvas(device) as draw: draw.rectangle(device.bounding_box, outline="white", fill="black") draw.text((30, 40), "Hello World", fill="white") ``` #### 应用实例展示 通过上述介绍的方法完成初始化工作之后就可以着手构建实际应用场景了。比如智能家居控制系统里的人机交互界面设计或是便携式医疗检测仪器上的数据显示部分都可以考虑选用此类小型化的视觉呈现方案以达到节省空间成本的目的同时提供清晰直观的信息反馈给用户群体。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值