欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

基于STM32的0.96寸OLED显示屏(模拟SPI)

程序员文章站 2022-03-05 11:12:41
OLED,即有机发光二极管( Organic Light Emitting Diode)。 OLED 由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快,可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。...

关于模拟SPI可以看我的另一篇博客


我使用的是中景园电子的 0.96 寸 OLED 显示屏,0.96 寸 OLED 有黄蓝,白,蓝三种颜色可选;其中黄蓝是屏上 1/4 部分为黄光,下 3/4 为蓝;而且是固定区域显示固定颜色,颜色和显示区域均不能修改;白光则为纯白,也就是黑底白字;蓝色则为纯蓝,也就是黑底蓝字,分辨率为 128*64。

相关参数

  1. GND 电源地
  2. VCC 电源正(3~5.5V)
  3. D0 OLED 的 D0 脚,在 SPI 和 IIC 通信中为CLK管脚
  4. D1 OLED 的 D1 脚,在 SPI 和 IIC 通信中为MOSI管脚
  5. RES OLED 的 RES#脚,用来复位(低电平复位)
  6. DC OLED 的 D/C#E 脚,数据和命令控制管脚 1表示数据 0表示命令
  7. CS OLED 的 CS#脚,也就是片选管脚

关于RES复位引脚:所有 OLED 本身都会有一个复位脚;因为 OLED 在被操作之前需要在将寄存作一次复位;然后才能对期进行初始货操作;否则 OLED 可能会出现不稳定的情况。(先将 RES 拉低延迟 200ms 左右;然后再拉高一直处于高电平状态)
本屏所用的驱动 IC 为 SSD1306;其具有内部升压功能;所以在设计的时候不需要再专一设计升压电路;当然了本屏也可以选用外部升压,具体的请详查数据手册。SSD1306 的每页包含了128 个字节,总共 8 页,这样刚好是 128*64 的点阵大小。这点与 1.3 寸 OLED 驱动 IC SSD1106稍有不同,SSD1106 每页是 132 个字节,也是 8 页。所以在用 0.96 寸 OLED 移植 1.3 寸 OLED 程序的时候需要将 0.96 寸的显示地址向右偏移 2,这样显示就正常了;否则在用 1.3 寸的时候 1.3寸屏右边会有 4 个像素点宽度显示不正常或是全白,这点大家注意一下 。其它的 SSD1306 和SSD1106 区别不大。

代码

GPIO初始化

全都是GPIO_Mode_Out_PP模式

static void OLED_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(OLED_RES_CLK|OLED_DC_CLK,ENABLE);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = OLED_RES_Pin|OLED_DC_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(OLED_RES_PORT,&GPIO_InitStructure);	
	Software_SPI_Init();
	/*复位寄存器*/
	OLED_RES_0();
	SysTick_Delay_Ms(200);
	OLED_RES_1();
	
}

写数据和写命令

void OLED_WriteCmd(u8 Cmd)
{
	OLED_DC_Cmd();//DC引脚低电平表示命令
	Software_SPI_Write(Cmd);
}

void OLED_WriteData(u8 Cmd)
{
	OLED_DC_Data();//DC引脚高电平表示数据
	Software_SPI_Write(Cmd);
}

配置OLED模式

void OLED_Init(void)
{
	OLED_GPIO_Init();
	OLED_WriteCmd(0XAE);//关闭OLED面板
	OLED_WriteCmd(0X00);//设置页地址模式的列起始地址低位
	OLED_WriteCmd(0X10);//设置页地址模式的列起始地址高位
	OLED_WriteCmd(0X40);//设置屏幕起始行
	
	OLED_WriteCmd(0X81);//设置对比度(相当于屏幕亮度)
	OLED_WriteCmd(0X00);//对比度设置值,范围0X00-0XFF
	
	/*好像是设置显示方向的*/
	OLED_WriteCmd(0XA1);//设置行扫描方向为从左到右
	OLED_WriteCmd(0XC8);//设置列扫描方向为数据低位在前
	
	
	OLED_WriteCmd(0XA8);//设置复用率
	
	OLED_WriteCmd(0X3F);
	
	/*显示偏移*/
	OLED_WriteCmd(0XD3);//设置显示偏移
	OLED_WriteCmd(0x00);//不偏移
	
	/*设置时钟*/
	OLED_WriteCmd(0XD5);//设置显示时钟分频值/震荡频率
	OLED_WriteCmd(0x80);//设置分频比,将时钟设置为100帧/秒
	
	/*充电*/
	OLED_WriteCmd(0XD9);//设置预充电周期
	OLED_WriteCmd(0xF1);//1个充电时钟和15个放电时钟
	
	OLED_WriteCmd(0XDA);//设置列引脚硬件配置
	OLED_WriteCmd(0x12);//列输出扫描方向从COM63到COM0(C8h), 启用列左/右映射(DAh A[5]=1)

	OLED_WriteCmd(0XDB);//设置VCOMH反压值
	OLED_WriteCmd(0X40);//设置VCOM取消选择级别
	
	OLED_WriteCmd(0X20);//设置内存寻址模式
	OLED_WriteCmd(0x02);//页地址寻址模式
	
	OLED_WriteCmd(0x8D);//电荷泵启用/禁用
	OLED_WriteCmd(0x14);//关闭
	
	OLED_WriteCmd(0xA4);//点亮屏幕
	OLED_WriteCmd(0xA6);//设置正常显示,不反转,1表示点亮像素
	OLED_WriteCmd(0xAF);//打开OLED面板
	
	OLED_Clear();//清屏
	OLED_Set_Pos(0,0);//设置起始坐标
}

OLED页寻址方式

	OLED_WriteCmd(0X20);//设置内存寻址模式
	OLED_WriteCmd(0x02);//页地址寻址模式

基于STM32的0.96寸OLED显示屏(模拟SPI)
OLED显示屏每一行为一页,一页共128字节。
COLx表示图形显示数据RAM列。

void OLED_Set_Pos(unsigned char x, unsigned char y) 
{ 
	OLED_WriteCmd(0xb0+y);
	OLED_WriteCmd(((x&0xf0)>>4)|0x10);
	OLED_WriteCmd((x&0x0f)|0x00); 
}   

OLED_WriteCmd(0xb0+y);相当于设置在OLED的第几行显示;

基于STM32的0.96寸OLED显示屏(模拟SPI)

又表可得知X坐标是分两次分别发送。

OLED_WriteCmd(((x&0xf0)>>4)|0x10);
取X坐标的高4位与表中D7~D4(0001)组成新的8位数写入OLED。
==OLED_WriteCmd((x&0x0f)|0x00); ==
取X坐标的低4位与表中D7~D4(0000)组成新的8位数写入OLED。
如此一来,我们就按照数据手册将坐标写入到了OLED寄存器。

详情可见该博客STM32学习笔记—OLED页寻址方式

OLED清屏

在页寻址模式下,读/写显示RAM后,列地址指针自动加1,如果列地址指针达到列结束地址,则列地址指针重置为列起始地址,页地址指针不变。用户必须设置新的页面和列地址才能访问下一页RAM内容。

void OLED_Clear(void)
{
	u8 i,n;
	for(i=0;i<8;i++)
	{
		OLED_WriteCmd(0XB0+i);//设置页地址 0XB0~0XB7
		OLED_WriteCmd(0X00);//设置显示位置—列低地址
		OLED_WriteCmd(0X10);//设置显示位置—列高地址
		for(n=0;n<128;n++)
		{
			OLED_WriteData(0);
		}
	}
}

当将清屏写入的数据改为1时OLED_WriteData(0);会发现屏幕上出现了8条横线。
因为SSD1306写入数据是一次性写入一个字节,写入1相当于二进制0000 0001,低位在前高位在后。
基于STM32的0.96寸OLED显示屏(模拟SPI)

显示字符

基于STM32的0.96寸OLED显示屏(模拟SPI)GDDRAM是位映射的静态RAM,其中包含要显示的位模式。 RAM的大小为128 x 64位,RAM分为8页,从PAGE0到PAGE7,用于单色128x64点矩阵显示,如图8-13所示。
基于STM32的0.96寸OLED显示屏(模拟SPI)当将一个数据字节写入GDDRAM时,当前列同一页的所有行图像数据都将被填充(即,由列地址指针指向的整个列(8位)将被填充)。 如图8-14所示,数据位D0被写入顶部行,而数据位D7被写入底部行。

根据数据手册的图片与说明得知OLED模块的取模方向为列行式,低位在前。
基于STM32的0.96寸OLED显示屏(模拟SPI)


显示汉字

/*
 * @brief 显示一个汉字
 * @para  x 横坐标    0-111
 * @para  y 纵坐标    0-6
*/
void OLED_ShowChar(u8 x,u8 y,u8 Char)
{
	u8 t;
	OLED_Set_Pos(x,y);
	for(t=0;t<16;t++)
	{
		OLED_WriteData(chinese[2*Char][t]);
  }
	OLED_Set_Pos(x,y+1);
  for(t=0;t<16;t++)
	{	
			OLED_WriteData(chinese[2*Char+1][t]);
  }			
}

一个汉字占用两行,取模时要对应上位置,不然会出现汉字错位。

显示多个汉字

/*
 * @brief 显示多个汉字
 * @para  x 横坐标   
 * @para  y 纵坐标
 * @para  length 待显示汉字的长度
*/
void OLED_ShowCHinese(u8 x,u8 y,u8 length)
{
	u8 i;
	for(i=0;i<length;i++)
	{
		OLED_ShowChar(x,y,i);
		x += 16;
	}
}

显示字符串

/*
 * @brief 显示8x16字符串
 * @para  x  横坐标
 * @para  y  纵坐标
 * @para  ch 指针
*/
void OLED_8x16Str(u8 x,u8 y,char *ch)
{
	u8 c=0,i=0,j=0;
	while(ch[j]!='\0')
	{
		c = ch[j]-32;
		if(x>120)//换行显示
		{
			x=0;
			y++;
		}
		OLED_Set_Pos(x,y);
		for(i=0;i<8;i++)
		{
			OLED_WriteData(F8X16[c*16+i]);//前8位字模数据
		}
		OLED_Set_Pos(x,y+1);//下一页
		for(i=0;i<8;i++)
		{
			OLED_WriteData(F8X16[c*16+i+8]);//前8位字模数据
		}
		x+=8;//下一个字符的坐标
		j++;//字符的序列号
	}
}

要点:因为字模数组第一个字符是空格,所以需要减去空格(c = ch[j]-32;)才能得到正确字模所对应的位置。

主函数

int main(void)
{	
	USART_Config();
	Software_SPI_Init();
	OLED_Init();
	while(1)
	{
		OLED_ShowCHinese(0,0,4);
		OLED_8x16Str(2,2,"2020/11/10");
		OLED_8x16Str(2,4,"CSDN");
	}
}

效果图

基于STM32的0.96寸OLED显示屏(模拟SPI)

完整工程下载

本文地址:https://blog.csdn.net/qq_43334597/article/details/109401827

相关标签: STM32 嵌入式