0.96寸OLED驱动显示图片、汉字、GIF图

一、前言

0.96寸的OLED模块通常是使用 SSD1306 驱动芯片的。这个芯片非常常见,支持I2C或SPI通信等通信方式,通常用于低功耗显示应用,1306芯片手册

二、OLED介绍

从1306芯片的芯片手册8.1能看到支持很多种通信方式,使用最多的是I2C和SPI方式,也就造就市面上OLED的两种主流型号,4针I2C和7针OLED
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fbf048b85ac240bf9dc812551deee79d.png

驱动你的OLED前需要先确认你的屏幕接线使用什么协议进行通信的,很简单,直接看是几个引脚即可

2.1 OLED硬件接口

2.1.1 I2C接口

4针OLED使用I2C接口如下图,因为引脚更少使用会比SPI接口的多,但是屏幕刷新速率会相对慢一点,毕竟I2C速度显示了每秒的数据量
VCC -> 3.3V(确保使用与模块兼容的电压,很多模块支持3.3V)
GND -> GND
SDA -> I2C数据线(STM32的一个I2C数据引脚,例如PB7)
SCL -> I2C时钟线(STM32的I2C时钟引脚,例如PB6)
在这里插入图片描述

2.1.2 SPI接口

7针OLED使用SPI接口如下图
在这里插入图片描述
VCC -> 3.3V
GND -> GND
SCL -> SPI时钟引脚
SDA -> SPI MOSI引脚
RES -> 重置引脚(可选,一般连接到一个GPIO口)
DC -> 数据/命令控制引脚(可选)
CS -> 片选引脚(可选)

2.2 OLED原理描述

  1. 0.96寸OLED显示区域为128*64个像素点,横坐标为X轴一共128个点,纵坐标为Y轴一共64个点,通过点亮对应的像素点达到显示不同图案的效果
/**
  * 坐标轴定义:
  * 左上角为(0, 0)点
  * 横向向右为X轴,取值范围:0~127
  * 纵向向下为Y轴,取值范围:0~63
  * 
  *       0             X轴           127 
  *      .------------------------------->
  *    0 |
  *      |
  *      |
  *      |
  *  Y轴 |
  *      |
  *      |
  *      |
  *   63 |
  *      v
  * 
  */

三、驱动流程

因为市面上大部分的0.96寸OLED都是4针I2C驱动,我们以4针版本讲解如何驱动显示文字,图案。选择STM32f103为例子

1. I2C初始化

I2C协议的原理我不具体描述,我其他博客模拟I2C使用有详细描述过I2C的使用,这里我们需要注意的是使用OLED屏幕作为I2C的从机,我们需要知道从机的地址和指令。
从数据手册能看出来从机地址为0x78(0b0111100)****或者0x7A(0b0111101),地址取决于SA0的数值,SA0的数值通过1306的芯片的D/C引脚接VCC或者GND来决定,根据我使用的情况来看大部分I2C 0.96寸OLED的从机地址都是0x78
在这里插入图片描述后续所有对OLED进行命令的操作都是通过对OLED的从机地址写入指令


#define OLED_CMD 				0		//??
#define OLED_DATA 				1		//??

void OLED_WR_Byte(u8 dat,u8 cmd)
{
	IIC_Start();	         //IIC????
	IIC_Send_Byte(0x78);     //????
	IIC_Wait_Ack();		 //??ACK
	if(cmd) IIC_Send_Byte(0x40);	 //???
	else IIC_Send_Byte(0x00);	 //???
	IIC_Wait_Ack();		 //??ACK
	IIC_Send_Byte(dat);	 //????/??
	IIC_Wait_Ack();		 //??ACK
	IIC_Stop();		 //IIC??
}

2.OLED初始化

OLED的初始化主要是1306库中的函数去初始化,实现I2C后,按顺序填充CMD,再清屏
下面的代码可以参考下

#include "ssd1306.h"

void OLED_Init(void)
{
	delay_ms(500);							
	OLED_WR_Byte(0xAE,OLED_CMD);
	OLED_WR_Byte(0x00,OLED_CMD);
	OLED_WR_Byte(0x10,OLED_CMD);
	OLED_WR_Byte(0x40,OLED_CMD);
	OLED_WR_Byte(0x81,OLED_CMD);
	OLED_WR_Byte(0xCF,OLED_CMD);
	OLED_WR_Byte(0xA1,OLED_CMD);
	OLED_WR_Byte(0xC8,OLED_CMD);
	OLED_WR_Byte(0xA6,OLED_CMD);
	OLED_WR_Byte(0xA8,OLED_CMD);
	OLED_WR_Byte(0x3F,OLED_CMD);
	OLED_WR_Byte(0xD3,OLED_CMD);
	OLED_WR_Byte(0x00,OLED_CMD);
	OLED_WR_Byte(0xD5,OLED_CMD);
	OLED_WR_Byte(0x80,OLED_CMD);
	OLED_WR_Byte(0xD9,OLED_CMD);
	OLED_WR_Byte(0xF1,OLED_CMD);
	OLED_WR_Byte(0xDA,OLED_CMD);
	OLED_WR_Byte(0x12,OLED_CMD);
	OLED_WR_Byte(0xDB,OLED_CMD);
	OLED_WR_Byte(0x40,OLED_CMD);
	OLED_WR_Byte(0x20,OLED_CMD);
	OLED_WR_Byte(0x02,OLED_CMD);
	OLED_WR_Byte(0x8D,OLED_CMD);
	OLED_WR_Byte(0x14,OLED_CMD);
	OLED_WR_Byte(0xA4,OLED_CMD);
	OLED_WR_Byte(0xA6,OLED_CMD);
	OLED_WR_Byte(0xAF,OLED_CMD);
	OLED_Clear();
	OLED_SetCursorAddrese(0,0); 
}

3.显示内容

3.1 显示文本字符串

	/*在(0, 0)位置显示字符'A',字体大小为8*16点阵*/
	OLED_ShowChar(0, 0, 'A', OLED_8X16);
	
	/*在(16, 0)位置显示字符串"Hello World!",字体大小为8*16点阵*/
	OLED_ShowString(16, 0, "Hello World!", OLED_8X16);
	
	/*在(0, 18)位置显示字符'A',字体大小为6*8点阵*/
	OLED_ShowChar(0, 18, 'A', OLED_6X8);
	
	/*在(16, 18)位置显示字符串"Hello World!",字体大小为6*8点阵*/
	OLED_ShowString(16, 18, "Hello World!", OLED_6X8);
	
	/*在(0, 28)位置显示数字12345,长度为5,字体大小为6*8点阵*/
	OLED_ShowNum(0, 28, 12345, 5, OLED_6X8);
	
	/*在(40, 28)位置显示有符号数字-66,长度为2,字体大小为6*8点阵*/
	OLED_ShowSignedNum(40, 28, -66, 2, OLED_6X8);

3.2 显示汉字

显示汉字需要有对应的汉字字库,通常可以使用16x16或24x24的点阵字库,16x16的字库是较为常见的,能适应0.96寸OLED屏幕的分辨率。你可以从一些开源库中获取汉字字库,或者自己编写程序来生成。

我们以16*16字库为例,这个字库是最常用的。

使用PCtoLCD2002软件去完成汉字的取模,这里我们选16*16的字体,生成的字模型定义成数组,调用
OLED_ShowCHinese(0,0,0)去显示,第一、二个参数是起始显示的x、y的位置,第三个参数是显示数组中第几个字
以下面举例的取模为例,第三个参数应该是0和1.


const char hanzi[4][32]

{0x10,0x60,0x02,0x0C,0xC0,0x02,0x1E,0xE2,0x02,0x02,0x02,0xE2,0x1E,0x00,0x00,0x00},
{0x04,0x04,0x7C,0x03,0x80,0x80,0x40,0x20,0x13,0x0C,0x13,0x20,0x40,0x80,0x80,0x00},/*"汉",0*/
/* (16 X 16 , 宋体 )*/

{0x10,0x0C,0x04,0x24,0x24,0x24,0x25,0x26,0xA4,0x64,0x24,0x04,0x04,0x14,0x0C,0x00},
{0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x00},/*"字",1*/
/* (16 X 16 , 宋体 )*/


在这里插入图片描述

3.3 显示图片

在0.96寸OLED屏幕上显示图片,通常需要将图片转换成适合屏幕分辨率(通常是128x64像素)的点阵数据,并通过程序将这些数据传输到OLED屏幕上进行显示。由于OLED是单色显示,因此图片需要转换成二值图像(黑白图像)

具体分三步进行:

3.3.1 图片转换为bmp单色格式

  1. 画图板转换(这里做原理介绍,如果是使用建议直接下拉用方式2)
    有两种方式一种是使用电脑自带的画图板进行转换,
    在这里插入图片描述
    在这里插入图片描述
    重设完成后另存为单色bmp格式即可,但是有一个缺点,如果原来的图片亮度比较高可能会生成的单色bmp图片在取模软件上
    取模后的数据无法准确显示,所以方法2是使用软件去生成bmp图片,可以调整亮度对比度后生成

  2. 使用img2lcd软件去生产单色bmp图片
    注意红线框起来的地方的设置,这里我找了一张黑色占比较多的图片,直接生成单色图片会很模糊,所以我们可以调整亮度和对比度后再生成,这是直接使用画图板生成bmp无法做到的,也是我推荐这种方式生成单色BMP的原因。
    下图是默认参数下的单色bmp图片,丢失了中间部分黄色的细节
    在这里插入图片描述

下图是调整了亮度和对比度的结果还原了中间过亮区域的细节,调整到满意的效果后保存单色BMP文件到PCtoLCD软件里面的
图片模式去对图片取模。
在这里插入图片描述

3.3.2 对单色bmp图片进行取模

使用 PCtoLCD软件对bmp图片进行取模,先设置成图片模式,再调整参数,导入图片
在这里插入图片描述
按照下图设置好图形模式,然后导入图片生成
在这里插入图片描述

在这里插入图片描述

// 
unsigned char oled_img[] = 
{
0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,
0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFC,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xF8,0x0C,0x0C,0xCC,0x0C,0x0C,0xCC,0x0C,0x0C,0xCC,0x0C,0xCC,0x0C,
0x0C,0xCC,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0xFC,0xF8,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x1F,0xFF,0xFF,0xFF,
0xFF,0xFB,0xF1,0xF1,0xF1,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0xFF,0x00,0x00,0x7F,0x00,0x00,0x7F,0x00,0x00,0x7F,0x00,0x7F,0x00,
0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x1F,0x1F,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x03,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,
0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x03,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x1F,0x1F,0x1F,0x1F,0x0F,0x07,
};

/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{ 	
 unsigned int j=0;
 unsigned char x,y;
  
  if(y1%8==0) y=y1/8;      
  else y=y1/8+1;
	for(y=y0;y<y1;y++)
	{
		OLED_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
	    {      
	    	OLED_WR_Byte(BMP[j++],OLED_DATA);	    	
	    }
	}
} 

/*
函数功能:向OLED写入一个字节
参数:
dat:写入的数据/命令
cmd:1为写数据 0为写命令
*/
void OLED_WR_Byte(u8 dat,u8 cmd)
{
	IIC_Start();	         //IIC开始信号
	IIC_Send_Byte(0x78);     //传输地址
	IIC_Wait_Ack();		 //接收ACK
	if(cmd) IIC_Send_Byte(0x40);	 //写数据
	else IIC_Send_Byte(0x00);	 //写命令
	IIC_Wait_Ack();		 //接收ACK
	IIC_Send_Byte(dat);	 //发送数据/命令
	IIC_Wait_Ack();		 //接收ACK
	IIC_Stop();		 //IIC停止

四、综合代码及效果视频

下面是综合代码基于stm32f103的代码片供参考,显示汉使用OLED_DisplayChinese接口,显示字符串使用OLED_DisplayString接口,显示图片使用OLED_DrawBMP接口去实现,如果需要实现表情包类的动图,则需要循环显示图片了见附录效果。

需要完整代码和取模软的评论留下邮箱我打包发你

int main( void )
{	
	NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2 );
	uart_init(115200);
	delay_init();
	
  IIC_Init();
	
	OLED_Init();     //OLED???
	delay_ms(100);  
	//OLED_DisplayChinese(24,0,0,4);    // OLED显示汉字
	//OLED_DisplayString(88,0,16,":");
	//OLED_DisplayChinese(24,3,4,2);  
	//OLED_DisplayString(56,3,16,":"); // OLED显示字符串
	//OLED_DisplayString(88,3,16,"mA");

	while(1)
	{
		OLED_DrawBMP(0,0,54,8,tupian);
	}
}

附录GIF动图效果

OLED_GIF

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值