本篇使用SPI驱动0.96寸OLED显示屏
一、硬件
屏幕:中景园的0.96寸黄蓝OLED显示屏,驱动芯片是SSD1306。
OLED介绍
OLED引脚,是7针SPI模式。
- GND 电源地VCC 电源正(3~5.5V)
- D0 OLED 的 D0 脚,在 SPI 和 IIC 通信中为时钟管脚
- D1 OLED 的 D1 脚,在 SPI 和 IIC 通信中为数据管脚
- RES OLED 的 RES#脚,用来复位(低电平复位)
- DC OLED 的 D/C#E 脚,数据和命令控制管脚
OLED与SPI引脚连接顺序为:
D0---PA5
D1---PA7
RES-PD14
DC---PD15
CS---PF12
二、软件设计
1、配置相关引脚
使能SPI1和配置相关参数
配置OLED DC/RST/CS引脚
2、编写OLED驱动函数
OLED.c
#include "OLED.h"
#include "oledfont.h"
#include "spi.h"
/*OLED段码分布
正常
(page0) SEG0-SEG128
COM0
|
COM7
反置
(page0) SEG128-SEG0
COM63
|
COM56
写命令,其实是写寄存器
*/
/****************************************************************************
* 名 称:void OLED_Init(void)
* 功 能:OLED初始化
* 入口参数:无
* 出口参数:无
* 说 明:参照上电序列初始化(24/40)
****************************************************************************/
void OLED_Init(void)
{
OLED_CS_High;
//复位OLED
OLED_RST_High;
HAL_Delay(200);
OLED_RST_Low;
HAL_Delay(200);
OLED_RST_High;
OLED_Write_Operate(OLED_Mode_Cmd,0xAE); //关闭OLED
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //设置列低位地址
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //设置列高位地址
OLED_Write_Operate(OLED_Mode_Cmd,0x40); //设置起始行地址及映射RAM显示起始行 (0x00~0x3F)
OLED_Write_Operate(OLED_Mode_Cmd,0xB0); //设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,0x81); //对比度设置
OLED_Write_Operate(OLED_Mode_Cmd,0xCF); //Set SEG Output Current Brightness
OLED_Write_Operate(OLED_Mode_Cmd,0xA1); //Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_Write_Operate(OLED_Mode_Cmd,0xA6); //
OLED_Write_Operate(OLED_Mode_Cmd,0xA8); //设置驱动路数(1 to 64)
OLED_Write_Operate(OLED_Mode_Cmd,0x3F); //*duty = 1/64*/
OLED_Write_Operate(OLED_Mode_Cmd,0xC8); //0xc0上下反置 0xc8正常
OLED_Write_Operate(OLED_Mode_Cmd,0xD3); //设置显示偏移(0x00~0x3F)
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //not offset
OLED_Write_Operate(OLED_Mode_Cmd,0xD5); //--set Display clock divide ratio/oscillator frequency
OLED_Write_Operate(OLED_Mode_Cmd,0x80); //--set divide ratio, Set Clock as 100 Frames/Sec
OLED_Write_Operate(OLED_Mode_Cmd,0xD9); //*set pre-charge period*/
OLED_Write_Operate(OLED_Mode_Cmd,0Xf1); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_Write_Operate(OLED_Mode_Cmd,0xDA); //*set COM pins*/
OLED_Write_Operate(OLED_Mode_Cmd,0x12); //
OLED_Write_Operate(OLED_Mode_Cmd,0xdb); //*set vcomh*/
OLED_Write_Operate(OLED_Mode_Cmd,0x40); //Set VCOM Deselect Level
/**/
OLED_Write_Operate(OLED_Mode_Cmd,0x20); //设置存储模式(0x00,0x02,0x01)
OLED_Write_Operate(OLED_Mode_Cmd,0x02); //页地址模式
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //*set charge pump disable*/
OLED_Write_Operate(OLED_Mode_Cmd,0x14); //--set(0x10) disable
/**/
OLED_Write_Operate(OLED_Mode_Cmd,0xA4); //显示开启(A4,显示,A5无显示)
OLED_Write_Operate(OLED_Mode_Cmd,0xA6); //背景正反向显示(0xa6,正显,0xa7,反显)
OLED_Display_Clear(); //清屏
OLED_Write_Operate(OLED_Mode_Cmd,0xAF); //打开显示
}
/****************************************************************************
* 名 称:uint8_t OLED_Write_Byte(uint8_t data)
* 功 能:OLED写一个字节
* 入口参数:无
* 出口参数:接收的数据
* 返回值 :0失败,1成功
* 说 明:无
****************************************************************************/
uint8_t OLED_Write_Byte(uint8_t data)
{
if(!HAL_SPI_Transmit(&hspi1, &data, 1, 10))
return 0;
else
return 1;
}
/****************************************************************************
* 名 称:void OLED_Write_Operate(uint8_t mode,uint8_t data)
* 功 能:OLED写操作
* 入口参数:模式,数据
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Write_Operate(uint8_t mode,uint8_t data)
{
OLED_CS_Low;
if(mode)
{
OLED_Write_Data;
}
else
{
OLED_Write_Cmd;
}
OLED_Write_Byte(data);
OLED_CS_High;
}
/****************************************************************************
* 名 称:void OLED_Display_Clear(void)
* 功 能:OLED清屏
* 入口参数:无
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_Clear(void)
{
uint8_t page = 0;
uint8_t i=0;
OLED_CS_Low;
for(page=0;page < 8; page++)
{
OLED_Write_Operate(OLED_Mode_Cmd,0xB0+page);//设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,0x00); //设置显示位置-列低地址
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //设置显示位置-列高地址
for(i = 0;i< 128; i++)
{
OLED_Write_Operate(OLED_Mode_Data,0x00); //清屏
}
}
}
/****************************************************************************
* 名 称:void OLED_Set_Positon(void)
* 功 能:设置显示坐标
* 入口参数:x,y
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Set_Positon(uint8_t x,uint8_t y)
{
OLED_Write_Operate(OLED_Mode_Cmd,0xB0 + y); //设置页地址
OLED_Write_Operate(OLED_Mode_Cmd,((x & 0xf0) >>4 ) | 0x10); //设置列高四位地址
OLED_Write_Operate(OLED_Mode_Cmd,(x & 0x0f) | 0x01); //设置列低四位地址
}
/****************************************************************************
* 名 称:void OLED_Display_on(void)
* 功 能:显示打开
* 入口参数:无
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_on(void)
{
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //写充电泵寄存器
OLED_Write_Operate(OLED_Mode_Cmd,0x14); //打开充电泵
OLED_Write_Operate(OLED_Mode_Cmd,0xAF); //打开OLED显示
}
/****************************************************************************
* 名 称:void OLED_Display_offvoid)
* 功 能:显示关闭
* 入口参数:无
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_off(void)
{
OLED_Write_Operate(OLED_Mode_Cmd,0x8d); //写充电泵寄存器
OLED_Write_Operate(OLED_Mode_Cmd,0x10); //关闭充电泵
OLED_Write_Operate(OLED_Mode_Cmd,0xAE); //关闭OLED显示
}
/****************************************************************************
* 名 称:void OLED_Display_onechar(uint8_t x,uint8_t y,uint8_t character,uint8_t size)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
character 字符
size 字号大小
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_onechar(uint8_t x,uint8_t y,uint8_t character,uint8_t size)
{
uint8_t c=0,i=0;
c = character-' ';
if(x > MAX_COLUMN - 1)
{
x= 0;
if(size == SIZE8)
{
y = y+1;
}
if(size == SIZE16)
{
y = y+2;
}
}
if(size == SIZE16)
{
OLED_Set_Positon(x,y);
for( i =0;i< 8; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F8X16[c*16 + i]);
}
OLED_Set_Positon(x,y+1);
for( i =0;i< 8; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F8X16[c*16 + i+8]);
}
}
else
{
OLED_Set_Positon(x,y+1);
for( i =0;i< 6; i++)
{
OLED_Write_Operate(OLED_Mode_Data,F6x8[c][i]);
}
}
}
/****************************************************************************
* 名 称:void OLED_Display_string(uint8_t x,uint8_t y,uint8_t *str,uint8_t size)
* 功 能:显示字符串
* 入口参数:
x ,y坐标位置
str 字符串
size 字号大小
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_string(uint8_t x,uint8_t y,uint8_t *str,uint8_t size)
{
uint8_t i=0;
while(str[i]!='\0')
{
OLED_Display_onechar(x,y,str[i],size);
x += 8;
if(x > 120)
{
x = 0;
y += 2;
}
i++;
}
}
/****************************************************************************
* 名 称:void OLED_Display_Chinese(uint8_t x,uint8_t y,uint8_t Sno)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
Sno 表示汉字数组中一个字的码所占的序号
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_Chinese(uint8_t x,uint8_t y,uint8_t Sno)
{
uint8_t adder=0,i=0;
OLED_Set_Positon(x,y);
for(i = 0;i< 16;i++)
{
OLED_Write_Operate(OLED_Mode_Data,Hzk[2*Sno][i]);
adder += 1;
}
OLED_Set_Positon(x,y+1);
for(i = 0;i< 16;i++)
{
OLED_Write_Operate(OLED_Mode_Data,Hzk[2*Sno+1][i]);
adder += 1;
}
}
/****************************************************************************
* 名 称:uint32_t OLED_POW(uint8_t m, uint8_t n)
* 功 能:m的n次方
* 入口参数:
m为底数,n为指数
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
uint32_t OLED_POW(uint8_t m, uint8_t n)
{
uint32_t result=1;
while(n--)
{
result *= m;
}
return result;
}
/****************************************************************************
* 名 称:void OLED_Display_Num(uint8_t x,uint8_t y,uint32_t num, uint8_t Len,uint8_t size)
* 功 能:显示单个字符
* 入口参数:
x ,y坐标位置
Sno 表示汉字数组中一个字的码所占的序号
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_Num(uint8_t x,uint8_t y,uint32_t num, uint8_t len,uint8_t size)
{
uint8_t i=0;
uint8_t endisplay=0;
uint8_t temp=0;
for(i = 0;i < len;i++)
{
temp = (num / (OLED_POW(10,len-i-1)))%10;
if(endisplay == 0 && i < len-1)
{
if(temp == 0)
{
OLED_Display_onechar(x + (size / 2) * i,y,' ',size);
continue;
}
else
{
endisplay = 1;
}
}
OLED_Display_onechar(x + (size / 2) * i,y,temp + '0',size);
}
}
/****************************************************************************
* 名 称:void OLED_Display_Picture(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMP[])
* 功 能:显示一张图片
* 入口参数:
x0 ,y0,x1,y1图片的大小
BMP[] 图片的码
* 出口参数:无
* 返回值 :无
* 说 明:无
****************************************************************************/
void OLED_Display_Picture(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMP[])
{
uint8_t i=0;
uint8_t x,y;
if(y1 == 8)
{
y= y1/ 8;
}
else
{
y = y1/ 8 + 1;
}
for(y = y0;y < y1;y++)
{
OLED_Set_Positon(x0,y);
for(x = x0;x< x1; x++)
{
OLED_Write_Operate(OLED_Mode_Data,BMP[i++]);
}
}
}
OLED.h
#ifndef _OLED_H
#define _OLED_H
#include "main.h"
/*引脚连接
PA4 CS 低电平有效
PA5 SCLK(SPI1)
PA6 RES/MISO 低电平有效
PA7 MOSI
PB0 DC
Page0-7地址为B0-B7
*/
#define MAX_COLUMN 128
#define MAX_ROW 64
#define SIZE16 16
#define SIZE8 8
#define OLED_Mode_Data 1 //数据模式
#define OLED_Mode_Cmd 0 //命令模式
#define W25QXX_CS_L()
#define W25QXX_CS_H()
#define OLED_Write_Data HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_SET) //写数据
#define OLED_Write_Cmd HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_RESET) //写命令
#define OLED_CS_High HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_SET) //片选无效
#define OLED_CS_Low HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_RESET) //片选有效
#define OLED_RST_High HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_SET)
#define OLED_RST_Low HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_RESET)
void OLED_Config(void);
void OLED_GPIO_Init(void);
void OLED_SPI_Init(void);
void OLED_Init(void);
uint8_t SPI1_WriteReadByte(uint8_t Data);
uint8_t OLED_Write_Byte(uint8_t data);
void OLED_Write_Operate(uint8_t mode,uint8_t data);
void OLED_Display_Clear(void);
void OLED_Set_Positon(uint8_t x,uint8_t y);
void OLED_Display_on(void);
void OLED_Display_off(void);
void OLED_Display_onechar(uint8_t x,uint8_t y,uint8_t character,uint8_t size);
void OLED_Display_string(uint8_t x,uint8_t y,uint8_t *str,uint8_t size);
uint32_t OLED_POW(uint8_t m, uint8_t n);
void OLED_Display_Num(uint8_t x,uint8_t y,uint32_t num, uint8_t len,uint8_t size);
void OLED_Display_Chinese(uint8_t x,uint8_t y,uint8_t Sno);
void OLED_Display_Picture(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMP[]);
#endif
三、下载验证
1、显示文字和图片
2、工程