首页 > 其他分享 >STM32OLED使用

STM32OLED使用

时间:2024-03-01 21:47:18浏览次数:28  
标签:设置 uint8 OLED IIC 使用 I2C I2C1 STM32OLED

STM32OLED使用.md

STM32OLED使用

市面上大部分OLED使用SSD1306作为主控芯片,在这里使用STM32F103作为主控芯片,使用IIC总线点亮OLED。

1.IIC设置以及初始化

共需要引用4个头文件“stm32f10x_rcc.h”,“stm32f10x_gpio.h”,“stm32f10x_i2c.h”,“string.h”

void IIC_init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIO时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//开启IIC时钟

GPIO_InitTypeDef IIC_Gpio;//定义GPIO结构体
IIC_Gpio.GPIO_Pin |= GPIO_Pin_6 | GPIO_Pin_7;//设置GPIO引脚
IIC_Gpio.GPIO_Mode = GPIO_Mode_AF_OD;//设置GPIO为复用推挽输出
IIC_Gpio.GPIO_Speed = GPIO_Speed_50MHz;//设置GPIO速度
GPIO_Init(GPIOB,&IIC_Gpio);//载入GPIO配置

I2C_DeInit(I2C1);//初始化IIC
I2C_InitTypeDef IIC_InitStruct;//定义IIC结构体
IIC_InitStruct.I2C_ClockSpeed = 400000;//设置IIC时钟速率
IIC_InitStruct.I2C_Mode = I2C_Mode_I2C;//设置IIC模式
IIC_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//设置IIC占空比
IIC_InitStruct.I2C_OwnAddress1 = 0x21;//设置IIC本机地址,可随意设置,但不能与已有设备重复
IIC_InitStruct.I2C_Ack = I2C_Ack_Enable;//设置IIC应答
IIC_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//设置IIC应答地址长度
I2C_Init(I2C1,&IIC_InitStruct);//载入IIC配置

I2C_Cmd(I2C1,ENABLE);//使能IIC
}

2.IIC发送函数

由于STM32标准库的事件查询组不具备阻塞性质,需要进行封装成阻塞式来等待事件完成

void IIC_WaitEvent(I2C_TypeDef* I2Cx,uint32_t Check_Event)//等待事件更新
{
	while(I2C_CheckEvent(I2C1,Check_Event) != SUCCESS);
}

对于OLED屏幕,不但需要发送一次读写位,还需要在发送一个命令位来确定是写入数据还是命令,数据的话需要先发送0x40,命令的化需要发送0x80。

#define OLED_Address 0x78
void IIC_Send(uint8_t data,uint8_t type)//发送数据函数,type为1时发送命令,为0时发送数据
{
	if(type)//发送命令
	{
		I2C_GenerateSTART(I2C1,ENABLE);//生成IIC起始信号
		IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT);//等待IIC模式被选中事件
		I2C_Send7bitAddress(I2C1,OLED_Address,I2C_Direction_Transmitter);//发送IIC地址和方向
		IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待IIC发送器模式被选中事件
		I2C_SendData(I2C1,0x80);//发送命令位
		IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待发送完成事件
		I2C_SendData(I2C1,data);//发送数据
		IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待发送完成事件
		I2C_GenerateSTOP(I2C1,ENABLE);//生成IIC停止信号
	}
	else//发送数据
	{
		I2C_GenerateSTART(I2C1,ENABLE);//生成IIC起始信号
		IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT);//等待IIC模式被选中事件
		I2C_Send7bitAddress(I2C1,OLED_Address,I2C_Direction_Transmitter);//发送IIC地址和方向
		IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待IIC发送器模式被选中事件
		I2C_SendData(I2C1,0x40);//发送数据位
		IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待发送完成事件
		I2C_SendData(I2C1,data);//发送数据
		IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待发送完成事件
		I2C_GenerateSTOP(I2C1,ENABLE);//生成IIC停止信号
	}
}

void IIC_SendBuff(uint8_t* str,uint16_t len,uint8_t type)//发送多字节
{
I2C_GenerateSTART(I2C1,ENABLE);//生成IIC起始信号
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT);//等待IIC模式被选中事件
I2C_Send7bitAddress(I2C1,OLED_Address,I2C_Direction_Transmitter);//发送IIC地址和方向
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//等待IIC发送器模式被选中事件
if(type)
{
I2C_SendData(I2C1,0x80);//发送命令位
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待发送完成事件
while(len--)//循环发送数据
{
I2C_SendData(I2C1,str);//发送数据
str++;
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待发送完成事件
}
}
else
{
I2C_SendData(I2C1,0x40);//发送数据位
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待发送完成事件
while(len--)//循环发送数据
{
I2C_SendData(I2C1,
str);//发送数据
str++;
IIC_WaitEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//等待发送完成事件
}
}
I2C_GenerateSTOP(I2C1,ENABLE);//生成IIC停止信号
}

3.OLED初始化

OLED初始化指令解析:

Hex D7 D6 D5 D4 D3 D2 D1 D0 命令内容
0x81 1 0 0 0 0 0 0 1 设置对比度,下一条命令代表对比度参数
A[7:0] A7 A6 A5 A4 A3 A2 A1 A0 设置对比度值范围为1~255
0xA4 1 0 1 0 0 1 0 0 开启正常显示
0xA5 1 0 1 0 0 1 0 1 点亮屏幕所所有像素点
0xA6 1 0 1 0 0 1 1 0 正常显示
0xA7 1 0 1 0 0 1 1 1 像素反向显示
0xAE 1 0 1 0 1 1 1 0 关闭OLED显示,进入睡眠模式
0xAF 1 0 1 0 1 1 1 1 开启OLED显示,从睡眠模式中唤醒
0x20 0 0 1 0 0 0 0 0 设置页面地址模式,下一条命令为具体模式设置
A[1:0] * * * * * * A1 A0 设置页面地址模式,A[1:0]=00:水平寻址模式,A[1:0]=01:垂直寻址模式,A[1:0]=10:页寻址模式,A[1:0]=11:无效
0x21 0 0 1 0 0 0 0 1 设置列显示位置,下两条命令为具体模式设置
A[7:0] * A6 A5 A4 A3 A2 A1 A0 列起始地址,范围0-127
B[7:0] * B6 B5 B4 B3 B2 B1 B0 列结束地址,范围0-127
0x22 0 0 1 0 0 0 0 1 设置页显示位置,下两条命令为具体模式设置
A[7:0] * * * * * A2 A1 A0 页起始地址,范围0-7
B[7:0] * * * * * B2 B1 B0 页结束地址,范围0-7
0xA0 1 0 1 0 0 0 0 0 设置列扫描方向,从左向右扫描
0xA1 1 0 1 0 0 0 0 1 设置列扫描方向,从右向左扫描
0xA8 1 0 1 0 1 0 0 0 设置多路复用器,下一条命令为具体参数
A[7:0] * * A5 A4 A3 A2 A1 A0 设置多路复用器为初始模式,即16bit模式[1]
0xC0 1 1 0 0 0 0 0 0 设置行扫描方向,从上到下扫描
0xC8 1 1 0 0 0 1 0 0 设置行扫描方向,从下到上扫描
0xD3 1 1 0 1 0 0 1 1 设置显示偏移量,下一条命令为具体参数
A[5:0] * * A5 A4 A3 A2 A1 A0 设置显示偏移量,范围0~63
0xD5 1 1 0 1 0 1 0 1 设置显示时钟分频比,下一条命令为具体参数
A[7:0] A7 A6 A5 A4 A3 A2 A1 A0 设置显示时钟,A[3:0]+1为振荡器分频比,A[7:4]为振荡器频率,范围为0~1111,复位值为1000
0xD9 1 1 0 1 1 0 1 1 设置预充电周期,下一条命令为具体参数
A[7:0] A7 A6 A5 A4 A3 A2 A1 A0 设置预充电周期,在阶段1,A[3:0]个周期为无效周期,范围0~15;在阶段2,A[7:4]个周期为有效周期,范围0~15
0xDB 1 1 0 1 1 0 1 1 设置VCOMH级别,下一条命令为具体参数
A[7:0] A7 A6 A5 A4 A3 A2 A1 A0 A[6:4]=000b,VCOMH=0.65VCC;A[6:4]=010b,VCOMH=0.77VCC;A[6:4]=011b,VCOMH=0.83*VCC
0xE3 1 1 1 0 0 0 1 1 无操作
0xD6 1 1 0 1 0 1 1 0 设置放大模式,下一条命令为具体参数
A[7:0] * * * * * * * A0 A[0] = 0,关闭放大模式,A[0] = 1,开启放大模式
0x8D 1 0 0 0 1 1 0 1 开启电荷泵,后续两条指令必须为0x14和0xAF

上述指令并不包括所有SSD1306的指令,在这里只给出配置相关的指令,具体指令请参考SSD1306的数据手册。

详细初始化代码:

uint8_t OLED_InitCmd[] = 
{	0xAE,//关闭OLED显示
	0x00,//设置低列地址
	0x10,//设置高列地址
	0x40,//设置开始行地址
	0x81,//设置对比度控制寄存器
	0xCF,//设置SEG输出电路亮度
	0xA1,//设置SEG列扫描方向,0xA0左右翻转,
	0xC8,//设置COM输出扫描方向,0xC0上下翻转,0xC8正常显示
	0xA6,//设置正常显示
	0xA8,//设置多路复用器,
	0x3F,//设置多路复用为16bit
	0xD3,//设置移位映射寄存器
	0x00,//无操作
	0xD5,//设置显示时钟分频比/振荡器频率
	0x80,//设置分频比,设置时钟为100帧/s
	0xD9,//设置预充电周期
	0xF1,//设置预充电周期具体参数
	0xDA,//设置COM硬件配置
	0x12,//设置为页面寻址模式
	0xDB,//设置VCOMH
	0x40,//设置VCOM取消电平
	0x20,//设置页面寻址模式
	0x02,//设置为页面寻址模式
	0x8D,//设置电荷泵
	0x14,//设置电荷泵启用
	0xA4,//开启正常显示
	0xA6,//禁用反向显示
	0xAF};//开启OLED显示

void OLED_Init()
{
IIC_init();//初始化IIC
IIC_SendBuff(OLED_InitCmd,sizeof(OLED_InitCmd)/sizeof(uint8_t),OLED_CMD);将OLED初始化命令发送到OLED
}

OLED画点函数实现

由于OLED使用的显示为页面寻址,此寻址方式有一个很大的问题,假设此时要显示的东西位于页1的后4行和页2的前四行,如果不进行数据的读取而进行刷新,是必然会丢掉页1的前4行和页2的后4行数据。因此必须要使用页面缓冲的刷新方式,而不能单纯使用点刷新或者行刷新,即最小刷新单位为一个页面。 我的思路是将每个页面数据都存放在长度为128的数组中,每次修改显示数据时,先将要更改的数据存入要显示的位置,在将数组中的数据全部发送到OLED,这样就可以保证不会丢失数据。

uint8_t OLED_Page_Rom[8][128] = {};//定义页面缓存,即显存
void OLED_SetPos(uint16_t ram_address,uint8_t page_address)//设置显示起始位置
{
	IIC_Send(0xb0 | page_address,OLED_CMD);//设置行起始位置
	IIC_Send(0x00 | (ram_address&0x00ff),OLED_CMD);//设置列
}

void OLED_Point_Preload(uint16_t x,uint16_t y,uint8_t draw)//显存预加载函数,将要更改的像素数据传入对应的数组位置
{
uint8_t page_address = y/8;//得到y坐标对应的页地址
uint8_t line_address = y%8;//得到y坐标对应的页面中的行地址
if((OLED_Page_Rom[page_address][x] & 0x01<<line_address) != (draw-30)) //代表原显存与要修改的值不同
{
OLED_Page_Rom[page_address][x] |= (draw<<line_address&0xff); //将修改的值存入对应位置
}
}

void OLED_PageRam_Load(uint8_t page_address,uint8_t* str)//显存发送函数
{
uint8_t blank[128];//定义局部变量
memcpy(blank,str,128);//将传入的变量传入局部变量blank
OLED_SetPos(0,page_address);设置显示起始位置
IIC_SendBuff(blank,sizeof(blank)/sizeof(uint8_t),OLED_DATA);//向OLED发送数据
}

void OLED_Draw_Point(uint16_t x,uint16_t y,uint8_t draw)
{
uint8_t page_address = y/8;//得到对应的页地址
OLED_Point_Preload(x,y,draw);//预加载显存
OLED_PageRam_Load(page_address,OLED_Page_Rom[page_address]);//发送显存
}

标签:设置,uint8,OLED,IIC,使用,I2C,I2C1,STM32OLED
From: https://www.cnblogs.com/tqht7h/p/18047994

相关文章

  • 自定义 DataLoader 时应使用 Unix 系统
    自定义Dataset类PyTorch允许自定义Dataset类,并由此获得DataLoader,能方便训练时获得batch:fromtorch.utils.dataimportDataLoader,Datasetimporth5pyimportosclassRadarDataset(Dataset):def__init__(self,directory):...def__len__(s......
  • STM32硬件IIC使用
    STM32硬件IIC使用.md概述虽然STM32的硬件IIC据说有设计缺陷,但是经过我的实践,至少STM32F103的硬件IIC是没问题的。这里给出STM32的硬件IIC的使用以及编程思路。1.STM32硬件IIC引脚在这里给出STM32F103的硬件IIC引脚,方便查阅使用2.STM32硬件IIC使用流程STM32的硬件IIC我认......
  • 【Azure Logic App】在中国区的微软云服务上,使用逻辑应用是否可以下载SharePoint上的
    问题描述在中国区的微软云服务上,使用逻辑应用是否可以下载SharePoint上的文件呢?目前遇见的问题时,选择LogicApp的SharePoint组件,登录SharePoint账号时,只能选择中国区的登录账号,不能使用GlobalSharepoint账号。问题解答AzureChina的LogicApp中的SharepointConnector只能......
  • 在 Spring Boot 3.x 中使用 SpringDoc 2 / Swagger V3
    SpringDocV1只支持到SpringBoot2.xspringdoc-openapiv1.7.0isthelatestOpenSourcereleasesupportingSpringBoot2.xand1.x.SpringBoot3.x要用SpringDoc2/SwaggerV3,并且包名也改成了springdoc-openapi-starter-webmvc-uiSpringDocV2https://spr......
  • 使用-solidity-开发第一个-以太坊智能合约
    目录目录使用solidity开发第一个以太坊智能合约前言项目源代码最终效果环境搭建智能合约内容Truffle创建项目Truffle编码Truffle打包Truffle部署修改编译器版本0.8.19Truffle测试创建测试文件运行测试命令Dapp命令总结遇到的问题注意Solidity......
  • Ubuntu中安装使用QEMU/KVM/virt-manager运行虚拟机
    本文为原创,原文发布于个人博客网站:Ubuntu中安装使用QEMU/KVM/virt-manager运行虚拟机有时候我们需要在同一台计算机中使用多种不同操作系统环境,基于已有的同一堆硬件资源来获得不同操作系统各自的便利性。对此,常用的解决方案主要有:在物理机器中安装使用双系统在宿主系统中安......
  • 使用 chrome 的本地 Mock 功能
    1.前言   过去,本地调试要用mock的话,需要我们可以通过代理的方式去hack的实现或者使用其它的工具实现,但是现在再也不用这么麻烦了,chrome原生就支持了,而且体验相当丝滑 2.使用方法  如果你的chrome浏览器没有以下功能,则需要更新到最新的版本第一步:找到需要mock的......
  • (笔记)Linux下glog日志库的详细使用方法
     Glog是一个开源的C++日志库,它提供了非常方便的日志记录功能。下面是使用Glog的详细步骤: 一、安装Glog库您可以从Glog的官方网站(https://github.com/google/glog)下载Glog的源代码,然后进行编译和安装。在Linux系统下,您可以使用以下命令安装Glog库:sudoapt-getinstalllibg......
  • Flutter widget_id: key 的使用
    Flutterwidgetid(唯一标识):keykey的作用Key是一个附加到元素(widgets,semantics,renderobjects等)的标识符。它用于控制框架是否应将旧widget与当前树中的其他widget匹配起来。简单来说,Keys的作用主要在于保持状态和在widget树重建时识别哪些widget是相同的。key的......
  • 【HarmonyOS】一招教你在竖屏的UIAbility中使用横屏页面
    ​【关键字】鸿蒙应用开发、ArkTS、UIAbility、横屏页面显示 1、写在前面我们在实际的项目开发过程中,可能会遇到这样的需求:在一个手机应用中,A页面是竖屏展示的,点击A页面的某个按钮需要跳转到B页面,但是B页面需要横屏展示,比如查看海报或者表格信息等内容,在HarmonyOS中,在不增加......