当前位置: 首页 > web >正文

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

结束

代码重在练习!

代码重在练习!

代码重在练习!

今天的分享就到此结束了,希望对你有所帮助,如果你喜欢我的分享,请点赞收藏加关注,谢谢大家!!!

http://www.xdnf.cn/news/8132.html

相关文章:

  • 无人机影像水面拼接、海面拼接
  • 146.LRU缓存-图解LRU
  • Axure项目实战:智慧运输平台后台管理端-运单管理
  • 华为Cangjie编程技术深度解析(续篇1)
  • 手机入网时长查询接口:精准风控与用户运营的智能利器
  • 【软考向】Chapter 3 数据结构
  • C++线程池----基于生产者消费者模式队列实现
  • 线性代数:AI大模型的数学基石
  • 遨游三防科普:三防平板是什么?有什么特殊功能?
  • ObservableCollection序列化,和监听链表内元素变化
  • nginx动态控制前端版本
  • FPGA通信之VGA
  • 塔能科技:工厂能耗精准节能全方位解决方案
  • 高效缓存设计的哲学
  • 基于科大讯飞语音识别组件(Vue3)
  • PyInstaller 如何在mac电脑上生成在window上可执行的exe文件
  • AI 招聘系统科普:如何辨别真智能与伪自动化
  • 什么是VR实景?有哪些高价值场景?
  • 微信小程序学习基础:从入门到精通
  • 5G 网络中 DNN 的深度解析:从基础概念到核心应用
  • NMEA定位测试,硬件验证
  • 【工具】Quicker/VBA|PPT 在指定位置添加参考线
  • [Memory] 01.QEMU 内存虚拟化概览
  • Python实现PDB文件预处理
  • uniapp使用sse连接后端,接收后端推过来的消息
  • Rust 学习笔记:关于生命周期的练习题
  • Win11怎样禁止程序开机启动
  • 车载以太网网络测试-27【SOME/IP-SD简述】
  • MySQL中实现大数据量的快速插入
  • 游戏引擎学习第304天:构建与遍历图