本文首先会简单介绍SPI通信协议,然后后面的实验分为两个板块,一个是OLED屏的使用,另一个是在此基础上,结合上次实验(结尾会附上链接),用OLED屏显示温湿度信息。
实验器材:STM32F103C8T6、0.96寸OLED屏、AHT20温湿度传感器、杜邦线若干
实验环境:Keil μVision5、PCtoLCD2002


文章目录

  • 一、SPI协议
    • 1. SPI简介
  • 二、OLED屏的简单应用
    • 1. OLED原理
    • 2. OLED显示文字
      • 2.1 部分代码实现思想
      • 2.2 完整代码
        • `oled.h`
        • `oled.c`
        • `gui.h`
        • `gui.c`
        • `spi.h`
        • `spi.c`
        • `main.c`
      • 2.3 实验效果
  • 三、OLED屏的温湿度显示
    • 1. 部分代码实现思想
    • 2. 完整代码
    • 3. 实验效果
  • 四、OLED屏的滚动显示
    • 1. 部分代码实现思想
    • 2. 完整代码
    • 3. 实验效果
  • 五、实验总结
  • 六、参考资料

一、SPI协议

1. SPI简介

SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。

SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

SPI内部结构简明图

SPI接口一般使用4条线通信:

MISO 主设备数据输入,从设备数据输出。

MOSI 主设备数据输出,从设备数据输入。

SCLK时钟信号,由主设备产生。

CS从设备片选信号,由主设备控制。

在stm32f103系列芯片中,引脚对应关系如下

STM32F10x的SPI引脚

这些引脚信息也可以在数据手册查询到,这里是一个整理

在STM32中文参考手册中给出了SPI的框图

SPI框图

通常SPI通过4个引脚与外部器件相连:

①硬件上为4根线。
②主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。
③串行移位寄存器通过MOSI信号线将字节传送给从机,从机也将自己的串行移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。
④外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。

GPIO口的配置如下图

表22 SPI

在STM32中文参考手册及其他厂商的参考资料、开发手册介绍的已经非常详细,介于篇幅限制,本文不在详细叙述。

二、OLED屏的简单应用

1. OLED原理

OLED(Organic Light-Emitting Diode),又称为有机电激光显示、有机发光半导体(Organic Electroluminescence Display,OLED)。OLED属于一种电流型的有机发光器件,是通过载流子的注入和复合而致发光的现象,发光强度与注入的电流成正比。OLED在电场的作用下,阳极产生的空穴和阴极产生的电子就会发生移动,分别向空穴传输层和电子传输层注入,迁移到发光层。当二者在发光层相遇时,产生能量激子,从而激发发光分子最终产生可见光

本次实验采用7针0.96英寸SPI OLED屏,屏幕如下图

0.96英寸SPI OLED屏

其中七个引脚的配置如下:

引脚说明

所以根据上述引脚说明,OLED的引脚连接如下表

OLED模块 STM32单片机
VCC 5V/3.3V
GND GND
D0 PB13
D1 PB15
RES PB12
DC PB10
CS PB11

由于本次实验采用软件模拟SPI通信,所以引脚的选择相对比较自由。

2. OLED显示文字

2.1 部分代码实现思想

首先是对引脚的GPIO配置

void OLED_Init_GPIO(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能B端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;   //GPIOB10,11,12,13,15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);      //初始化GPIOB10、11、12、13、15GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15);
}

然后是对OLED屏的初始化

void OLED_Init(void)
{OLED_Init_GPIO(); //初始化GPIOdelay_ms(200);OLED_Reset();     //复位OLED/**************初始化SSD1306*****************/ OLED_WR_Byte(0xAE,OLED_CMD); /*display off*/OLED_WR_Byte(0x00,OLED_CMD); /*set lower column address*/OLED_WR_Byte(0x10,OLED_CMD); /*set higher column address*/OLED_WR_Byte(0x40,OLED_CMD); /*set display start line*/ OLED_WR_Byte(0xB0,OLED_CMD); /*set page address*/OLED_WR_Byte(0x81,OLED_CMD); /*contract control*/ OLED_WR_Byte(0xFF,OLED_CMD); /*128*/OLED_WR_Byte(0xA1,OLED_CMD); /*set segment remap*/ OLED_WR_Byte(0xA6,OLED_CMD); /*normal / reverse*/OLED_WR_Byte(0xA8,OLED_CMD); /*multiplex ratio*/ OLED_WR_Byte(0x3F,OLED_CMD); /*duty = 1/64*/OLED_WR_Byte(0xC8,OLED_CMD); /*Com scan direction*/OLED_WR_Byte(0xD3,OLED_CMD); /*set display offset*/ OLED_WR_Byte(0x00,OLED_CMD);OLED_WR_Byte(0xD5,OLED_CMD); /*set osc division*/ OLED_WR_Byte(0x80,OLED_CMD);OLED_WR_Byte(0xD9,OLED_CMD); /*set pre-charge period*/ OLED_WR_Byte(0XF1,OLED_CMD);OLED_WR_Byte(0xDA,OLED_CMD); /*set COM pins*/ OLED_WR_Byte(0x12,OLED_CMD);OLED_WR_Byte(0xDB,OLED_CMD); /*set vcomh*/ OLED_WR_Byte(0x30,OLED_CMD);OLED_WR_Byte(0x8D,OLED_CMD); /*set charge pump disable*/ OLED_WR_Byte(0x14,OLED_CMD);OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
}

一般厂家会给出相应的代码,我们只需要使用就可以了,具体代码如何实现请自行查看

本次实验需要显示汉字和数字,其中数字已经包含在const unsigned char F6x8[][8]数组中,无需设置。显示的文字需要通过PCtoLCD2002这款软件实现,比如爱我中华

在文本框中输入文字后,在选项中设置格式为C51格式,输出数制为十六进制数

PCtoLCD2002选项

点击生成字模按钮

然后将下面生成的字模复制粘贴到代码中

注意:不同代码字模的格式不一定相同,请根据代码自行更改相应的格式

2.2 完整代码

其中delay.c和delay.h可以参考笔者之前的博客,由于篇幅限制,参考代码中删除了部分注释代码

oled.h

#ifndef __OLED_H
#define __OLED_H                 //--------------OLED参数定义---------------------
#define PAGE_SIZE    8
#define XLevelL     0x00
#define XLevelH     0x10
#define YLevel       0xB0
#define Brightness   0xFF
#define WIDTH        128
#define HEIGHT       64 //-------------写命令和数据定义-------------------
#define OLED_CMD     0  //写命令
#define OLED_DATA    1  //写数据 //-----------------OLED端口定义----------------
#define OLED_CS   GPIO_Pin_11   //片选信号           PB11
#define OLED_DC   GPIO_Pin_10   //数据/命令控制信号  PB10
#define OLED_RST  GPIO_Pin_12   //复位信号           PB12//-----------------OLED端口操作定义----------------
#define OLED_CS_Clr()  GPIO_ResetBits(GPIOB,OLED_CS)
#define OLED_CS_Set()  GPIO_SetBits(GPIOB,OLED_CS)#define OLED_DC_Clr()  GPIO_ResetBits(GPIOB,OLED_DC)
#define OLED_DC_Set()  GPIO_SetBits(GPIOB,OLED_DC)#define OLED_RST_Clr()  GPIO_ResetBits(GPIOB,OLED_RST)
#define OLED_RST_Set()  GPIO_SetBits(GPIOB,OLED_RST)//OLED控制用函数
void OLED_WR_Byte(unsigned dat,unsigned cmd);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_Reset(void);
void OLED_Init_GPIO(void);
void OLED_Init(void);
void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color);
void OLED_Display(void);
void OLED_Clear(unsigned dat);
#endif

oled.c

#include "oled.h"
#include "stdlib.h"
#include "string.h"
#include "delay.h"
#include "spi.h"
//OLED显存总共分为8页
//每页8行,一行128个像素点
//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127 (0~7)行
//[1]0 1 2 3 ... 127 (8~15)行
//[2]0 1 2 3 ... 127 (16~23)行
//[3]0 1 2 3 ... 127 (24~31)行
//[4]0 1 2 3 ... 127 (32~39)行
//[5]0 1 2 3 ... 127 (40~47)行
//[6]0 1 2 3 ... 127 (48~55)行
//[7]0 1 2 3 ... 127 (56~63)行              //数组每个bit存储OLED每个像素点的颜色值(1-亮(白色),0-灭(黑色))
//每个数组元素表示1列8个像素点,一共128列
static unsigned char OLED_buffer[1024] =
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};/******************************************************************** @name       :void OLED_WR_Byte(unsigned dat,unsigned cmd)* @date       :2018-08-27* @function   :Write a byte of content to the OLED screen* @parameters :dat:Content to be writtencmd:0-write command1-write data* @retvalue   :None
********************************************************************/
void OLED_WR_Byte(unsigned dat,unsigned cmd)
{if(cmd){OLED_DC_Set();}else{OLED_DC_Clr();}OLED_CS_Clr();SPI_WriteByte(dat);OLED_CS_Set();
}/******************************************************************** @name       :void OLED_Set_Pos(unsigned char x, unsigned char y) * @date       :2018-08-27* @function   :Set coordinates in the OLED screen* @parameters :x:x coordinatesy:y coordinates* @retvalue   :None
********************************************************************/
void OLED_Set_Pos(unsigned char x, unsigned char y)
{OLED_WR_Byte(YLevel+y/PAGE_SIZE,OLED_CMD);OLED_WR_Byte((((x+2)&0xf0)>>4)|0x10,OLED_CMD);OLED_WR_Byte(((x+2)&0x0f),OLED_CMD);
}  /******************************************************************** @name       :void OLED_Display_On(void) * @date       :2018-08-27* @function   :Turn on OLED display* @parameters :None* @retvalue   :None
********************************************************************/
void OLED_Display_On(void)
{OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ONOLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}/******************************************************************** @name       :void OLED_Display_Off(void)* @date       :2018-08-27* @function   :Turn off OLED display* @parameters :None* @retvalue   :None
********************************************************************/
void OLED_Display_Off(void)
{OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFFOLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}/******************************************************************** @name       :void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color)* @date       :2018-08-27* @function   :set the value of pixel to RAM* @parameters :x:the x coordinates of pixely:the y coordinates of pixelcolor:the color value of the point1-white0-black* @retvalue   :None
********************************************************************/
void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color)
{if(color){OLED_buffer[(y/PAGE_SIZE)*WIDTH+x]|= (1<<(y%PAGE_SIZE))&0xff;}else{OLED_buffer[(y/PAGE_SIZE)*WIDTH+x]&= ~((1<<(y%PAGE_SIZE))&0xff);}
}                    /******************************************************************** @name       :void OLED_Display(void)* @date       :2018-08-27* @function   :Display in OLED screen* @parameters :None* @retvalue   :None
********************************************************************/
void OLED_Display(void)
{u8 i,n;            for(i=0;i<PAGE_SIZE;i++)  {  OLED_WR_Byte (YLevel+i,OLED_CMD);    //设置页地址(0~7)OLED_WR_Byte (XLevelL,OLED_CMD);      //设置显示位置—列低地址OLED_WR_Byte (XLevelH,OLED_CMD);      //设置显示位置—列高地址   for(n=0;n<WIDTH;n++){OLED_WR_Byte(OLED_buffer[i*WIDTH+n],OLED_DATA); }}   //更新显示
}/******************************************************************** @name       :void OLED_Clear(unsigned dat)  * @date       :2018-08-27* @function   :clear OLED screen* @parameters :dat:0-Display full black1-Display full white* @retvalue   :None
********************************************************************/
void OLED_Clear(unsigned dat)
{  if(dat){memset(OLED_buffer,0xff,sizeof(OLED_buffer));}else{memset(OLED_buffer,0,sizeof(OLED_buffer));}OLED_Display();
}/******************************************************************** @name       :void OLED_Reset(void) * @date       :2018-08-27* @function   :Reset OLED screen* @parameters :dat:0-Display full black1-Display full white* @retvalue   :None
********************************************************************/
void OLED_Reset(void)
{OLED_RST_Set();delay_ms(100);OLED_RST_Clr();delay_ms(100);OLED_RST_Set();
}   /******************************************************************** @name       :void OLED_Init_GPIO(void)* @date       :2018-08-27* @function   :Reset OLED screen* @parameters :None* @retvalue   :None
********************************************************************/
void OLED_Init_GPIO(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //使能B端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15;   //GPIOB10,11,12,13,15 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);      //初始化GPIOB10、11、12、13、15GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_15);
}/******************************************************************** @name       :void OLED_Init(void)* @date       :2018-08-27* @function   :initialise OLED SH1106 control IC* @parameters :None* @retvalue   :None
********************************************************************/
void OLED_Init(void)
{OLED_Init_GPIO(); //初始化GPIOdelay_ms(200);OLED_Reset();     //复位OLED/**************初始化SSD1306*****************/ OLED_WR_Byte(0xAE,OLED_CMD); /*display off*/OLED_WR_Byte(0x00,OLED_CMD); /*set lower column address*/OLED_WR_Byte(0x10,OLED_CMD); /*set higher column address*/OLED_WR_Byte(0x40,OLED_CMD); /*set display start line*/ OLED_WR_Byte(0xB0,OLED_CMD); /*set page address*/OLED_WR_Byte(0x81,OLED_CMD); /*contract control*/ OLED_WR_Byte(0xFF,OLED_CMD); /*128*/OLED_WR_Byte(0xA1,OLED_CMD); /*set segment remap*/ OLED_WR_Byte(0xA6,OLED_CMD); /*normal / reverse*/OLED_WR_Byte(0xA8,OLED_CMD); /*multiplex ratio*/ OLED_WR_Byte(0x3F,OLED_CMD); /*duty = 1/64*/OLED_WR_Byte(0xC8,OLED_CMD); /*Com scan direction*/OLED_WR_Byte(0xD3,OLED_CMD); /*set display offset*/ OLED_WR_Byte(0x00,OLED_CMD);OLED_WR_Byte(0xD5,OLED_CMD); /*set osc division*/ OLED_WR_Byte(0x80,OLED_CMD);OLED_WR_Byte(0xD9,OLED_CMD); /*set pre-charge period*/ OLED_WR_Byte(0XF1,OLED_CMD);OLED_WR_Byte(0xDA,OLED_CMD); /*set COM pins*/ OLED_WR_Byte(0x12,OLED_CMD);OLED_WR_Byte(0xDB,OLED_CMD); /*set vcomh*/ OLED_WR_Byte(0x30,OLED_CMD);OLED_WR_Byte(0x8D,OLED_CMD); /*set charge pump disable*/ OLED_WR_Byte(0x14,OLED_CMD);OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
}  

gui.h

#ifndef __GUI_H__
#define __GUI_H__void GUI_DrawPoint(u8 x, u8 y, u8 color);
void GUI_Fill(u8 sx,u8 sy,u8 ex,u8 ey,u8 color);
void GUI_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2,u8 color);
void GUI_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color);
void GUI_FillRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color);
void GUI_DrawCircle(u8 xc, u8 yc, u8 color, u8 r);
void GUI_FillCircle(u8 xc, u8 yc, u8 color, u8 r);
void GUI_DrawTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color);
void GUI_FillTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color);
void GUI_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size,u8 mode);
void GUI_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 Size,u8 mode);
void GUI_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size,u8 mode);
void GUI_ShowFont16(u8 x,u8 y,u8 *s,u8 mode);
void GUI_ShowFont24(u8 x,u8 y,u8 *s,u8 mode);
void GUI_ShowFont32(u8 x,u8 y,u8 *s,u8 mode);
void GUI_ShowChinese(u8 x,u8 y,u8 hsize,u8 *str,u8 mode);
void GUI_DrawBMP(u8 x,u8 y,u8 width, u8 height, u8 BMP[], u8 mode);
#endif

gui.c

#include "oled.h"
#include "string.h"
#include "oledfont.h"
#include "delay.h"
#include "gui.h"/******************************************************************** @name       :void GUI_DrawPoint(u8 x,u8 y,u8 color)* @date       :2018-08-27* @function   :draw a point in LCD screen* @parameters :x:the x coordinate of the pointy:the y coordinate of the pointcolor:the color value of the point1-white0-black* @retvalue   :None
********************************************************************/
void GUI_DrawPoint(u8 x,u8 y,u8 color)
{OLED_Set_Pixel(x,y,color);OLED_Display();
}/******************************************************************** @name       :void GUI_Fill(u8 sx,u8 sy,u8 ex,u8 ey,u8 color)* @date       :2018-08-27 * @function   :fill the specified area* @parameters :sx:the bebinning x coordinate of the specified areasy:the bebinning y coordinate of the specified areaex:the ending x coordinate of the specified areaey:the ending y coordinate of the specified areacolor:the color value of the the specified area1-white0-black* @retvalue   :None
********************************************************************/
void GUI_Fill(u8 sx,u8 sy,u8 ex,u8 ey,u8 color)
{   u8 i,j;         u8 width=ex-sx+1;         //得到填充的宽度u8 height=ey-sy+1;       //高度for(i=0;i<height;i++){for(j=0;j<width;j++){OLED_Set_Pixel(sx+j, sy+i,color);}     }OLED_Display();
}/******************************************************************** @name       :void GUI_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)* @date       :2018-08-27 * @function   :Draw a line between two points* @parameters :x1:the bebinning x coordinate of the liney1:the bebinning y coordinate of the linex2:the ending x coordinate of the liney2:the ending y coordinate of the linecolor:the color value of the line1-white0-black* @retvalue   :None
********************************************************************/
void GUI_DrawLine(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)
{u16 t; int xerr=0,yerr=0,delta_x,delta_y,distance; int incx,incy,uRow,uCol; delta_x=x2-x1; //计算坐标增量 delta_y=y2-y1; uRow=x1; uCol=y1; if(delta_x>0)incx=1; //设置单步方向 else if(delta_x==0)incx=0;//垂直线 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平线 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 else distance=delta_y; for(t=0;t<=distance+1;t++ )//画线输出 { OLED_Set_Pixel(uRow,uCol,color);xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } }  OLED_Display();
} /****************************************************************************** @name       :void GUI_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)* @date       :2018-08-27 * @function   :Draw a rectangle* @parameters :x1:the bebinning x coordinate of the rectangley1:the bebinning y coordinate of the rectanglex2:the ending x coordinate of the rectangley2:the ending y coordinate of the rectanglecolor:the color value of the rectangle1-white0-black                              * @retvalue   :None
******************************************************************************/
void GUI_DrawRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)
{GUI_DrawLine(x1,y1,x2,y1,color);GUI_DrawLine(x1,y1,x1,y2,color);GUI_DrawLine(x1,y2,x2,y2,color);GUI_DrawLine(x2,y1,x2,y2,color);
}  /****************************************************************************** @name       :void GUI_FillRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)* @date       :2018-08-27* @function   :Filled a rectangle* @parameters :x1:the bebinning x coordinate of the filled rectangley1:the bebinning y coordinate of the filled rectanglex2:the ending x coordinate of the filled rectangley2:the ending y coordinate of the filled rectanglecolor:the color value of the rectangle1-white0-black  * @retvalue   :None
******************************************************************************/
void GUI_FillRectangle(u8 x1, u8 y1, u8 x2, u8 y2,u8 color)
{GUI_Fill(x1,y1,x2,y2,color);
}/****************************************************************************** @name       :static void _draw_circle_8(u8 xc, u8 yc, u8 x, u8 y, u8 color)* @date       :2018-08-27 * @function   :8 symmetry circle drawing algorithm (internal call)* @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center x:the x coordinate relative to the Circular center y:the y coordinate relative to the Circular center color:the color value of the rectangle1-white0-black * @retvalue   :None
******************************************************************************/
static void _draw_circle_8(u8 xc, u8 yc, u8 x, u8 y, u8 color)
{OLED_Set_Pixel(xc + x, yc + y, color);OLED_Set_Pixel(xc - x, yc + y, color);OLED_Set_Pixel(xc + x, yc - y, color);OLED_Set_Pixel(xc - x, yc - y, color);OLED_Set_Pixel(xc + y, yc + x, color);OLED_Set_Pixel(xc - y, yc + x, color);OLED_Set_Pixel(xc + y, yc - x, color);OLED_Set_Pixel(xc - y, yc - x, color);
}/****************************************************************************** @name       :void GUI_DrawCircle(u8 xc, u8 yc, u8 color, u8 r)* @date       :2018-08-27* @function   :Draw a circle of specified size at a specified location* @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center r:Circular radiuscolor:the color value of the rectangle1-white0-black    * @retvalue   :None
******************************************************************************/
void GUI_DrawCircle(u8 xc, u8 yc, u8 color, u8 r)
{int x = 0, y = r,d;d = 3 - 2 * r;while (x <= y) {_draw_circle_8(xc, yc, x, y, color);if (d < 0) {d = d + 4 * x + 6;}else {d = d + 4 * (x - y) + 10;y--;}x++;}OLED_Display();
}/****************************************************************************** @name       :void GUI_FillCircle(u8 xc, u8 yc, u8 color, u8 r)* @date       :2018-08-27* @function   :Fill a circle of specified size at a specified location* @parameters :xc:the x coordinate of the Circular center yc:the y coordinate of the Circular center r:Circular radiuscolor:the color value of the rectangle1-white0-black    * @retvalue   :None
******************************************************************************/
void GUI_FillCircle(u8 xc, u8 yc, u8 color, u8 r)
{int x = 0, y = r, yi, d;d = 3 - 2 * r;while (x <= y) {for (yi = x; yi <= y; yi++){_draw_circle_8(xc, yc, x, yi, color);}if (d < 0) {d = d + 4 * x + 6;} else {d = d + 4 * (x - y) + 10;y--;}x++;}OLED_Display();
}/*********************************************************************************** @name       :void GUI_DrawTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color)* @date       :2018-08-27 * @function   :Draw a triangle at a specified position* @parameters :x0:the bebinning x coordinate of the triangular edge y0:the bebinning y coordinate of the triangular edge x1:the vertex x coordinate of the triangulary1:the vertex y coordinate of the triangularx2:the ending x coordinate of the triangular edge y2:the ending y coordinate of the triangular edge color:the color value of the rectangle1-white0-black * @retvalue   :None
***********************************************************************************/
void GUI_DrawTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color)
{GUI_DrawLine(x0,y0,x1,y1,color);GUI_DrawLine(x1,y1,x2,y2,color);GUI_DrawLine(x2,y2,x0,y0,color);
}/****************************************************************************** @name       :static void _swap(u8 *a, u8 *b)* @date       :2018-08-27* @function   :Exchange two numbers(internal call)* @parameters :a:the address of the first number b:the address of the second number* @retvalue   :None
******************************************************************************/
static void _swap(u8 *a, u8 *b)
{u16 tmp;tmp = *a;*a = *b;*b = tmp;
}/****************************************************************************** @name       :static void _draw_h_line(u8 x0,u8 x1,u8 y,u8 color)* @date       :2018-08-27* @function   :draw a horizontal line in RAM(internal call)* @parameters :x0:the bebinning x coordinate of the horizontal linex1:the ending x coordinate of the horizontal liney:the y coordinate of the horizontal linecolor:the color value of the rectangle1-white0-black  * @retvalue   :None
******************************************************************************/
static void _draw_h_line(u8 x0,u8 x1,u8 y,u8 color)
{u8 i=0;for(i=x0;i<=x1;i++){OLED_Set_Pixel(i, y, color);}
}/****************************************************************************** @name       :void GUI_FillTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color)* @date       :2018-08-27 * @function   :filling a triangle at a specified position* @parameters :x0:the bebinning x coordinate of the triangular edge y0:the bebinning y coordinate of the triangular edge x1:the vertex x coordinate of the triangulary1:the vertex y coordinate of the triangularx2:the ending x coordinate of the triangular edge y2:the ending y coordinate of the triangular edge color:the color value of the rectangle1-white0-black   * @retvalue   :None
******************************************************************************/
void GUI_FillTriangel(u8 x0,u8 y0,u8 x1,u8 y1,u8 x2,u8 y2,u8 color)
{u8 a, b, y, last;int dx01, dy01, dx02, dy02, dx12, dy12;long sa = 0;long sb = 0;if (y0 > y1) {_swap(&y0,&y1); _swap(&x0,&x1);}if (y1 > y2) {_swap(&y2,&y1); _swap(&x2,&x1);}if (y0 > y1) {_swap(&y0,&y1); _swap(&x0,&x1);}if(y0 == y2) { a = b = x0;if(x1 < a){a = x1;}else if(x1 > b){b = x1;}if(x2 < a){a = x2;}else if(x2 > b){b = x2;}_draw_h_line(a,b,y0,color);return;}dx01 = x1 - x0;dy01 = y1 - y0;dx02 = x2 - x0;dy02 = y2 - y0;dx12 = x2 - x1;dy12 = y2 - y1;if(y1 == y2){last = y1; }else{last = y1-1; }for(y=y0; y<=last; y++) {a = x0 + sa / dy01;b = x0 + sb / dy02;sa += dx01;sb += dx02;if(a > b){_swap(&a,&b);}_draw_h_line(a,b,y,color);}sa = dx12 * (y - y1);sb = dx02 * (y - y0);for(; y<=y2; y++) {a = x1 + sa / dy12;b = x0 + sb / dy02;sa += dx12;sb += dx02;if(a > b){_swap(&a,&b);}_draw_h_line(a,b,y,color);}OLED_Display();
}/****************************************************************************** @name       :void GUI_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size,u8 mode)* @date       :2018-08-27 * @function   :Display a single English character* @parameters :x:the bebinning x coordinate of the Character display positiony:the bebinning y coordinate of the Character display positionchr:the ascii code of display character(0~94)Char_Size:the size of display character(8,16)mode:0-white background and black character1-black background and white character* @retvalue   :None
******************************************************************************/
void GUI_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size,u8 mode)
{       unsigned char c=0,i=0,tmp,j=0;   c=chr-' ';//得到偏移后的值          if(x>WIDTH-1){x=0;y=y+2;}if(Char_Size ==16){for(i=0;i<16;i++){if(mode){tmp = F8X16[c*16+i];}else{tmp = ~(F8X16[c*16+i]);}for(j=0;j<8;j++){if(tmp&(0x80>>j)){OLED_Set_Pixel(x+j, y+i,1);}else{OLED_Set_Pixel(x+j, y+i,0);}}}}else if(Char_Size==8){  for(i=0;i<8;i++){if(mode){tmp = F6x8[c][i];}else{tmp = ~(F6x8[c][i]);}for(j=0;j<8;j++){if(tmp&(0x80>>j)){OLED_Set_Pixel(x+j, y+i,1);}else{OLED_Set_Pixel(x+j, y+i,0);}}}}else{return;}OLED_Display();
}/****************************************************************************** @name       :void GUI_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size,u8 mode)* @date       :2018-08-27 * @function   :Display English string* @parameters :x:the bebinning x coordinate of the English stringy:the bebinning y coordinate of the English stringchr:the start address of the English stringChar_Size:the size of display charactermode:0-white background and black character1-black background and white character* @retvalue   :None
******************************************************************************/
void GUI_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size,u8 mode)
{unsigned char j=0,csize;if(Char_Size == 16){csize = Char_Size/2;}else if(Char_Size == 8){csize = Char_Size/2+2;}else{return;}while (chr[j]!='\0'){      GUI_ShowChar(x,y,chr[j],Char_Size,mode);x+=csize;if(x>120){x=0;y+=Char_Size;}j++;}
}/****************************************************************************** @name       :u32 mypow(u8 m,u8 n)* @date       :2018-08-27 * @function   :get the nth power of m (internal call)* @parameters :m:the multipliern:the power* @retvalue   :the nth power of m
******************************************************************************/
static u32 mypow(u8 m,u8 n)
{u32 result=1;  while(n--)result*=m;    return result;
}/****************************************************************************** @name       :void GUI_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 Size,u8 mode)* @date       :2018-08-27 * @function   :Display number* @parameters :x:the bebinning x coordinate of the numbery:the bebinning y coordinate of the numbernum:the number(0~4294967295)len:the length of the display numberSize:the size of display numbermode:0-white background and black character1-black background and white character* @retvalue   :None
******************************************************************************/
void GUI_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 Size,u8 mode)
{           u8 t,temp;u8 enshow=0,csize;if(Size == 16){csize = Size/2;}else if(Size == 8){csize = Size/2+2;}    else{return;}for(t=0;t<len;t++){temp=(num/mypow(10,len-t-1))%10;if(enshow==0&&t<(len-1)){if(temp==0){GUI_ShowChar(x+csize*t,y,' ',Size,mode);continue;}else enshow=1; }GUI_ShowChar(x+csize*t,y,temp+'0',Size,mode); }
}  /****************************************************************************** @name       :void GUI_ShowFont16(u8 x,u8 y,u8 *s,u8 mode)* @date       :2018-08-27 * @function   :Display a single 16x16 Chinese character* @parameters :x:the bebinning x coordinate of the Chinese charactery:the bebinning y coordinate of the Chinese characters:the start address of the Chinese charactermode:0-white background and black character1-black background and white character* @retvalue   :None
******************************************************************************/
void GUI_ShowFont16(u8 x,u8 y,u8 *s,u8 mode)
{u8 i,j,k,tmp;u16 num;num = sizeof(cfont16)/sizeof(typFNT_GB16);for(i=0;i<num;i++){if((cfont16[i].Index[0]==*s)&&(cfont16[i].Index[1]==*(s+1))){for(j=0;j<32;j++){if(mode){tmp = cfont16[i].Msk[j];}else{tmp = ~(cfont16[i].Msk[j]);}for(k=0;k<8;k++){if(tmp&(0x80>>k)){OLED_Set_Pixel(x+(j%2)*8+k, y+j/2,1);}else{OLED_Set_Pixel(x+(j%2)*8+k, y+j/2,0);}}}   break;} }OLED_Display();
}/****************************************************************************** @name       :void GUI_ShowFont24(u8 x,u8 y,u8 *s,u8 mode)* @date       :2018-08-27 * @function   :Display a single 24x24 Chinese character* @parameters :x:the bebinning x coordinate of the Chinese charactery:the bebinning y coordinate of the Chinese characters:the start address of the Chinese charactermode:0-white background and black character1-black background and white character* @retvalue   :None
******************************************************************************/
void GUI_ShowFont24(u8 x,u8 y,u8 *s,u8 mode)
{u8 i,j,k,tmp;u16 num;num = sizeof(cfont24)/sizeof(typFNT_GB24);for(i=0;i<num;i++){if((cfont24[i].Index[0]==*s)&&(cfont24[i].Index[1]==*(s+1))){for(j=0;j<72;j++){if(mode){tmp = cfont24[i].Msk[j];}else{tmp = ~(cfont24[i].Msk[j]);}for(k=0;k<8;k++){if(tmp&(0x80>>k)){OLED_Set_Pixel(x+(j%3)*8+k, y+j/3,1);}else{OLED_Set_Pixel(x+(j%3)*8+k, y+j/3,0);}}}   break;} }OLED_Display();
}/****************************************************************************** @name       :void GUI_ShowFont32(u8 x,u8 y,u8 *s,u8 mode)* @date       :2018-08-27 * @function   :Display a single 32x32 Chinese character* @parameters :x:the bebinning x coordinate of the Chinese charactery:the bebinning y coordinate of the Chinese characters:the start address of the Chinese charactermode:0-white background and black character1-black background and white character* @retvalue   :None
******************************************************************************/
void GUI_ShowFont32(u8 x,u8 y,u8 *s,u8 mode)
{u8 i,j,k,tmp;u16 num;num = sizeof(cfont32)/sizeof(typFNT_GB32);for(i=0;i<num;i++){if((cfont32[i].Index[0]==*s)&&(cfont32[i].Index[1]==*(s+1))){for(j=0;j<128;j++){if(mode){tmp = cfont32[i].Msk[j];}else{tmp = ~(cfont32[i].Msk[j]);}for(k=0;k<8;k++){if(tmp&(0x80>>k)){OLED_Set_Pixel(x+(j%4)*8+k, y+j/4,1);}else{OLED_Set_Pixel(x+(j%4)*8+k, y+j/4,0);}}}  break;} }OLED_Display();
}/****************************************************************************** @name       :void GUI_ShowCHinese(u8 x,u8 y,u8 hsize,u8 *str,u8 mode)* @date       :2018-08-27 * @function   :Display Chinese strings* @parameters :x:the bebinning x coordinate of the Chinese stringsy:the bebinning y coordinate of the Chinese stringssize:the size of Chinese stringsstr:the start address of the Chinese stringsmode:0-white background and black character1-black background and white character* @retvalue   :None
******************************************************************************/
void GUI_ShowChinese(u8 x,u8 y,u8 hsize,u8 *str,u8 mode)
{ while(*str!='\0'){if(hsize == 16){GUI_ShowFont16(x,y,str,mode);}else if(hsize == 24){GUI_ShowFont24(x,y,str,mode);}else if(hsize == 32){GUI_ShowFont32(x,y,str,mode);}else{return;}x+=hsize;if(x>WIDTH-hsize){x=0;y+=hsize;}str+=2;}
}/****************************************************************************** @name       :void GUI_DrawBMP(u8 x,u8 y,u8 width, u8 height, u8 BMP[], u8 mode)* @date       :2018-08-27 * @function   :Display a BMP monochromatic picture* @parameters :x:the bebinning x coordinate of the BMP monochromatic picturey:the bebinning y coordinate of the BMP monochromatic picturewidth:the width of BMP monochromatic pictureheight:the height of BMP monochromatic pictureBMP:the start address of BMP monochromatic picture arraymode:0-white background and black character1-black background and white character                                * @retvalue   :None
******************************************************************************/
void GUI_DrawBMP(u8 x,u8 y,u8 width, u8 height, u8 BMP[], u8 mode)
{   u8 i,j,k;u8 tmp;for(i=0;i<height;i++){for(j=0;j<(width+7)/8;j++){if(mode){tmp = BMP[i*((width+7)/8)+j];}else{tmp = ~BMP[i*((width+7)/8)+j];}for(k=0;k<8;k++){if(tmp&(0x80>>k)){OLED_Set_Pixel(x+j*8+k, y+i,1);}else{OLED_Set_Pixel(x+j*8+k, y+i,0);}}}} OLED_Display();
}

spi.h

#ifndef _SPI_H_
#define _SPI_H_
#include "stm32f10x.h"//本测试程序使用的是软件模拟SPI接口驱动
//SPI的数据引脚定义和时钟引脚定义都可以任意修改
//修改引脚定义后,需要对应修改oled.c中OLED_Init_GPIO函数里面引脚初始化//--------------SPI总线引脚定义-----------------------
#define OLED_MOSI      GPIO_Pin_15  //OLED屏SPI写数据信号
#define OLED_CLK       GPIO_Pin_13  //OLED屏SPI时钟信号//--------------SPI端口操作定义---------------------
#define OLED_MOSI_SET()     GPIO_SetBits(GPIOB,OLED_MOSI)
#define OLED_MOSI_CLR()     GPIO_ResetBits(GPIOB,OLED_MOSI) #define OLED_CLK_SET()      GPIO_SetBits(GPIOB,OLED_CLK)
#define OLED_CLK_CLR()      GPIO_ResetBits(GPIOB,OLED_CLK)    //SPI写数据函数
void SPI_WriteByte(u8 Data);
#endif

spi.c

 #include "spi.h"/****************************************************************************** @name       :void SPI_WriteByte(u8 Data)* @date       :2018-08-27 * @function   :Write a byte of data using STM32's Software SPI* @parameters :Data:Data to be written* @retvalue   :None
******************************************************************************/
void SPI_WriteByte(u8 Data)
{unsigned char i=0;for(i=8;i>0;i--){if(Data&0x80)  {OLED_MOSI_SET(); //写数据1}else{OLED_MOSI_CLR(); //写数据0}OLED_CLK_CLR();    //将时钟拉低拉高     OLED_CLK_SET();    //发送1bit数据Data<<=1; }
}

main.c

#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "gui.h"int main(void)
{   DELAY_Init();            //延时函数初始化    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);OLED_Init();           //初始化OLED  OLED_Clear(0); while(1) {        GUI_ShowCHinese(28,20,16,"***",1);GUI_ShowString(4,48,"******",16,1);delay_ms(1500);        delay_ms(1500);}      }

其中还需要oledfont.h、bmp.h,分别为存储字体和图像的文件

2.3 实验效果

图 2.3实验效果

三、OLED屏的温湿度显示

有关OLED屏的资料很多,如果有需要可以在各大厂家或卖家等获取相关资料,或者也可以在其官方网站下载资料。

1. 部分代码实现思想

结合上次的实验基于I2C的温湿度采集_江南烟浓雨的博客-CSDN博客,通过IIC读取温湿度信息后再通过OLED显示出来,主要功能在主程序中实现。将iic.h中H1和T1设置为全局变量,在调用读取函数时,H1和T1的值便会保存在H1和T1中,再通过上面的GUI函数实现。

注意:需要将原来的H1和T1设置为全局变量,在头文件中通过extern声明为全局变量

实验电路(引脚接口)请参考本次实验OLED屏及上次实验AHT20的引脚接法

2. 完整代码

main.c

#include "stm32f10x.h"
#include "stdio.h"
#include "stdlib.h"
#include "bmp.h"
#include "delay.h"
#include "iic.h"
#include "oled.h"
#include "gui.h"uint32_t  H1;  //Humility
uint32_t  T1;  //Temperatureint main(void)
{   DELAY_Init();            //延时函数初始化MyUSART_Init();IIC_Init();NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);OLED_Init();         //初始化OLED  OLED_Clear(0); while(1) {read_AHT20_once();GUI_DrawLine(0, 10, WIDTH-1, 10,1);GUI_DrawLine(WIDTH/2-1,11,WIDTH/2-1,HEIGHT-1,1);GUI_DrawLine(WIDTH/2-1,10+(HEIGHT-10)/2-1,WIDTH-1,10+(HEIGHT-10)/2-1,1);GUI_ShowString(0,1,"2021-11-24",8,1);GUI_ShowString(70,1,"Wednesday",8,1);GUI_ShowString(14,HEIGHT-1-10,"Cloudy",8,1);GUI_ShowString(WIDTH/2+1,13,"TEMP",8,1);  //显示温度GUI_DrawCircle(WIDTH-20, 25, 1,2);GUI_ShowString(WIDTH-15,20,"C",16,1);GUI_ShowNum(WIDTH/2+8,20,T1/10,2,16,1);GUI_ShowString(WIDTH-41,26,".",8,1);GUI_ShowNum(WIDTH-35,20,T1%10,1,16,1);GUI_ShowString(WIDTH/2+1,39,"HUM",8,1);       //显示湿度GUI_ShowNum(WIDTH/2+8,46,H1/10,2,16,1);GUI_ShowString(WIDTH-41,52,".",8,1);GUI_ShowNum(WIDTH-35,46,H1%10,1,16,1);GUI_ShowString(WIDTH-21,46,"%",16,1);GUI_DrawBMP(6,16,51,32, BMP5, 1);delay_ms(2000);}    }

3. 实验效果

在实验过程中,用手捂住AHT20温湿度传感器,使其温度升高,OLED屏幕上也会随之而变化

四、OLED屏的滚动显示

1. 部分代码实现思想

OLED支持水平滚动、垂直并水平滚动两种效果。在0.96OLED数据手册第九章中给出了功能定义

Scrolling Command Table

第一个字节是26h/27h,26h:向右进行水平滚动;27h:向左进行水平滚动
第二个字节是空字节,建议发送00即可
第三个字节设置水平滚动的起始页地址,页0 ~页7。
第四个字节设置滚动步长时间间隔,帧为单位。
第五个字节设置水平滚动的终止页地址,页0 ~页7(终止页地址必须要比起始页地址要大)
第六个字节是空字节,建议发送00即可
第七个字节是空字节,建议发送FF即可

注意:设置滚动前,必须先发送2Eh命令停止滚动。

以上内容参考自如何使用OLED实现滚动效果_正点原子的博客-CSDN博客

知道了这些连续字节的含义,接下来就是水平滚动代码的编写。(更多资料请参考相关博客或数据手册)

2. 完整代码

注意:需要修改或添加oledfont.h的文字内容

main.c

#include "stm32f10x.h"
#include "delay.h"
#include "oled.h"
#include "gui.h"int main(void)
{   DELAY_Init();            //延时函数初始化    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);OLED_Init();           //初始化OLED  OLED_Clear(0); OLED_WR_Byte(0x2E,OLED_CMD);        //关闭滚动OLED_WR_Byte(0x26,OLED_CMD);        //水平向左或者右滚动 26/27OLED_WR_Byte(0x00,OLED_CMD);        //虚拟字节OLED_WR_Byte(0x00,OLED_CMD);        //起始页 0OLED_WR_Byte(0x07,OLED_CMD);        //滚动时间间隔OLED_WR_Byte(0x07,OLED_CMD);        //终止页 7OLED_WR_Byte(0x00,OLED_CMD);        //虚拟字节OLED_WR_Byte(0xFF,OLED_CMD);  GUI_ShowChinese(0,20,16,"你说江南烟浓雨",1);OLED_WR_Byte(0x2F,OLED_CMD);delay_ms(1500);
}

3. 实验效果

五、实验总结

本次实验完成了对于OLED屏的一些操作,但是美中不足的是没有实现硬件IIC和SPI,而是软件模拟的方式实现了IIC和SPI协议。文中所附代码大部分可能并没有用到,请读者自行斟酌,可以参考相关厂商的代码进行改进

六、参考资料

SPI(SPI协议)_百度百科 (baidu.com)

OLED_百度百科 (baidu.com)

基于SPI通信方式的OLED显示_不#曾&轻听的博客-CSDN博客

如何使用OLED实现滚动效果_正点原子的博客-CSDN博客

0.96inch SPI OLED Module - LCD wiki

基于I2C的温湿度采集_江南烟浓雨的博客-CSDN博客

STM32中文参考手册.pdf

STM32F103数据手册.pdf

0.96OLED显示屏_驱动芯片手册.pdf

基于SPI的OLED温湿度显示相关推荐

  1. 【嵌入式】STM32基于SPI通信协议OLED屏显示

    STM32基于SPI通信协议OLED屏显示 一.SPI协议和OLED介绍 1.SPI协议介绍 物理层 协议层 2.OLED显示屏介绍 二.显示个人学号姓名实验 1.题目要求 2.代码部分 1.完整代码 ...

  2. 实验 STM32 基于SPI的OLED屏显示

    STM32 基于SPI的OLED屏显示 一.任务要求 二.显示自己的学号和姓名 1.例子程序的改写 (1)下载资料 (2)解压后找到文件,并用KEIL打开. (3)改写程序 2.连接硬件 3.运行结果 ...

  3. esp32 spi 驱动 oled 屏显示来自 PC 的画面

    esp32 spi 驱动 oled 屏显示来自 PC 的画面 实验代码 gayhub 实验源码 设备及运行环境 装有python的电脑 Python 3.8.2 (tags/v3.8.2:7b3ab5 ...

  4. 【合泰HT32F52352+oled温湿度显示】

    合泰HT32F52352+oled温湿度显示 实验效果图 本实验中oled和dht11的代码是移值之前stm32中的大部分都是一样 只是在进行引脚初始化和相关时钟初始化有点区别 oled.h #ifn ...

  5. 基于STM32实现OLED滚动显示

    基于STM32实现OLED滚动显示 滚动方式 水平滚动 水平加垂直滚动 一.文字取模 二.代码修改 三.硬件连接加结果 总结 参考文献 滚动方式 水平滚动 OLED_WR_Byte(0x2E,OLED ...

  6. 【基于stm32f103的SHT30温湿度显示】

    基于stm32f103的SHT30温湿度显示 本次分享的是基于STM32F103C8T6单片机型号和SHT30温湿度传感器以及TFT(3.5)屏的温湿度显示实验 本实验使用的TFT彩色屏的驱动程序由商 ...

  7. 基于SPI的OLED显示

    文章目录 一.SPI协议 1. SPI简介 2. SPI通信原理 3. GPIO口配置 二.OLED原理及应用 1. OLED原理 2. OLED显示 2.1 姓名学号显示 ①准备工作及部分代码 ②实 ...

  8. 基于stm32的OLED显示屏显示

    文章目录 一.内容 二.关于SPI 三.关于OLED 四.功能实现 1)实验准备 2)代码准备 1.显示学号和姓名 2.显示AHT20的温度和湿度 3.滑动显示长字符 3)结果展示 五.参考内容 六. ...

  9. 基于SPI协议OLED屏显实例

    目录 一.SPI协议 1.1 SPI简介 1.2 SPI四线 1.3 SPI四种工作模式 1.4 SPI时序图 二.项目实现 2.1 实验准备 2.2 字模提取 2.3 程序代码 2.4 硬件连接 2 ...

最新文章

  1. Android 中单选框或复选框点击其中一个,其余取消操作
  2. php的declare,php 中的declare
  3. 计算机拆卸组装过程,如何拆卸并重新组装笔记本电脑
  4. Go语言学习笔记(四)结构体struct 接口Interface 反射reflect
  5. visio2010下载地址中文版本32位中文版本64位和激活密钥方法分享哦
  6. 抖音微信登录服务器繁忙,抖音微信登录不了_抖音微信登录不上原因解决介绍_游戏吧...
  7. 淘宝优惠券商城赚钱是真的吗?购物最便宜的app
  8. 国外最流行的Bootstrap后台管理模板
  9. 图解yarn的作业提交流程
  10. Hinton论文系列-Reducing the dimensionality of data with neural networks
  11. FIL在十月份的ICO流通减产
  12. 男人还是学点一技之长最靠谱
  13. Class.forName 报错 java.lang.RuntimeException: java.lang.ClassNotFoundException: Persion
  14. 知识图谱类产品-开题报告构想(一)
  15. 计算机基础题word,计算机应用基础试题(带答案)Word版
  16. 盘点波卡生态潜力项目 | 跨链特性促进多赛道繁荣
  17. 米大师服务端接入坑记录
  18. 解决linux下php命令无法使用,配置环境变量
  19. Android消息推送叨逼叨
  20. 机器学习中特征值分解与奇异值分解的区别及应用

热门文章

  1. 如何用“底层逻辑“看透世界的底牌?| 刘润最新演讲-学习总结
  2. C#Winform中picturebox控件加载图片后无法释放
  3. 网易服务器修改权限等级,网易企业邮箱新增“管理员权限分级”功能
  4. 从源头解决问题,而不是曲线救国
  5. 你旁边的电闸有辐射或者其它危害吗?
  6. QQ浏览器如何安装油猴插件
  7. 今天没有写的,唱首歌吧。。
  8. 关于前端研发质量提升的建设思路
  9. 《深度学习导论及案例分析》一导读
  10. booth乘法器的原理与verilog实现