STM32 硬件 SPI 驱动 0.96 寸 的 OLED

2023-10-25 00:30
文章标签 驱动 stm32 oled spi 硬件 0.96

本文主要是介绍STM32 硬件 SPI 驱动 0.96 寸 的 OLED,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:

为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。

在这里插入图片描述


github:my github


注:博客所涉及的关于 stm32 的代码,均在仓库【stm32f013_study】下,包括底层驱动和应用测试代码。
本文设计的文件包含:
(1)hardware_spi.c:硬件 SPI实现
(2)drvoled.c:OLED 驱动实现
(3)头文件:
hardware_spi.h :SPI;
drvoled.h :OLED ;
oled_font.h :字体编码部分;
bmp.h:图片部分


1. OLED相关

1.1 OLED 简介

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

OLED 显示技术具有自发光的特性,采用非常薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,而且 OLED 显示屏幕可视角度大,并且能够节省电能。

1.2. OLED 模块简介

本文采用中景园的 0.96 寸的 OLED 显示模块。原理图如下:

这里写图片描述

1.3 模块特点:

(1)0.96 寸 OLED 有黄蓝,白,蓝三种颜色可选;其中黄蓝是屏上 1/4 部分为黄光,下 3/4 为蓝;而且是固定区域显示固定颜色,颜色和显示区域均不能修改;白光则为纯白,也就是黑底白字;蓝色则为纯蓝,也就是黑底蓝字。

(2)分辨率为 128*64;

(3)多种接口方式;OLED 裸屏总共种接口包括:6800、8080 两种并行接口方式、3 线或 4 线的串行 SPI 接口方式、 IIC 接口方式(只需要 2 根线就可以控制 OLED 了),这五种接口是通过屏上的 BS0~BS2 来配置的。

1.4 模块接口:

接口功能
GND电源地
VCC电源正(3~5.5V)
D0OLED 的 D0 脚,在 SPI 和 IIC 通信中为时钟管脚
D1OLED 的 D1 脚,在 SPI 和 IIC 通信中为数据管脚
RESOLED 的 RES#脚,用来复位(低电平复位)
DCOLED 的 D/C#E 脚,数据和命令控制管脚
CSOLED 的 CS#脚,片选管脚

1.5 OLED 驱动 IC

本屏所用的驱动 IC 为 SSD1306;其具有内部升压功能;所以在设计的时候不需要再专一设计升压电路;屏也可以选用外部升压,。SSD1306 的每页包含了128 个字节,总共 8 页,这样刚好是128*64 的点阵大小。

这里写图片描述

1.6 OLED 驱动方式

此模块支持四线 SPI、三线 SPI、IIC 接口和 6800、8080 并口方式,模块的通信接口是通过 BS0,BS1,BS2 三个管脚来配置。

这里写图片描述
此处使用三线 SPI(CS、CLK、MOSI)

1.7 SSD1306的命令

这里写图片描述

0X81: 设置对比度。包含两个字节,第一个0X81为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。

0XAE,0XAF: 0XAE为关闭显示命令;0XAF为开启显示命令。

0X8D:包含2个字节,第一个为命令字,第二个为设置值,第二个字节的BIT2表示电荷泵的开关状态,该位为1,则开启电荷泵,为0则关闭。在模块初始化的时候,这个必须要开启,否则是看不到屏幕显示的。
命令0XB0~B7:用于设置页地址,其低三位的值对应着GRAM的页地址。

0X00~0X0F: 用于设置显示时的起始列地址低四位。

0X10~0X1F: 用于设置显示时的起始列地址高四位。

1.8 字体和图片取模

笔者使用的软件为:PCtoLCD2002.exe,也可以采用其他的软件。

下载地址: PCtoLCD2002

在这里插入图片描述

(1)汉字取模

设置为字符模式,如下图:

在这里插入图片描述

参数设置如下:

在这里插入图片描述

这里笔者取出 “学习” 两个字的字模,如下所示:

在这里插入图片描述

显示如下:

在这里插入图片描述

图片处理:笔者先用画图打开将要用于 OLED 显示的图片,分辨率修改为 128 x 64,然后另存为位图 bmp 格式。字模部分的设置同字符设置,模式选为图片模式即可,注意去掉 “{}” 符号

在这里插入图片描述

然后使用转换软件打开上一步另存为位图(bmp)格式的图片:

在这里插入图片描述点击生成字模,即可得到图片对应的编码数据。

const unsigned char dis_tmp_buff[]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,0xE0,0x60,0x60,0x30,0x30,0x30,0x10,0x18,0x18,0xF8,0xF8,0xF8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xE0,0xF0,0x78,0x38,0x1C,0x0C,0x0C,0x06,0x06,0x07,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x03,0x03,0x23,0x63,0x63,0x62,0x62,0x26,0x06,0x0E,0x0C,0x1C,0x38,0x38,0xF0,0xE0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xF0,0xFE,0x7F,0x3F,0x37,0x60,0x60,0x60,0xC0,0xC0,0xC0,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x40,0x60,0x60,0x70,0x39,0x3F,0x1F,0x0F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,0xE0,0x70,0x30,0x38,0x18,0x1C,0x8C,0x8C,0xC6,0xC6,0x66,0x63,0x73,0x33,0x33,0x19,0x19,0x19,0x19,0x09,0x0C,0x0C,0x0C,0x0C,0x0F,0x07,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x20,0x60,0x70,0x38,0x38,0x1C,0x0E,0x0F,0x07,0x03,0x03,0x03,0x03,0x06,0x06,0x06,0x04,0x0C,0x0C,0x0C,0x0C,0x08,0x19,0x19,0x19,0x19,0x19,0x11,0x13,0x13,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x3F,0x3F,0x3F,0x79,0xF1,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFC,0xFF,0x3F,0x07,0x01,0x00,0xC0,0xF8,0xFC,0xFE,0x0F,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC0,0xC0,0xE0,0x60,0x70,0x30,0x30,0x18,0x18,0x18,0x0C,0x0C,0x0C,0x0C,0x04,0x06,0x06,0x06,0x06,0x03,0x03,0x03,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0xFF,0xFF,0xFE,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x19,0x79,0xF8,0xF0,0xC0,0x80,0x00,0x0F,0x1F,0x3F,0x7C,0xF0,0xC0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xF0,0xF8,0xFE,0x1F,0x0F,0x03,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xF0,0xF0,0xF0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xF0,0xF0,0xF8,0x1C,0x0E,0x0F,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x0F,0x0E,0x1C,0x38,0x38,0x70,0x61,0x61,0xC3,0xC3,0xC7,0x86,0x86,0x8C,0x0C,0x0C,0x18,0x1F,0x1F,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xE0,0xE0,0xF0,0xB0,0xB8,0x9C,0x9F,0x0F,0x07,0x07,0x0F,0x1F,0x7C,0xF8,0xF0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE3,0xF3,0xF3,0xF3,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x03,0x03,0x03,0x03,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0C,0x0C,0x0C,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,0x19,0x19,0x19,0x19,0x1B,0x1F,0x1F,0x1E,0x1C,0x00,0x00,0x01,0x07,0x0F,0x0F,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x19,0x19,0x19,0x19,0x19,0x1B,0x1B,0x13,0x1E,0x1E,0x1C,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

这个数据我们就可以用于显示到 OLED 了。

在这里插入图片描述


2. 硬件SPI

采用 stm32 硬件 SPI1。

2.1 连接关系

stm32 iooled io
PA1OLED CS
PA3OLED DC
PA4OLED RST
PA5OLED DO
PA7OLED DI

2.2 驱动程序

(1)宏定义部分

#define SPIM1_GPIO_PORT	    GPIOA#define SPIM1_CLK_IO	(GPIO_Pin_5)
#define SPIM1_MISO_IO	(GPIO_Pin_6)
#define SPIM1_MOSI_IO	(GPIO_Pin_7)#define FLASH_CS_IO     		(GPIO_Pin_2)
#define FLASH_CS_0()			(GPIO_ResetBits(SPIM1_GPIO_PORT, FLASH_CS_IO))		
#define FLASH_CS_1() 			(GPIO_SetBits(SPIM1_GPIO_PORT, FLASH_CS_IO))#define RCC_PCLK_SPIM1_GPIO     RCC_APB2Periph_GPIOA
#define RCC_PCLK_SPIM1_HD       RCC_APB2Periph_SPI1

(2)初始化部分——SPI1

//--------------------------------------------------------------------------------------------------------
//	函 数 名: spi_master_init
//	功能说明: SPI 硬件配置参数初始化
//	形    参: 	spi_chl:SPIM 通道
//	返 回 值: 无
//	日    期: 2020-03-12
//  备    注:采用 Unix like 方式
//	作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
void spi_master_init(uint8_t spi_chl)
{SPI_InitTypeDef  spi_config_init;
#if 1  if(spi_chl == 1){	spi_flash_gpio_init();	//spi flash cs 初始化spi_gpio_init(1);	//spi gpio 初始化RCC_APB2PeriphClockCmd(RCC_PCLK_SPIM1_HD, ENABLE);	//SPI1时钟使能spi_config_init.SPI_Direction 			= SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工spi_config_init.SPI_Mode 				= SPI_Mode_Master;		//设置SPI工作模式:设置为主SPIspi_config_init.SPI_DataSize 			= SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构spi_config_init.SPI_CPOL 				= SPI_CPOL_Low;		//选择了串行时钟的稳态:空闲时钟低spi_config_init.SPI_CPHA 				= SPI_CPHA_1Edge;	//数据捕获(采样)于第1个时钟沿spi_config_init.SPI_NSS					= SPI_NSS_Soft;//SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制spi_config_init.SPI_BaudRatePrescaler 	= SPI_BaudRatePrescaler_256;		//定义波特率预分频的值:波特率预分频值为256spi_config_init.SPI_FirstBit 			= SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始spi_config_init.SPI_CRCPolynomial 		= 7;	//CRC值计算的多项式SPI_Init(SPI1, &spi_config_init);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI_Cmd(SPI1, ENABLE); //使能SPI外设}
#endif
} 

(3)收发数据部分

//--------------------------------------------------------------------------------------------------------
//	函 数 名: spi_master_send_recv_byte
//	功能说明: SPI 收发数据
//	形    参: 	spi_chl:SPIM 通道
//				send_byte:发送的数据
//	返 回 值: 无
//	日    期: 2020-03-14
//  备    注:采用 Unix like 方式
//	作    者: by 霁风AI
//--------------------------------------------------------------------------------------------------------
uint8_t spi_master_send_recv_byte(uint8_t spi_chl, uint8_t spi_byte)
{		uint8_t time = 0;if (spi_chl == 1)			    {while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位{time++;if(time>200){return false;}}			  SPI_I2S_SendData(SPI1, spi_byte); //通过外设SPIx发送一个数据time = 0;while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位{time++;if(time>200){return false;}}	  						    return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据	}else {return false;}
}

3. 驱动程序

驱动程序参照 51 单片机进行移植,只不过模拟的 SPI 换成 STM32 硬件 SPI,不用再写时序部分的代码。对于 STM32 的硬件 SPI,我们在驱动 FLASH 中已有介绍,这里就不再做介绍。

3.1 OLED 引脚部分定义

#define MAX_COLUMN	128
#define MAX_ROW	64
#define SIZE 16 	//显示字体选择()#define OLED_DATA	1
#define OLED_COMM	0#define	OLED_GPIO_CLK				RCC_APB2Periph_GPIOA
#define	OLED_PORT					GPIOA#if 1
#define OLED_CS_PIN		GPIO_Pin_1	//CS
#define OLED_CS_LOW		GPIO_ResetBits(OLED_PORT, OLED_CS_PIN)						
#define OLED_CS_HIGH	GPIO_SetBits(OLED_PORT, OLED_CS_PIN)
#else
#define OLED_CS_PIN		GPIO_Pin_4	//CS
#define OLED_CS_LOW		GPIO_ResetBits(GPIOC, GPIO_Pin_2)						
#define OLED_CS_HIGH	GPIO_SetBits(GPIOC, GPIO_Pin_2)
#endif#define OLED_DC_PIN		GPIO_Pin_3	//DC
#define OLED_DC_LOW		GPIO_ResetBits(OLED_PORT, OLED_DC_PIN)
#define OLED_DC_HIGH	GPIO_SetBits(OLED_PORT, OLED_DC_PIN)#define OLED_RST_PIN	GPIO_Pin_4	//RST
#define OLED_RST_LOW	GPIO_ResetBits(OLED_PORT, OLED_RST_PIN)
#define OLED_RST_HIGH	GPIO_SetBits(OLED_PORT, OLED_RST_PIN)#define OLED_CLK_PIN	GPIO_Pin_5
#define OLED_DATA_PIN	GPIO_Pin_7

连接的时候需要看清楚,一开始我就不小心把 SPI 的 CLK 与 DO 接反了,半天找不到原因,这种问题就太低级了,一定得多细心。


3.2 OLED IO 初始化

//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_gpio_init
//	功能说明: oled gpio 初始化
//	形    参: 无
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
static void oled_gpio_init(void)
{GPIO_InitTypeDef gpio_config_init;RCC_APB2PeriphClockCmd(OLED_GPIO_CLK, ENABLE);		//开启OLED GPIO时钟gpio_config_init.GPIO_Pin = OLED_CS_PIN | OLED_DC_PIN | OLED_RST_PIN;	//OLED IO初始化gpio_config_init.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出gpio_config_init.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(OLED_PORT, &gpio_config_init);GPIO_SetBits(OLED_PORT, OLED_CS_PIN | OLED_DC_PIN | OLED_RST_PIN);	//IO初始状态都设置为高电平
} 

3.3 OLED 写数据实现

//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_write_byte
//	功能说明: oled 写一字节数据
//	形    参: write_byte:写入的数据
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 调用SPI发送数据函数
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
static void oled_write_byte(uint8_t write_byte)
{
//	hal_spi_send_bytes(1, &write_byte, 1);	//硬件方式SPI(中间层函数封装)spi_master_send_recv_byte(1, write_byte);	//底层硬件SPI
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_write_operate
//	功能说明: oled 写操作
//	形    参: mode:写入的是数据还是命令(0:命令;1:数据)
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 包含写数据和写命令,通过OLED DC 引脚高低电平区分
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
static void oled_write_operate(uint8_t mode, uint8_t dat)
{OLED_CS_LOW;if (mode)	//写入数据{OLED_DC_HIGH;}else 	//写入命令{OLED_DC_LOW;}oled_write_byte(dat);OLED_CS_HIGH;
}

3.4 OLED 操作实现

//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_set_pos
//	功能说明: oled 显示坐标设置
//	形    参: x:横坐标;y:纵坐标
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 无
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_set_pos(uint8_t x, uint8_t y)
{oled_write_operate(OLED_COMM, 0xb0 + y);	//设置页(page)地址oled_write_operate(OLED_COMM, ((x & 0xf0) >> 4) | 0x10);	//列高四位地址oled_write_operate(OLED_COMM, (x & 0x0f) | 0x01);	//列低四位地址
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_on
//	功能说明: oled 打开显示
//	形    参: 无
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 写入AF指令打开
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_on(void)
{oled_write_operate(OLED_COMM, 0x8d);	//打开DCDColed_write_operate(OLED_COMM, 0x14);	//打开DCDColed_write_operate(OLED_COMM, 0xaf);	//打开OLED
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_off
//	功能说明: oled 关闭显示
//	形    参: 无
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 写入AE指令关闭
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_off(void)
{oled_write_operate(OLED_COMM, 0x8d);//设置DCDColed_write_operate(OLED_COMM, 0x10);//关闭DCDColed_write_operate(OLED_COMM, 0xae);//关闭OLED
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_clear
//	功能说明: oled 清除显示
//	形    参: 无
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 写入00清除
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_clear(void)
{uint8_t page = 0;uint8_t i = 0;for (page = 0; page < 8; page++){oled_write_operate(OLED_COMM, 0xb0 + page);	//设置页地址(0--7)oled_write_operate(OLED_COMM, 0x00);	//设置显示位置—列低地址oled_write_operate(OLED_COMM, 0x10); 	//设置显示位置—列高地址for(i = 0; i < 128; i++){oled_write_operate(OLED_DATA, 0x00);	//0x00清屏}}
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_set
//	功能说明: oled 显示出可视区域
//	形    参: 无
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 写入ff设置
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_set(void)
{uint8_t page = 0;uint8_t i = 0;for (page = 0; page < 8; page++){oled_write_operate(OLED_COMM, 0xb0 + page);	//设置页地址(0--7)oled_write_operate(OLED_COMM, 0x00);	//设置显示位置—列低地址oled_write_operate(OLED_COMM, 0x10);	//设置显示位置—列高地址for (i = 0; i < 128; i++){oled_write_operate(OLED_DATA, 0xff);}}
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_one_char
//	功能说明: oled 显示单个字符
//	形    参: x:横坐标(列);y:纵坐标(行);str:显示字符
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 无
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_one_char(uint8_t x, uint8_t y, uint8_t str)
{uint8_t i = 0;uint8_t ret = 0;//ret = str -32;ret = str - ' ';//得到偏移后的值,对ASCLL码进行一个减法.即在二维数组里找它的位置  if (x > (MAX_COLUMN - 1))	//列超过最大,更换到下一行{x = 0;if (SIZE == 8 ){y = y + 1;//针对8号的字符}if (SIZE == 16 ){y = y + 2;//针对16号的字符}}if (SIZE == 16 ){oled_set_pos(x, y);//16的字体分成两部分写入for (i = 0; i < 8; i++){oled_write_operate(OLED_DATA, F8X16[ret*16+i]);}oled_set_pos(x, y + 1);for	(i = 0; i < 8; i++){oled_write_operate(OLED_DATA, F8X16[ret*16+i+8]);}}else {oled_set_pos(x, y + 1);for(i = 0; i < 6; i++){oled_write_operate(OLED_DATA, F6x8[ret][i]);}}
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_str
//	功能说明: oled 显示多个字符
//	形    参: x:横坐标(列);y:纵坐标(行);str:显示字符串
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 无
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_str(uint8_t x, uint8_t y, uint8_t *str)
{uint8_t i = 0;while(str[i] != '\0'){oled_dis_one_char(x, y, str[i]);x += 8;if(x > 120){x = 0;y += 2;}i++;}
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_chinese
//	功能说明: oled 显示汉字
//	形    参: x:横坐标(列);y:纵坐标(行);no:显示汉字位于编码位置
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 无
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_chinese(uint8_t x, uint8_t y, uint8_t no)
{uint8_t i = 0;uint8_t addr = 0;oled_set_pos(x, y);for (i = 0; i < 16; i++)//数组行列寻址{oled_write_operate(OLED_DATA, TEST[2*no][i]);addr += 1;}oled_set_pos(x, y + 1);for (i = 0; i < 16; i++){oled_write_operate(OLED_DATA, TEST[2*no+1][i]);addr += 1;}}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_picture
//	功能说明: oled 显示图片
//	形    参: x:横坐标(列);y:纵坐标(行);no:显示汉字位于编码位置
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 无
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_picture(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t *bmp)
{uint8_t x = 0;uint8_t y = 0;uint32_t i = 0;if ((y1 % 8) == 0){y = y1 / 8;}else{y = y1 /8 + 1;}for (y = y0; y < y1; y++)	//每行(0 - 7 page){oled_set_pos(x0, y);for (x = x0; x < x1; x++)	//0~128{oled_write_operate(OLED_DATA, bmp[i++]);}}
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_logo
//	功能说明: oled 显示图片logo
//	形    参: 无
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 整屏幕显示
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_logo(void)
{const uint8_t *pdata = myBitmap;uint8_t page = 0;uint8_t seg = 0;for (page = 0xb0; page < 0xb8; page++){oled_write_operate(OLED_COMM, page);oled_write_operate(OLED_COMM, 0x10);oled_write_operate(OLED_COMM, 0x00);for (seg = 0; seg < 128; seg++){oled_write_operate(OLED_DATA, *pdata++);}//		if (page >= 0xB2 && page <= 0xB5)	//调整图片区域
//		{
//			for (seg = 0; seg < 128; seg++)
//			{
//				oled_write_operate(OLED_DATA, *pdata++);
//			}
//		}
//		else
//		{
//			for (seg = 0; seg < 128; seg++)
//			{
//				oled_write_operate(OLED_DATA, 0x00);
//			}
//		}}
}
//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_pow
//	功能说明: 计算 m的n次方
//	形    参: m:底数;n:指数
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 无
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
uint32_t oled_pow(uint8_t m, uint8_t n)
{uint32_t ret = 1;while(n--){ret *= m;}return ret;
}//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_dis_picture
//	功能说明: oled 数字
//	形    参: x:横坐标(列);y:纵坐标(行);num:显示数字;len:数字长度;size_num:数字大小
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 无
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_dis_num(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size_num)
{uint8_t i = 0;uint8_t temp = 0;uint8_t enshow = 0;for (i = 0; i < len; i++){temp = (num / (oled_pow(10,len-i-1))) % 10;//把显示的数字一位一位取出来if((enshow == 0) && (i < (len-1))){if(temp == 0){oled_dis_one_char(x + (size_num / 2) * i, y, ' ');continue;}else{enshow = 1;}}oled_dis_one_char(x + (size_num / 2) * i, y, temp + '0');}
}

3.5 OLED 初始化实现


//---------------------------------------------------------------------------------------------------------------------------------------------
//	函 数 名: oled_init
//	功能说明: oled 初始化
//	形    参: 无
//	返 回 值: 无
//	日    期: 2020-04-11
//  备    注: 外部调用初始化OLED
//	作    者: by 霁风AI
//---------------------------------------------------------------------------------------------------------------------------------------------
void oled_init(void)
{oled_gpio_init();	//oled cs/dc/rst 三个io初始化OLED_RST_HIGH;delay_ms(200);OLED_RST_LOW;delay_ms(200);OLED_RST_HIGH; oled_write_operate(OLED_COMM, 0xAE);	//关闭OLEDoled_write_operate(OLED_COMM, 0x00);//设置列低位地址oled_write_operate(OLED_COMM, 0x10);//设置列高位地址oled_write_operate(OLED_COMM, 0x40);	//设置起始行地址及映射RAM显示起始行 (0x00~0x3F)oled_write_operate(OLED_COMM, 0x81);	//对比度设置oled_write_operate(OLED_COMM, 0xCF); 	// Set SEG Output Current Brightnessoled_write_operate(OLED_COMM, 0xA1);	//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常oled_write_operate(OLED_COMM, 0xC8);	//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常oled_write_operate(OLED_COMM, 0xA8);	//设置驱动路数(1 to 64)oled_write_operate(OLED_COMM, 0x3f);	//--1/64 dutyoled_write_operate(OLED_COMM, 0xD3);	//-设置显示偏移(0x00~0x3F)oled_write_operate(OLED_COMM, 0x00);	//-not offsetoled_write_operate(OLED_COMM, 0xd5);	//--set display clock divide ratio/oscillator frequencyoled_write_operate(OLED_COMM, 0x80);	//--set divide ratio, Set Clock as 100 Frames/Secoled_write_operate(OLED_COMM, 0xD9);	//--set pre-charge periodoled_write_operate(OLED_COMM, 0xF1);	//Set Pre-Charge as 15 Clocks & Discharge as 1 Clockoled_write_operate(OLED_COMM, 0xDA);	//--set com pins hardware configurationoled_write_operate(OLED_COMM, 0x12);oled_write_operate(OLED_COMM, 0xDB);	//--set vcomholed_write_operate(OLED_COMM, 0x40);	//Set VCOM Deselect Leveloled_write_operate(OLED_COMM, 0x20);	//设置页地址模式(0x00/0x01/0x02)oled_write_operate(OLED_COMM, 0x02);	//oled_write_operate(OLED_COMM, 0x8D);	//--set Charge Pump enable/disableoled_write_operate(OLED_COMM, 0x14);	//--set(0x10) disableoled_write_operate(OLED_COMM, 0xA4);	//显示开启(显示:A4;无显示:A5)oled_write_operate(OLED_COMM, 0xA7);	// 背景正反向显示 (0xa6:正显;a7:反显) oled_write_operate(OLED_COMM, 0xAF);	//打开显示oled_write_operate(OLED_COMM, 0xAF); 	//display ON(on:AF;off:AE)oled_dis_clear();oled_set_pos(0, 0); 	
}  

实现效果:

这里写图片描述

这篇关于STM32 硬件 SPI 驱动 0.96 寸 的 OLED的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/wwt18811707971/article/details/78681547
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/278776

相关文章

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

Linux如何快速检查服务器的硬件配置和性能指标

《Linux如何快速检查服务器的硬件配置和性能指标》在运维和开发工作中,我们经常需要快速检查Linux服务器的硬件配置和性能指标,本文将以CentOS为例,介绍如何通过命令行快速获取这些关键信息,... 目录引言一、查询CPU核心数编程(几C?)1. 使用 nproc(最简单)2. 使用 lscpu(详细信

一文彻底搞懂Java 中的 SPI 是什么

《一文彻底搞懂Java中的SPI是什么》:本文主要介绍Java中的SPI是什么,本篇文章将通过经典题目、实战解析和面试官视角,帮助你从容应对“SPI”相关问题,赢得技术面试的加分项,需要的朋... 目录一、面试主题概述二、高频面试题汇总三、重点题目详解✅ 面试题1:Java 的 SPI 是什么?如何实现一个

Dubbo之SPI机制的实现原理和优势分析

《Dubbo之SPI机制的实现原理和优势分析》:本文主要介绍Dubbo之SPI机制的实现原理和优势,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Dubbo中SPI机制的实现原理和优势JDK 中的 SPI 机制解析Dubbo 中的 SPI 机制解析总结Dubbo中

如何在Ubuntu上安装NVIDIA显卡驱动? Ubuntu安装英伟达显卡驱动教程

《如何在Ubuntu上安装NVIDIA显卡驱动?Ubuntu安装英伟达显卡驱动教程》Windows系统不同,Linux系统通常不会自动安装专有显卡驱动,今天我们就来看看Ubuntu系统安装英伟达显卡... 对于使用NVIDIA显卡的Ubuntu用户来说,正确安装显卡驱动是获得最佳图形性能的关键。与Windo

嵌入式Linux之使用设备树驱动GPIO的实现方式

《嵌入式Linux之使用设备树驱动GPIO的实现方式》:本文主要介绍嵌入式Linux之使用设备树驱动GPIO的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、设备树配置1.1 添加 pinctrl 节点1.2 添加 LED 设备节点二、编写驱动程序2.1

嵌入式Linux驱动中的异步通知机制详解

《嵌入式Linux驱动中的异步通知机制详解》:本文主要介绍嵌入式Linux驱动中的异步通知机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、异步通知的核心概念1. 什么是异步通知2. 异步通知的关键组件二、异步通知的实现原理三、代码示例分析1. 设备结构

usb接口驱动异常问题常用解决方案

《usb接口驱动异常问题常用解决方案》当遇到USB接口驱动异常时,可以通过多种方法来解决,其中主要就包括重装USB控制器、禁用USB选择性暂停设置、更新或安装新的主板驱动等... usb接口驱动异常怎么办,USB接口驱动异常是常见问题,通常由驱动损坏、系统更新冲突、硬件故障或电源管理设置导致。以下是常用解决

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型的操作流程

《0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeekR1模型的操作流程》DeepSeekR1模型凭借其强大的自然语言处理能力,在未来具有广阔的应用前景,有望在多个领域发... 目录0基础租个硬件玩deepseek,蓝耘元生代智算云|本地部署DeepSeek R1模型,3步搞定一个应