基于SPI的OLED温湿度显示
本文首先会简单介绍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温湿度显示相关推荐
- 【嵌入式】STM32基于SPI通信协议OLED屏显示
STM32基于SPI通信协议OLED屏显示 一.SPI协议和OLED介绍 1.SPI协议介绍 物理层 协议层 2.OLED显示屏介绍 二.显示个人学号姓名实验 1.题目要求 2.代码部分 1.完整代码 ...
- 实验 STM32 基于SPI的OLED屏显示
STM32 基于SPI的OLED屏显示 一.任务要求 二.显示自己的学号和姓名 1.例子程序的改写 (1)下载资料 (2)解压后找到文件,并用KEIL打开. (3)改写程序 2.连接硬件 3.运行结果 ...
- esp32 spi 驱动 oled 屏显示来自 PC 的画面
esp32 spi 驱动 oled 屏显示来自 PC 的画面 实验代码 gayhub 实验源码 设备及运行环境 装有python的电脑 Python 3.8.2 (tags/v3.8.2:7b3ab5 ...
- 【合泰HT32F52352+oled温湿度显示】
合泰HT32F52352+oled温湿度显示 实验效果图 本实验中oled和dht11的代码是移值之前stm32中的大部分都是一样 只是在进行引脚初始化和相关时钟初始化有点区别 oled.h #ifn ...
- 基于STM32实现OLED滚动显示
基于STM32实现OLED滚动显示 滚动方式 水平滚动 水平加垂直滚动 一.文字取模 二.代码修改 三.硬件连接加结果 总结 参考文献 滚动方式 水平滚动 OLED_WR_Byte(0x2E,OLED ...
- 【基于stm32f103的SHT30温湿度显示】
基于stm32f103的SHT30温湿度显示 本次分享的是基于STM32F103C8T6单片机型号和SHT30温湿度传感器以及TFT(3.5)屏的温湿度显示实验 本实验使用的TFT彩色屏的驱动程序由商 ...
- 基于SPI的OLED显示
文章目录 一.SPI协议 1. SPI简介 2. SPI通信原理 3. GPIO口配置 二.OLED原理及应用 1. OLED原理 2. OLED显示 2.1 姓名学号显示 ①准备工作及部分代码 ②实 ...
- 基于stm32的OLED显示屏显示
文章目录 一.内容 二.关于SPI 三.关于OLED 四.功能实现 1)实验准备 2)代码准备 1.显示学号和姓名 2.显示AHT20的温度和湿度 3.滑动显示长字符 3)结果展示 五.参考内容 六. ...
- 基于SPI协议OLED屏显实例
目录 一.SPI协议 1.1 SPI简介 1.2 SPI四线 1.3 SPI四种工作模式 1.4 SPI时序图 二.项目实现 2.1 实验准备 2.2 字模提取 2.3 程序代码 2.4 硬件连接 2 ...
最新文章
- Android 中单选框或复选框点击其中一个,其余取消操作
- php的declare,php 中的declare
- 计算机拆卸组装过程,如何拆卸并重新组装笔记本电脑
- Go语言学习笔记(四)结构体struct 接口Interface 反射reflect
- visio2010下载地址中文版本32位中文版本64位和激活密钥方法分享哦
- 抖音微信登录服务器繁忙,抖音微信登录不了_抖音微信登录不上原因解决介绍_游戏吧...
- 淘宝优惠券商城赚钱是真的吗?购物最便宜的app
- 国外最流行的Bootstrap后台管理模板
- 图解yarn的作业提交流程
- Hinton论文系列-Reducing the dimensionality of data with neural networks
- FIL在十月份的ICO流通减产
- 男人还是学点一技之长最靠谱
- Class.forName 报错 java.lang.RuntimeException: java.lang.ClassNotFoundException: Persion
- 知识图谱类产品-开题报告构想(一)
- 计算机基础题word,计算机应用基础试题(带答案)Word版
- 盘点波卡生态潜力项目 | 跨链特性促进多赛道繁荣
- 米大师服务端接入坑记录
- 解决linux下php命令无法使用,配置环境变量
- Android消息推送叨逼叨
- 机器学习中特征值分解与奇异值分解的区别及应用