STM32:0.96寸OLED屏驱动全解析——SSD1306 I2C通信与显存配置指南
知识点1【0.96OLED显示屏介绍】
1、OLED的介绍
OLED被称作为 第三代显示技术。显示技术与传统的LED不同:无需背光灯,具有柔性(采用柔性有机基板),有电流通过时,有机材料会发光。并且OLED屏幕可以做的更轻更薄,可视角度更大,能够显著节省耗电量。
缺点是:屏幕价格较贵,无法做大屏幕显示。
2、OLED基本概念介绍
像素点:最小成像单元,每个像素点都是有大小的。
单色屏:1个像素点占1bit
彩色屏:RGB565(16bit);RGB666(18bit);RGB888(24bit)
R——红色,G——绿色,B——蓝色
如RGB(565)
R:5bit
G:6bit
B:5bit
总计16bit
像素:拍照过程中,依次曝光采集的像素点的个数
屏幕分辨率:一个固定尺寸的屏幕容纳的最大像素点个数
3、OLED显示原理
OLED的驱动芯片:SSD1306B
SSD1306是通过I2C与OLED显示屏进行通信的。
SSD1306B的作用:
1、接收单片机发送过来的数据——字符取模 坐标
2、确定当前显示字符的位置
4、SSD1306B介绍
SSD1306B是一款OLED / PLED驱动器。
特点
(1)支持最高128*64点阵单色
(2)单色
(3)内有GDDRAM(Graphic Display Data RAM),可存储整个屏幕的 像素点阵 数据
(4)工作电压 2.4-3.5V(典型值3.3V)
(5)I2C接口
(6)指令集控制
知识点2【使用原理介绍】
1、GDDRAM(图形展示数据寄存器)
(1)特点总结
1、存储时,每8行像素为一页,屏幕有64行像素,因此被分为8页
2、每改动某行某列的像素,则 对应页对应列的8个像素将会一起被改动
3、每页每列的显示值都被一个字节定义,最低为对应最小行,最高位对应最高行。
(2)解释
如下图,
类似这样的页,还有7个(总计8个)
我们操作0行0列,即是操作红框的内容。
并且com0 - com7 依次对应的位是从低到高
2、指令集介绍
这里不介绍全部指令集,仅介绍一些常用的,或者说是本博客中会用到的指令集。
81 + [0~256] :亮度(对比度)配置
A4:正常显示
A5:纯色显示
A6:1亮0灭 正常显示
A7:1灭0亮 反色显示
AE:关闭显示睡眠模式
AF:打开显示,正常刷新画面
0xD5 + [0-256]:设置显示时钟分割比例与振荡器频率
A[3:0]:设置分割比例;A[7:4]:设置振荡器频率
0x8A + A[5:0]:设置多路复用比例
A[5:0]配置 行扫描数(根据屏幕分辨率) 这个值加1为行数
0xD3 + A[5:0]:设置显示偏移量
0x00
设置起始行的位置 0x40 表示从第0行开始
0xDA + A[5:4] 配置引脚顺序和和复用方式
根据屏幕的型号配置:我们这里是
0xDA + 0x12
配置垂直方向扫描方向
选择反向扫描:即0xC8
配置水平方向扫描方向
选择反向扫描:即0xA1
下面是电池配置
3、OLED初始化流程图
上图即使初始化的流程图,这些需要结合指令来理解,内容很杂,但不难。
解释
大家结合上面的指令分析去理解即可。
我们需要发送的指令有:
0xAE,0xD5,0x80,0xA8,0x3F,0xD3, 0x00,0x40,0xDA,0x12,0xC8,0xA1,0x8D,0x10,0xD9,0x22,0xDB, 0x30,0x81,0x66,0xA4,0xA6,0xAF
共计23个,大家最好依次发送。
4、设备地址和寄存器地址
(1)前三段解读:设备地址
我们从 前3段 中可以得知
设备地址是 b0111 10[SA0][R/W]
SA:是从机地址选择,如3C
地址仅7位,大家记住,这时I2C中的地址标准,因此这里的地址可以是0x3C与0x3D
有两个地址的原因,是为了提高硬件的灵活性。当我们需要连接多个SSD1306(如双屏)的时候,可以通过此两个不同的地址来区别两个屏幕
R/W功能位:决定读,还是写
由于屏幕,常用来 读取数据
因此我们这里经常发送0x0C<<1 | 0 即0x78
(2)后四段解读:寄存器地址
由后四段可以知道:
寄存器地址
[Co][D/C]00 0000
寄存器的地址可以用来配置 单字节模式/连续模式(Co位来决定),后续字节是命令还是【显存数据(GDDRAM)(即我们上面说的GDDRAM中的特定行特定列的8个像素)(D/C位决定)】
-
单字节模式:
每次传输仅发送 一个字节的数据或命令,后续操作需重新发送控制字节。
-
连续模式
允许连续发送 多个字节的数据或命令,无需重复发送控制字节。
我们选择单字节模式
因此我们
发送数据,命令为0x40
发送指令,命令为0x00
知识点3【代码补充——I2C的发送函数】
由于今天我复习I2C 与 OLED屏幕
I2C还没有来得及整理。
大家先看看一下代码 了解I2C配置的步骤
我将在这周之内补充I2C的内容,希望大家能够理解!
代码演示
I2C.c
#include "i2c.h"int i2c_timeout;void I2C_Config(void)
{GPIO_InitTypeDef GPIO_InitTSources={0};I2C_InitTypeDef I2C_InitSources;//打开时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);GPIO_InitTSources.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;GPIO_InitTSources.GPIO_Mode=GPIO_Mode_AF_OD;GPIO_InitTSources.GPIO_Speed=GPIO_Speed_10MHz;//PB6 PB7GPIO_Init(GPIOB,&GPIO_InitTSources);//i2c配置I2C_InitSources.I2C_ClockSpeed=100000;//100KHZI2C_InitSources.I2C_Mode=I2C_Mode_I2C;//IIC模式I2C_InitSources.I2C_OwnAddress1=0x00;I2C_InitSources.I2C_Ack=I2C_Ack_Enable;//使能应答I2C_InitSources.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;//7bit从机地址I2C_InitSources.I2C_DutyCycle=I2C_DutyCycle_16_9;I2C_Init(I2C1,&I2C_InitSources);I2C_Cmd(I2C1,ENABLE);
}u8 IIC_Write_Data(uint8_t sla_addr,uint8_t reg_addr,uint8_t data)
{//防止抢占冲突i2c_timeout = I2C_MAX_TIMEOUT_MS;while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY) && i2c_timeout--){//延时1msDelay_ms(1);if(i2c_timeout == 0){//关闭I2C1I2C_GenerateSTOP(I2C1,ENABLE);//返回超时信息return I2C_TRANS_TIMEOUT;}}//打开 加 防超时操作i2c_timeout = I2C_MAX_TIMEOUT_MS;I2C_GenerateSTART(I2C1,ENABLE);while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) && i2c_timeout--){Delay_ms(1);if(!i2c_timeout){I2C_GenerateSTOP(I2C1,ENABLE);return I2C_TRANS_TIMEOUT;}}//发送从设备地址 与 模式,判断是否被选中i2c_timeout = I2C_MAX_TIMEOUT_MS;I2C_Send7bitAddress(I2C1,sla_addr,I2C_Direction_Transmitter);while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) && i2c_timeout--){Delay_ms(1);if(!i2c_timeout){I2C_GenerateSTOP(I2C1,ENABLE);return I2C_TRANS_TIMEOUT;}}//判断接收应答 是否正确if(I2C_GetFlagStatus(I2C1,I2C_FLAG_AF)){//清楚标志位I2C_ClearFlag(I2C1, I2C_FLAG_AF);//关闭I2CI2C_GenerateSTOP(I2C1,ENABLE);//返回值return I2C_TRANS_OTHERERR;}//发送从设备的寄存器地址i2c_timeout = I2C_MAX_TIMEOUT_MS;I2C_SendData(I2C1,reg_addr);while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) && i2c_timeout--){Delay_ms(1);if(!i2c_timeout){I2C_GenerateSTOP(I2C1,ENABLE);return I2C_TRANS_TIMEOUT;}}//发送数据i2c_timeout = I2C_MAX_TIMEOUT_MS;I2C_SendData(I2C1,data);while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED) && i2c_timeout--){Delay_ms(1);if(!i2c_timeout){I2C_GenerateSTOP(I2C1,ENABLE);return I2C_TRANS_TIMEOUT;}}//停止I2C_GenerateSTOP(I2C1,ENABLE);return I2C_TRANS_SUCCESS;
}
I2C.h
#ifndef _I2C_H_
#define _I2C_H_#include "stm32f10x.h"
#include "delay.h"#define I2C_MAX_TIMEOUT_MS 1000
#define I2C_TRANS_OTHERERR 2
#define I2C_TRANS_TIMEOUT 1
#define I2C_TRANS_SUCCESS 0#endif
结束
代码重在练习!
代码重在练习!
代码重在练习!
今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏加关注,谢谢大家!!!