前言:
为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。
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) |
D0 | OLED 的 D0 脚,在 SPI 和 IIC 通信中为时钟管脚 |
D1 | OLED 的 D1 脚,在 SPI 和 IIC 通信中为数据管脚 |
RES | OLED 的 RES#脚,用来复位(低电平复位) |
DC | OLED 的 D/C#E 脚,数据和命令控制管脚 |
CS | OLED 的 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 io | oled io |
---|---|
PA1 | OLED CS |
PA3 | OLED DC |
PA4 | OLED RST |
PA5 | OLED DO |
PA7 | OLED 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);
}
实现效果: