一、固件库模板
二、准备资料
- 固件库模板
- MDK5开发环境
- IIC协议
- OLED 数据手册及实物
- 字模软件
实验程序已经发布到百度网盘,本文末有链接可以自取
IIC协议查看这篇博客IIC协议
数据手册查看SSD1306Z
字模链接 链接:https://pan.baidu.com/s/1k_ay03xnAdGChirlTpTIVA
提取码:OLED
三、OLED简介
OLED即有机发光管(Organic Light-Emitting Diode,OLED)。OLED显示技术具有自发光、广视角、几乎无穷高的对比度、较低功耗、极高反应速度、可用于绕曲性面板、使用温度范围广、构造及制程简单等有点,被认为是下一代的平面显示屏新兴应用技术。
OLED显示和传统的LCD显示不同,其可以自发光,所以不需要背光灯,这使得OLED显示屏相对于LCD显示屏尺寸更薄,同时显示效果更优。
常用的OLED屏幕有蓝色、黄色、白色等几种。屏的大小为0.96寸,像素点为128*64,所以我们称为0.96oled屏或者12864屏。
这类屏幕大部分是由SSD1306来驱动的,查看数据手册在这:SSD1306Z
1. OLED引脚
标号 | PIN | 引脚说明 |
---|---|---|
1 | GND | OLED显示模块电源地 |
2 | VCC | OLED显示模块电源正 |
3 | SCL | OLED显示模块I2C总线时钟信号 |
4 | SDA | OLED显示模块I2C总线数据信号 |
2. OLED屏幕像素与GDDRAM (Graphic Display Data RAM)
屏幕有128列(Column ),64行(Row),共128*64像素点,每8行为1页(PAGE),共有8页
3. OLED屏幕原理
STM32内部建立一个缓存(共128*8个字节),每次修改的时候,只是修改STM32上的缓存(静态随机存储器 SRAM),修改完后一次性把STM32上的缓存数据写入到OLED的GRAM。
这个方法也有坏处,对于SRAM很小的单片机(51系列)就比较麻烦。
4. OLED屏幕指令
这个写的很详细,建议看看
https://wlink.blog.csdn.net/article/details/81329770
5. 字模软件的使用(软件链接)
OLED点阵的点亮方式,举个显示”P”的例子,最左边位最高位P7。
这个图画错了从下到上应该是8个点,他画了9个点。从下至上第2个点开始。
-
可以看出,要想显示”P”,首先写入0x1f,则显示一个竖杠,之后控制器自动水平移动到下一列。
-
再写入0X05,则出现两个小横杆,这个两个横杆就是0X05中0000 0101中两个1所处的位置,写完第二列后,控制器自动跳到第三列.
-
再写入0X07,第四列写入0X00后,P就显示出来了。这也说明,即使你只想再一列的最上端显示一个小点,即写入0X01。
-
即你不能一次性控制一个点阵,只能一次性控制八位点阵,即一列点阵。这也决定了字模选择的取模方式为“列行式”。
链接:https://pan.baidu.com/s/1k_ay03xnAdGChirlTpTIVA
提取码:OLED
四、OLED显示实验(模拟IIC、硬件IIC)
1.硬件设计
GND接GND
VCC接3.3
OLED的SCL接stm32的B8(模拟IIC)
OLED的SDA接stm32的B9(模拟IIC)
硬件IIC请查看IIC协议
2.软件设计
-
配置通讯使用的目标引脚为开漏模式;
-
使能 I2C 外设的时钟;
-
配置 I2C 外设的模式、地址、速率等参数并使能 I2C 外设;
-
编写向OLED写入函数;
-
编写OLED初始化指令
2.1 复制工程 (stm32f103c8t6新建固件库模板(可自取))
2.2 新建oled文件(打开工程)
2.3 编写代码
oled.c(模拟IIC)
切记尽量避免使用PB3、PB4,具体看stm32f103c8t6使用PB3和PB4做普通GPIO使用时发现异常
#include "oled.h"
#include "stdlib.h"
#include "oledfont.h"
#include "delay.h"
//起始信号
void I2C_Start(void)
{
OLED_SDIN_Set();
OLED_SCLK_Set();
OLED_SDIN_Clr();
OLED_SCLK_Clr();
}
//结束信号
void I2C_Stop(void)
{
OLED_SCLK_Set();
OLED_SDIN_Clr();
OLED_SDIN_Set();
}
//等待信号响应
void I2C_WaitAck(void) //测数据信号的电平
{
OLED_SCLK_Set();
OLED_SCLK_Clr();
}
//写入一个字节
void Send_Byte(u8 dat)
{
u8 i;
for(i = 0; i < 8; i++)
{
OLED_SCLK_Clr();//将时钟信号设置为低电平
if(dat & 0x80) //将dat的8位从最高位依次写入
{
OLED_SDIN_Set();
}
else
{
OLED_SDIN_Clr();
}
OLED_SCLK_Set();//将时钟信号设置为高电平
OLED_SCLK_Clr();//将时钟信号设置为低电平
dat <<= 1;
}
}
//发送一个字节
//向SSD1306写入一个字节。
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat, u8 mode)
{
I2C_Start();
Send_Byte(0x78);
I2C_WaitAck();
if(mode)
{
Send_Byte(0x40);
}
else
{
Send_Byte(0x00);
}
I2C_WaitAck();
Send_Byte(dat);
I2C_WaitAck();
I2C_Stop();
}
uint8_t CMD_Data[] =
{
0xAE, 0x00, 0x10, 0x40, 0xB0, 0x81, 0xFF, 0xA1, 0xA6, 0xA8, 0x3F,
0xC8, 0xD3, 0x00, 0xD5, 0x80, 0xD8, 0x05, 0xD9, 0xF1, 0xDA, 0x12,
0xD8, 0x30, 0x8D, 0x14, 0xAF
}; //初始化命令
/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:15
* @brief: 写入初始化命令
* @return: None
********************************************************************************/
void Write_Cmd(void)
{
int i;
for (i = 0; i < 27; i++)
{
OLED_WR_Byte(CMD_Data[i], OLED_CMD); //SET DCDC命令
}
}
/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:19
* @brief: 向设备写控制命令
* @param: cmd
* @return: None
********************************************************************************/
void OLED_WR_CMD(uint8_t cmd)
{
OLED_WR_Byte(cmd, OLED_CMD); //SET DCDC命令
}
/********************************************************************************
* @author: Luo Chen
* @date: 2022-07-01 15:35
* @brief: 写数据
* @param: data
* @return: None
********************************************************************************/
void OLED_WR_DATA(uint8_t data)
{
OLED_WR_Byte(data, OLED_DATA);