• 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    四、终止信号

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

    void iic_stop()
    {
    	SCL = 1;
    	SDA = 0;
    	iic_delay();//5us
    	SDA = 1;
    	iic_delay();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    五、应答信号

    应答: 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    等待应答信号:

    unsigned char iic_wait_ack()
    {
    	SDA = 1;
    	SCL = 1;
    	_nop_();
    	
    	while (!SCL)//等待SCL拉高
    	if (SDA)
    	{
    		SCL = 0; //必须有一个时钟脉冲
    		return 1; //非应答
    	}
    
    	
    	SCL = 0; //必须有一个时钟脉冲
    	
    	return 0; //应答
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    六、数据收发

    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; //丢弃已传输的最高位
    	}	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    七、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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    八、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);
    
    • 1
    • 2

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

    oled_send_byte(0x78, 0x20, 0);
    oled_send_byte(0x78, 0x00, 0);
    
    • 1
    • 2

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

    oled_send_byte(0x78, 0x20, 0);
    oled_send_byte(0x78, 0x01, 0);
    
    • 1
    • 2

    九、OLED位置选择

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

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

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

    oled_send_byte(0x78, 0xB0, 0);
    
    • 1
    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);
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    十、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); //更新显示
    	} 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    十一、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);	    	
    		}
    	}
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    取模软件及参考资料

  • 相关阅读:
    GFD563A102 3BHE046836R0102 只读存储器本质上是非易失性的
    git init报错:‘git‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
    【内含接口】公众号查题:搭建属于自己的查题公众号
    java正则表达式用法总结
    Azure 机器学习 - 使用 Visual Studio Code训练图像分类 TensorFlow 模型
    突破亚马逊智能检测,全自动化运营的新利器:亚马逊鲲鹏系统
    还在写增删改查代码?直接一键生成
    P1650 田忌赛马,贪心,线性dp
    ClickHouse 原理解析之基础知识总结
    【OPENVX】对象基本使用之vx_matrix
  • 原文地址:https://blog.csdn.net/weixin_54178481/article/details/126888589