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  PB7
	GPIO_Init(GPIOB,&GPIO_InitTSources);
	//i2c配置
	
	I2C_InitSources.I2C_ClockSpeed=100000;//100KHZ
	I2C_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--)
	{
		//延时1ms
		Delay_ms(1);
		if(i2c_timeout == 0)
		{
			//关闭I2C1
			I2C_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);
		//关闭I2C
		I2C_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

结束

代码重在练习!

代码重在练习!

代码重在练习!

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

<think>好的,我需要帮助用户找到关于如何使用STM32F103RCT6驱动0.96OLED显示屏的方法或教程,以及示例代码。用户还提到了I2C和SPI接口。首先,我应该回顾用户提供的引用内容,看看是否有相关信息。 引用[1]提到STM32F103RCT6的OLED显示功能源码和硬件需求,可能包含示例代码的线索。引用[2]详细描述了基于STM320.96OLED显示数据的步骤,包括使用野火开发板和SPI接口,还提供了资料链接和Demo程序的下载方法。引用[3]则提到了模拟IIC控制的示例代码,并提供了百度网盘链接,可能包含有用的代码资源。 接下来,我需要整理这些信息,分步骤说明如何驱动OLED。首先,硬件连接部分需要区分I2C和SPI的不同接线方式。然后,软件配置方面,可能需要初始化GPIO、配置通信协议(I2C或SPI)、移植驱动程序,并编写显示代码。用户可能需要具体的代码示例,因此应参考引用中的资料包和Demo程序,特别是引用[2]和[3]中的链接。 需要注意用户使用的开发板型号是STM32F103RCT6,野火mini开发板可能有差异,需提醒用户根据具体情况调整引脚配置。同时,引用中提到的资料包和示例代码可能需要用户自行下载,需确保链接有效或提供替代方法。 另外,用户可能对I2C和SPI的选择有疑问,需要简要说明两者的区别及适用场景,帮助用户决定使用哪种接口。最后,生成的相关问题应围绕常见问题,如初始化失败、显示异常、优化显示效果等,以及比较I2C和SPI的优缺点,供用户进一步学习。</think>以下是基于STM32F103RCT6驱动0.96OLED显示屏的完整指南,整合了I2C和SPI两种通信方式: ### 一、硬件准备 1. **OLED模块参数**: - 分辨率:128x64 - 驱动芯片:SSD1306 - 接口支持:4线SPI(默认)或I2C[^2][^3] 2. **接线方式对比**: | 接口类型 | STM32引脚 | OLED引脚 | 备注 | |----------|-----------|----------|------| | **I2C** | PB6(SCL) | SCL | 需4.7K上拉电阻 | | | PB7(SDA) | SDA | | | **SPI** | PA5(SCK) | D0 | 硬件SPI更高效 | | | PA7(MOSI) | D1 | | | | PA4(CS) | CS | | | | PA2(DC) | DC | | | | PA1(RES) | RES | | ### 二、软件开发流程 1. **工程配置**: - 启用对应接口外设:`I2C1` 或 `SPI1`[^1] - 配置GPIO为复用推挽输出模式 - 设置时钟频率(I2C建议100KHz,SPI建议8MHz) 2. **驱动移植**: ```c // I2C初始化示例 void OLED_I2C_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; HAL_I2C_Init(&hi2c1); } // SPI初始化示例 void OLED_SPI_Init(void) { hspi1.Instance = SPI1; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; HAL_SPI_Init(&hspi1); } ``` 3. **显示控制函数**: ```c // 发送命令 void OLED_WriteCmd(uint8_t cmd) { HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, &cmd, 1, 10); // SPI方式 // 或使用I2C传输 } // 显示字符串 void OLED_ShowString(uint8_t x, uint8_t y, char *str) { while(*str) { OLED_ShowChar(x, y, *str); x += 8; str++; } } ``` ### 三、关键代码资源 1. **SPI接口Demo**: - 野火官方示例程序包含完整显示驱动库 - 下载地址:http://www.lcdwiki.com/zh/0.96inch_SPI_OLED_Module 2. **I2C接口代码**: - 百度云资源包含模拟I2C实现 - 提取码:1234(链接见引用[3]) ### 四、调试要点 1. **常见问题排查**: - 无显示:检查复位时序,确保`OLED_Init()`正确执行 - 花屏:确认显存刷新频率(建议≥60Hz) - 通信失败:用逻辑分析仪捕获SCL/SDA波形 2. **性能优化**: - SPI模式下启用DMA传输 - 使用硬件加速的SSD1306绘图指令 - 实现局部刷新代替屏刷新
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值