智能语音时钟–0.96寸OLED屏幕的使用

IIC协议0.96寸OLED屏幕使用教程

目录

IIC协议0.96寸OLED屏幕使用教程

1. 介绍

2. OLED屏幕原理

3. IIC协议基础

4. IIC时序图解

5. 如何连接0.96寸OLED屏幕

5.1 所需材料

5.2 连接步骤

6. 使用代码示例

7. 结论

视频链接

1. 介绍

0.96寸OLED屏幕是一种小型的显示设备,常用于电子项目中。它使用IIC(I2C)通信协议进行数据传输,具有低功耗、高对比度的优点。本文将介绍OLED屏幕的原理、IIC协议的基础知识以及如何使用这些屏幕。

2. OLED屏幕原理

OLED(有机发光二极管)是一种自发光显示技术,不需要背光。每个像素由有机材料组成,当电流通过时会发光。由于每个像素都是独立的光源,因此OLED屏幕具有高对比度和广视角的特点。

0.96寸OLED屏是128*64的屏幕,在OLED中将64分成8页,每页中有8行数据,OLED显示数据的方式是将先选定页再选定列然后逐个读或写数据。

OLED的页和页内的行

下图是显示数据在OLED上的样子,可以看到一个中文的显示分为两页,每页的不同行的电平不一样,最终实现一个文字在OLED上显示出来。

OLED屏幕一共有三种寻址方式,分别是页面寻址,水平寻址和垂直寻址。

所谓寻址方式就是数据写入方式,以水平寻址为例参考水平寻址的图片,假设要显示一张图片到OLED屏上,我们将数据从第一页的第一列开始填,填入的顺序是每一行的从左往右填入,当填入到每一行的最后一列时此时后续填入的数据会自动换到下一行,直到64行数据都被填满,此时就能显示一张图片,如果64行填满后还是有数据填入的话,新加入的数据就会回到第一页的第一列的位置覆盖到原先的数据,这就是水平寻址的方式,页面寻址和垂直寻址和水平寻址差不多,参考图片和水平寻址的方式去理解即可。

3. IIC协议基础

IIC(Inter-Integrated Circuit)是一种串行通信协议,广泛应用于微控制器与外围设备之间的数据传输。它使用两根线:SDA(数据线)和SCL(时钟线)。

  • SDA(Serial Data Line):用于传输数据。
  • SCL(Serial Clock Line):用于同步数据传输的时钟信号。
  • IIC是一种主从协议,一个主设备(如微控制器)可以控制多个从设备(如OLED屏幕)。每个从设备有一个唯一的地址,主设备通过这个地址与从设备通信。

    4. IIC时序图解

    (1)IIC信号时序:

    ①开始信号和结束信号:

                            

    ②应答信号和非应答信号:

            ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​  

    ③读和写一个字节:

            ​​​​​​​ 

    (2)IIC通信过程包括以下几个步骤:

    ①主机写从机读:

    1. 开始信号(Start Condition):SDA线在SCL线为高电平时发生跳变。
    2. 地址传输:主设备发送从设备的地址和读位。
    3. 确认位(ACK):从设备接收地址后,返回一个电平作为确认。
    4. 数据/命令寄存器地址:主设备发送从设备寄存器的地址。
    5. 确认位(ACK):从设备接收地址后,返回一个电平作为确认。
    6. 数据/命令传输:主设备发送数据/命令。
    7. 确认位(ACK):从设备接收地址后,返回一个电平作为确认。
    8. 停止信号(Stop Condition):SDA线在SCL线为高电平时发生跳变。

    程序

    ②主机读从机写:

    1. 开始信号(Start Condition):SDA线在SCL线为高电平时发生跳变。
    2. 地址传输:主设备发送从设备的地址和写位。
    3. 确认位(ACK):从设备接收地址后,返回一个电平作为确认。
    4. 数据/命令寄存器地址:主设备发送从设备寄存器的地址。
    5. 确认位(ACK):从设备接收地址后,返回一个电平作为确认。
    6. 停止信号(Stop Condition):SDA线在SCL线为高电平时从低变。
    7. 开始信号(Start Condition):SDA线在SCL线为高电平时发送跳变。
    8. 地址传输:主设备发送从设备的地址和读/写位。
    9. 确认位(ACK):从设备接收地址后,返回一个电平作为确认。
    10. 数据/命令传输:主设备读取数据/命令。
    11. 确认位(ACK):从设备接收地址后,返回一个电平作为确认。
    12. 停止信号(Stop Condition):SDA线在SCL线为高电平时从低变

    OLED地址

    OLED屏幕模块默认地址是0x78,如果要换成0x7A就需要将电阻重新焊接到右侧位置即可。

    5. 如何连接0.96寸OLED屏幕

    5.1 所需材料
  • 0.96寸OLED屏幕
  • 微控制器(如stm32等)
  • 连接线
  • 5.2 连接步骤
    1. 将OLED屏幕的VCC引脚连接到微控制器的3.3V电源。
    2. GND引脚连接到微控制器的地(GND)。
    3. SCL引脚连接到微控制器的SCL引脚。
    4. SDA引脚连接到微控制器的SDA引脚。

    6. 使用代码示例

    以stm32为例,使用模拟IIC协议来控制OLED屏幕。

    .c文件

    #include "oled.h"
    #include "stdlib.h"
    #include "oledfont.h"  	 
    #include "bsp_SysTick.h"
    
    int n2=0;
    void i2c_startup()
    {
    	sda_h;
    	Delay_us(1);
    	scl_h;
    	Delay_us(1);
    	sda_l;
    	Delay_us(1);
    	scl_l;
    	Delay_us(1);
    }
    
    void i2c_stopup()
    {
    	sda_l;
    	Delay_us(1);
    	scl_h;
    	Delay_us(1);
    	sda_h;
    	Delay_us(1);
    	scl_l;
    	Delay_us(1);
    
    }
    
    void ack_state(int ack_mask)
    {
    	if(ack_mask==0)
    	{
    		sda_l;
    	}
    	else
    		sda_h;
    	Delay_us(1);
    	scl_h;
    	Delay_us(1);
    	scl_l;
    	Delay_us(1);
    }
    
    int get_ack()
    {
    	int ack;
    	sda_h;
    	Delay_us(1);
    	scl_h;
    	Delay_us(1);
    	if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7) == RESET)
    	{
    		ack=0;
    	}else
    		ack=1;
    	scl_l;
    	Delay_us(1);
    
    	return ack;
    }
    
    
    int send_num(u8 num)
    {
    	int i;
    	char ack;
    	for(i=0;i<8;i++)
    	{
    		if(num&0x80)
    		{
    			sda_h;
    		}else
    			sda_l;
    		num<<=1;
    		scl_h;
    		Delay_us(1);
    		scl_l;
    		Delay_us(1);
    		
    	}
    	ack=get_ack();
       	 return ack;
    }
    
    u8 get_num(int state)
    {
    	int i;
    	u8 num=0;
    	for(i=0;i<8;i++)
    	{
    		sda_h;
    		Delay_us(1);
    		num <<= 1;
    		scl_h;
    		Delay_us(1);
    		if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_3) == SET)
    		{
    			num|=0x01;
    		}
    		scl_l;
    		Delay_us(1);
    	}
    	ack_state(state);
    	scl_l;
    	Delay_us(1);
    	return num;
    }
    
    //写入数据
    void Write_Data(unsigned char dat)
    {
    	i2c_startup();
    	send_num(0x78);      //写入oled地址
    	get_ack();
    	send_num(0x40);			 //写入命令地址
    	get_ack();
    	send_num(dat);			 //发送命令
    	get_ack();
    	i2c_stopup();
    }
    
    void Write_Command(unsigned char dat)
    {
       i2c_startup();
       send_num(0x78);            //Slave address,SA0=0
    	 get_ack();
       send_num(0x00);			//write command
    	 get_ack();
       send_num(dat);
    	 get_ack();
    	 i2c_stopup();
    }
    
    void OLED_writemode(unsigned dat,unsigned cmd)
    {
    	if(cmd)
       Write_Data(dat);
    	else
       Write_Command(dat);
    }
    
    
    
    //坐标设置
    void OLED_Set_Pos(unsigned char x, unsigned char y) 
    {
     	OLED_writemode(0xb0+y,OLED_CMD);
    	OLED_writemode((x&0x0f),OLED_CMD); 							 //计算出设置显示
    	OLED_writemode(((x&0xf0)>>4)|0x10,OLED_CMD);     //计算出设置显示位置—每一组中每一列的高地址位置—每一组中每一列的低地址
    }   	  
    
    		 
    //清屏函数,清完屏,整个屏幕是黑色的	  
    void OLED_Clear(void)  
    {  
    	char i,n;		    
    	for(i=0;i<8;i++)  
    	{  
    		OLED_writemode(0xb0+i,OLED_CMD);    //设置页地址(0~7),默认0页(0组)地址是0xb0
    		OLED_writemode(0x00,OLED_CMD);      //设置显示位置—每一组中每一列的低地址
    		OLED_writemode(0x10,OLED_CMD);      //设置显示位置—每一组中每一列的高地址   
    		for(n=0;n<128;n++)OLED_writemode(0,OLED_DATA);  //循环写入128列数据(都是0,相当于清屏)
    	} //更新显示
    }
    
    
    //在指定位置显示一个字符,包括部分字符
    //x:0~127
    //y:0~63
    //mode:0,反白显示;1,正常显示				 
    //size:选择字体 16/12 
    void OLED_ShowChar(char x,char y,char chr)
    {      	
    	  unsigned char c=0,i=0;	
    		c=chr-' ';																//得到偏移后的值,该值是根据头文件中符号对应的规律计算,空格是的ascii是32		
    		if(x>Max_Column-1){x=0;y=y+2;}						//+2是因为数据显示时每行数据实际上占两行,为了间距看起来正常需要将越界的数据偏移两行
    		OLED_Set_Pos(x,y);												//设置要写入的组号以及列的高低地址
    		for(i=0;i<8;i++)													//循环8次写入数据上半段
    		OLED_writemode(F8X16[c*16+i],OLED_DATA);
    		OLED_Set_Pos(x,y+1);											//下移一组
    		for(i=0;i<8;i++)												  //循环8次写入数据下半段
    		OLED_writemode(F8X16[c*16+i+8],OLED_DATA);
    			
    }
    
    
    //显示一个字符号串
    void OLED_ShowString(char x,char y,char *chr)
    {
    	unsigned char j=0;
    	while (chr[j]!='\0')
    	{		OLED_ShowChar(x,y,chr[j]); //写数据
    			x+=8;											 //+8是因为在x坐标写一次数据就占8个列,因此要写入下一个数据前必须进行位移
    		if(x>120){x=0;y+=2;}				 //+2是因为数据显示时每行数据实际上占两行,为了间距看起来正常需要将越界的数据偏移两行
    			j++;											 //数据下标后移
    	}
    }
    
    //初始化SSD1306					    
    void OLED_Init(void)
    { 	
    
    	GPIO_InitTypeDef PA;
    	
    	//使能时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    //	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    	
    	PA.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;
    	PA.GPIO_Mode = GPIO_Mode_Out_PP;
    	PA.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&PA);
    //	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7);
    
    	Delay_us(800000);
      OLED_writemode(0xAE,OLED_CMD);//--display off
    	OLED_writemode(0x00,OLED_CMD);//---set low column address
    	OLED_writemode(0x10,OLED_CMD);//---set high column address
    	OLED_writemode(0x40,OLED_CMD);//--set start line address  
    	OLED_writemode(0xB0,OLED_CMD);//--set page address
    	OLED_writemode(0x81,OLED_CMD); // contract control
    	OLED_writemode(0xFF,OLED_CMD);//--128   
    	OLED_writemode(0xA1,OLED_CMD);//set segment remap 
    	OLED_writemode(0xA6,OLED_CMD);//--normal / reverse
    	OLED_writemode(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
    	OLED_writemode(0x3F,OLED_CMD);//--1/32 duty
    	OLED_writemode(0xC8,OLED_CMD);//Com scan direction
    	OLED_writemode(0xD3,OLED_CMD);//-set display offset
    	OLED_writemode(0x00,OLED_CMD);//
    	
    	OLED_writemode(0xD5,OLED_CMD);//set osc division
    	OLED_writemode(0x80,OLED_CMD);//
    	
    	OLED_writemode(0xD8,OLED_CMD);//set area color mode off
    	OLED_writemode(0x05,OLED_CMD);//
    	
    	OLED_writemode(0xD9,OLED_CMD);//Set Pre-Charge Period
    	OLED_writemode(0xF1,OLED_CMD);//
    	
    	OLED_writemode(0xDA,OLED_CMD);//set com pin configuartion
    	OLED_writemode(0x12,OLED_CMD);//
    	
    	OLED_writemode(0xDB,OLED_CMD);//set Vcomh
    	OLED_writemode(0x30,OLED_CMD);//
    	
    	OLED_writemode(0x8D,OLED_CMD);//set charge pump enable
    	OLED_writemode(0x14,OLED_CMD);//
    	
    	OLED_writemode(0xAF,OLED_CMD);//--turn on oled panel
    }  
    
    
    
    void OLED_Clearport(int a,int b)
    {
    	OLED_writemode(0xb0+a,OLED_CMD);    //设置页地址(0~7)
    	OLED_writemode(0x00,OLED_CMD);      //设置显示位置—列低地址
    	OLED_writemode(0x10,OLED_CMD);      //设置显示位置—列高地址   
    	for(n2=0;n2<128;n2++)OLED_writemode(0,OLED_DATA);
    	OLED_writemode(0xb0+b,OLED_CMD);    //设置页地址(0~7)
    	OLED_writemode(0x00,OLED_CMD);      //设置显示位置—列低地址
    	OLED_writemode(0x10,OLED_CMD);      //设置显示位置—列高地址   
    	for(n2=0;n2<128;n2++)OLED_writemode(0,OLED_DATA);	
    }
    
    
    
    

    .h文件

    #ifndef __OLED_H
    #define __OLED_H			  	 
    #include "stdlib.h"	   
    #include "stm32f10x.h"
    #define scl_h GPIO_SetBits(GPIOA,GPIO_Pin_5);
    #define scl_l GPIO_ResetBits(GPIOA,GPIO_Pin_5);
    #define sda_h GPIO_SetBits(GPIOA,GPIO_Pin_7);
    #define sda_l GPIO_ResetBits(GPIOA,GPIO_Pin_7);
    #define OLED_MODE 0
    #define SIZE 8
    #define XLevelL		0x00
    #define XLevelH		0x10
    #define Max_Column	128
    #define Max_Row		64
    #define	Brightness	0xFF 
    #define X_WIDTH 	128
    #define Y_WIDTH 	64	    						  					   
    
    #define OLED_SCLK_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_5)//SCL
    #define OLED_SCLK_Set() GPIO_SetBits(GPIOA,GPIO_Pin_5)
    
    #define OLED_SDIN_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_7)//SDA
    #define OLED_SDIN_Set() GPIO_SetBits(GPIOA,GPIO_Pin_7)
    
     		     
    #define OLED_CMD  0	//写命令
    #define OLED_DATA 1	//写数据
    
    
     
    void OLED_Init(void);
    void OLED_Clear(void);
    void OLED_ShowChar(char x,char y,char chr);
    void OLED_ShowString(char x,char y, char *p);	 
    void OLED_Clearport(int a,int b);
    void OLED_Set_Pos(unsigned char x, unsigned char y);
    void i2c_startup(void);
    void i2c_stopup(void);
    int send_num(u8 num);
    u8 get_num(int state);
    void Write_Command(unsigned char dat);
    void OLED_writemode(unsigned dat,unsigned cmd);
    void Write_Data(unsigned char dat);
    void ack_state(int ack_mask);
    int get_ack(void);
    
    #endif  
    	 
    
    
    
    

    主函数

    #include "stm32f10x.h"
    #include "stdio.h"
    #include "bsp_SysTick.h"
    #include "bsp_usart.h"
    #include "oled.h"
    
    int TEMP,NUM;
    int cnt=0;
    char show[20];
    
    int main()
    {
    	SysTick_Init();	    	 //延时函数初始化
    	OLED_Init();
        OLED_Clear();
    	while(1)
    	{
    		OLED_ShowString(15,0,"open!");	
    		OLED_ShowString(15,3,"hellow world!");	
    		Delay_us(5000000);
    		OLED_Clear();
    		OLED_ShowString(15,0,"close!");	
    		OLED_ShowString(15,3,"hellow world!");	
    		Delay_us(5000000);
    		OLED_Clear();
    	}
    }
    
    

    7. 结论

    0.96寸OLED屏幕是一种简单而功能强大的显示器,可以在各种电子项目中使用。理解IIC协议的基础知识和时序是正确使用这些屏幕的关键。通过正确的连接和代码编写,你可以轻松实现数据的显示。

    视频链接

    OLED使用教程:智能语音时钟-oled屏显示_哔哩哔哩_bilibili

    OLED实现:外设篇协议模块6-OLED显示屏_哔哩哔哩_bilibili智能语音时钟-oled屏显示_哔哩哔哩_bilibili

    OLED显示图片:遥控小车-动画显示_哔哩哔哩_bilibili

    希望本教程能帮助你更好地理解和使用0.96寸OLED屏幕!要是觉得有用麻烦给我点个赞,谢谢各位了。

    作者:小刘爱玩单片机

    物联沃分享整理
    物联沃-IOTWORD物联网 » 智能语音时钟–0.96寸OLED屏幕的使用

    发表回复