STM32 硬件 SPI 驱动 0.96 寸 的 OLED

前言:

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

在这里插入图片描述


githubmy 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工作模式:设置为主SPI
		spi_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;		//定义波特率预分频的值:波特率预分频值为256
		spi_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);	//打开DCDC
	oled_write_operate(OLED_COMM, 0x14);	//打开DCDC
	oled_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);//设置DCDC
	oled_write_operate(OLED_COMM, 0x10);//关闭DCDC
	oled_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);	//关闭OLED
	oled_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 Brightness
	oled_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 duty
	oled_write_operate(OLED_COMM, 0xD3);	//-设置显示偏移(0x00~0x3F)
	oled_write_operate(OLED_COMM, 0x00);	//-not offset
	oled_write_operate(OLED_COMM, 0xd5);	//--set display clock divide ratio/oscillator frequency
	oled_write_operate(OLED_COMM, 0x80);	//--set divide ratio, Set Clock as 100 Frames/Sec
	oled_write_operate(OLED_COMM, 0xD9);	//--set pre-charge period
	oled_write_operate(OLED_COMM, 0xF1);	//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	oled_write_operate(OLED_COMM, 0xDA);	//--set com pins hardware configuration
	oled_write_operate(OLED_COMM, 0x12);
	oled_write_operate(OLED_COMM, 0xDB);	//--set vcomh
	oled_write_operate(OLED_COMM, 0x40);	//Set VCOM Deselect Level
	oled_write_operate(OLED_COMM, 0x20);	//设置页地址模式(0x00/0x01/0x02)
	oled_write_operate(OLED_COMM, 0x02);	//
	oled_write_operate(OLED_COMM, 0x8D);	//--set Charge Pump enable/disable
	oled_write_operate(OLED_COMM, 0x14);	//--set(0x10) disable
	oled_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); 	
}  


实现效果:

这里写图片描述

  • 44
    点赞
  • 194
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值