STM32之OLED显示

news/2024/2/23 14:42:14/文章来源:https://blog.csdn.net/weixin_52483742/article/details/135583663

一、模块介绍

1、常见的显示设备

LED、数码管、点阵、LCD屏(1602/12864)、OLED屏(消费电子)

2、OLED屏的概述

OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。因为具备轻薄、省电等特性,因此从2003 年开始,这种显示设备在 MP3 播放器上得到了广泛应用,而对于同属数码类产品的 DC与手机,此前只是在一些展会上展示过采用 OLED 屏幕的工程样品。自 2007 年后,寿命得到很大提高,具备了许多 LCD 不可比拟的优势

3、特性

型号:SH1106

尺寸:132 * 64个像素点(前两列和最后的两列显示不了东西)

像素点:一帧画面所能表示的最小的显示单位。

分辨率:横向像素点的个数 * 竖向像素点个数

通信方式:

硬线接线四线SPI的通信方式

二、硬件分析

1、引脚分布

A0管脚如果是低电平就是发送命令过去

A0管脚如果是高电平就是发送显示数据过去

OLED_SCL -- 时钟线

(MOSI)OLED_SI -- 输入对于OLED的驱动芯片

OLED_CS -- 片选线

OLED_RES -- 复位管脚

OLED_D/C -- 命令或数据引脚

IO口模拟SPI

使用SPI控制器

三、SPI通信

1、通信特点

4线SPI:同步串行全双工

3线SPI:同步串行半双工

2、通信速度

几十Mhz以上

3、通信模式

MODE0和MODE3:上升沿接收数据,下降沿发送数据

MODE1和MODE2:下降沿接收数据,上升沿发送数据

器件支持MODE0模式也支持MODE3,支持MODE1模式也支持MODE2

4、通讯图

四、软件编写

1、时序图

1. CS线要拉低
2. SPI符合模式0或者模式3,上升沿接收数据,下降沿发送数据
3. A0线拉低代表把刚刚传输过去的八位数据给到命令寄存器里,拉高代表传输到显存

2、OLED相关命令

假如现在想要从第1页开始显示就要把0xB0的指令发送出去

设置列地址分为了高四字节和低四字节

如果要去设置列地址就要分两次命令发送

当前如果要在第1列显示数据:

发送低位的列地址就是00

发送高位的列地址就是10

3、字模提取:

4、图像提取

五、流程

1、初始化GPIO口

复用功能

复用到哪里

PB3 -- SCL -- SPI1_SCL

PB5 -- SI -- SPI1_MOSI

PB13 -- RES -- 推挽输出

PB7 -- CS --  推挽输出

PA15 -- DC --  推挽输出

2、初始化SPI控制器

使用库函数:

先打开外设时钟

找Init函数

#include "spi.h"/****************************
函数功能:SPI管脚初始化
函数形参:u32 nms
函数返回值:void
函数说明:
PB3 -- SCL -- SPI1_SCL
PB5 -- SI -- SPI1_MOSI
PB13 -- RES -- 推挽输出
PB7 -- CS --  推挽输出
PA15 -- DC --  推挽输出
****************************/
void Spi_Port_Init(void)
{GPIO_InitTypeDef  GPIO_InitStruct;//定义了一个结构体变量SPI_InitTypeDef   SPI_InitStruct;  //1. 打开GPIOA的时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//2. 配置GPIO口功能GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//配置输出模式GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//配置为推挽GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_13;//选择7号管脚GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;//低速GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;//选择15号管脚GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//配置复用模式GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5;//选择3和5号管脚GPIO_Init(GPIOB, &GPIO_InitStruct); //3.复用到哪里GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);//4.SPI控制器初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//选择二分频SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge;//前沿采集SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low;//空闲时为低电平SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b;//8位数据为一帧SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//选择全双工SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;//高位先发SPI_InitStruct.SPI_Mode = SPI_Mode_Master;//主模式SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;//软件从模式管理SPI_Init(SPI1,&SPI_InitStruct);SPI_Cmd(SPI1,ENABLE);//使能SPI1}/****************************
函数功能:SPI发送一个字节数据
函数形参:u8 data
函数返回值:void
函数说明:****************************/
void Spi_SendByte(u8 data)
{while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET)//当前发送缓冲区为空才能跳出循环{}SPI_I2S_SendData(SPI1,data);//发送数据while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET)//当前接收缓冲区为空才能跳出循环{}SPI_I2S_ReceiveData(SPI1);//接收数据}
#include "oled.h"/**********************************************************************************************************
* 函数名    :   OLED_writeByte
* 功能描述  :   oled字节写,向SH1106写入一个字节。 
* 参数说明  :   dat:要写入的数据/命令
* cmd:数据/命令标志 0,表示命令;1,表示数据;
* 返回值说明:   none
* 修改记录  : 
* 其他      :
**********************************************************************************************************/
void OLED_writeByte(u8 dat, u8 cmd)
{	cmd ? OLED_DC_SET() : OLED_DC_CLR();	OLED_select();		 Spi_SendByte(dat);OLED_deSelect();
} /**********************************************************************************************************
* 函数名    :   OLED_clear
* 功能描述  :   清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	 
* 参数说明  :   none
* 返回值说明:   none
* 修改记录  : 
* 其他      :OLED;8页,每页132字节,
清屏:首先清除第1页,从第一个字节开始2
前面 & 后面 4列 因边框问题不处理
**********************************************************************************************************/
void OLED_clear(void)  
{  u8 i,n;		    for(i=0;i<8;i++)  //8页{  OLED_writeByte (0xb0+i,OLED_CMD);    //设置页地址(0~7)//从第2列(0x02)开始OLED_writeByte (0x02,OLED_CMD);      //设置显示位置—列低地址OLED_writeByte (0x10,OLED_CMD);      //设置显示位置—列高地址   for(n=0; n<130; n++)//到第130列{OLED_writeByte(0,OLED_DATA);   //息屏整个屏幕是黑色的!和没点亮一样!!!	}} //更新显示
}   /**********************************************************************************************************
* 函数名    :   Oled_init
* 功能描述  :   oled初始化 
* 参数说明  :   none
* 返回值说明:   none
* 修改记录  : 
* 其他      :
**********************************************************************************************************/void Oled_init(void)
{ Spi_Port_Init();	//管脚初始化OLED_RES_L;Delay_ms(100);OLED_RES_H;OLED_writeByte(0xAE,OLED_CMD);//--turn off oled panelOLED_writeByte(0x02,OLED_CMD);//---SET low column addressOLED_writeByte(0x10,OLED_CMD);//---SET high column addressOLED_writeByte(0x40,OLED_CMD);//--SET start line address  SET Mapping RAM Display Start Line (0x00~0x3F)OLED_writeByte(0x81,OLED_CMD);//--SET contrast control registerOLED_writeByte(0xCF,OLED_CMD); // SET SEG Output Current BrightnessOLED_writeByte(0xA1,OLED_CMD);//--SET SEG/Column Mapping     0xa0左右反置 0xa1正常OLED_writeByte(0xC8,OLED_CMD);//SET COM/Row Scan Direction   0xc0上下反置 0xc8正常OLED_writeByte(0xA6,OLED_CMD);//--SET normal displayOLED_writeByte(0xA8,OLED_CMD);//--SET multiplex ratio(1 to 64)OLED_writeByte(0x3f,OLED_CMD);//--1/64 dutyOLED_writeByte(0xD3,OLED_CMD);//-SET display offSET	Shift Mapping RAM Counter (0x00~0x3F)OLED_writeByte(0x00,OLED_CMD);//-not offSETOLED_writeByte(0xd5,OLED_CMD);//--SET display clock divide ratio/oscillator frequencyOLED_writeByte(0x80,OLED_CMD);//--SET divide ratio, SET Clock as 100 Frames/SecOLED_writeByte(0xD9,OLED_CMD);//--SET pre-charge periodOLED_writeByte(0xF1,OLED_CMD);//SET Pre-Charge as 15 Clocks & Discharge as 1 ClockOLED_writeByte(0xDA,OLED_CMD);//--SET com pins hardware configurationOLED_writeByte(0x12,OLED_CMD);OLED_writeByte(0xDB,OLED_CMD);//--SET vcomhOLED_writeByte(0x40,OLED_CMD);//SET VCOM Deselect LevelOLED_writeByte(0x20,OLED_CMD);//-SET Page Addressing Mode (0x00/0x01/0x02)OLED_writeByte(0x02,OLED_CMD);//OLED_writeByte(0x8D,OLED_CMD);//--SET Charge Pump enable/disableOLED_writeByte(0x14,OLED_CMD);//--SET(0x10) disableOLED_writeByte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)OLED_writeByte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) OLED_writeByte(0xAF,OLED_CMD);//--turn on oled panelOLED_writeByte(0xAF,OLED_CMD); /*display ON*/ OLED_clear();	
}  /**********************************************************************************************************
* 函数名    :   OLED_setPos
* 功能描述  :   
* 参数说明  :  X: 列坐标  0----131Y: 页坐标  0----7列总共由8个位组成
* 返回值说明:   none
* 修改记录  : 
* 其他      :  **********************************************************************************************************/
void OLED_setPos(unsigned char x, unsigned char y) //34 - 0010 0010
{ x += 2;//SSH1106 要加这个y &= 7;//保证页的地址不超OLED_writeByte(0xb0+y,OLED_CMD); //设置页地址OLED_writeByte(((x&0xf0)>>4)|0x10, OLED_CMD);//设置显示位置—列高地址//0010 0010 & 1111 0000//0010 0000 >> 4 -- 0000 0010OLED_writeByte((x&0x0f),OLED_CMD); //0010 0010 & 0000 1111 -- 0000 0010
}  /**********************************************************************************************************
* 函数名    :   Show_Signal_Word
* 功能描述  :   显示单个字符
* 参数说明  :   u8 page, u8 col, u8 ch
* 返回值说明:   none
* 修改记录  : 
* 其他      :
**********************************************************************************************************/
void Show_Signal_Word(u8 page, u8 col, u8 ch)//'a' -- 97
{u8 i;u8 n;u8 index = ch - ' ';//得到当前这个字符在ASCII_816的位置,97 - 32 = 65if(col > 120){col = 0;page += 2;}OLED_setPos(col,page);//由于一页只有八行,一个字符有16行,所以需要换两页for(i = 0; i < 2; i++){//由于一个字符只有8列for(n=0; n< 8; n++)//到第130列{OLED_writeByte(ASCII_816[index*16 + i*8 + n],OLED_DATA);   //息屏整个屏幕是黑色的!和没点亮一样!!!	}OLED_setPos(col,page+1);}
}/**********************************************************************************************************
* 函数名    :   Show_String
* 功能描述  :   显示字符串
* 参数说明  :   u8 page, u8 col, u8 *str, u8 num
* 返回值说明:   none
* 修改记录  : 
* 其他      :
**********************************************************************************************************/
void Show_String(u8 page, u8 col, u8 *str, u8 num)//"sakdjfhjk",0
{u8 i;OLED_setPos(col,page);for(i = 0; i < num; i++){Show_Signal_Word(page,col,*str);str++;col += 8;//为了保证下一个字符和前一个字符不重合,根据字体大小所以+8if(col > 120){col = 0;page += 2;}OLED_setPos(col,page);}
}/**********************************************************************************************************
* 函数名    :   Show_Chinese
* 功能描述  :   显示字符串
* 参数说明  :   u8 page, u8 col, u8 *str, u8 num
* 返回值说明:   none
* 修改记录  : 
* 其他      :
**********************************************************************************************************/
void Show_Chinese( u8 page, u8 col, u8 *str, u8 num)
{u8 i,j;u8 n;if(col > 112){col = 0;page += 2;}OLED_setPos(col,page);for(j = 0; j < num; j++){for(i = 0; i < 2; i++){//由于一个字符只有8列for(n=0; n < 16; n++)//代表有16列的数据{OLED_writeByte(str[j *32 + i*16 + n],OLED_DATA);   //息屏整个屏幕是黑色的!和没点亮一样!!!	}OLED_setPos(col,page+1);}col += 16;if(col > 112){col = 0;page += 2;}OLED_setPos(col,page);}
}/**********************************************************************************************************
* 函数名    :   Show_Pic
* 功能描述  :   显示图片
* 参数说明  :   u8 page, u8 col, u8 *pic
* 返回值说明:   none
* 修改记录  : 
* 其他      :
**********************************************************************************************************/
void Show_Pic(u8 page, u8 col, u8 *pic)
{u8 weight = pic[2];u8 height = pic[4];u8 i,j;pic += 6;//先偏移掉数据头的数据if(weight > 129 - col){col = 0;page += 2;}OLED_setPos(col,page);for(i = 0; i < height / 8; i++){for(j = 0;j < weight; j++){OLED_writeByte(*pic,OLED_DATA);pic++;}page += 1;OLED_setPos(col,page);}}

STM32之SPI总线-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_926247.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css宽度适应内容

废话不多说,看如下demo,我需要将下面这个盒子的宽度变成内容自适应 方法有很多,如下 父元素设置display:flex 实现子元素宽度适应内容 如下给父元素设置flex能实现宽度自适应内容 <!DOCTYPE html><html lang"en"><head><meta charset"U…

C++每日一练(15):简单幂计算

题目描述 输入两个数a和b&#xff0c;求a的b次方。 输入 输入两个整数a&#xff0c;b&#xff08;1<a<10&#xff0c;1<b<15&#xff09;。 输出 输出一个正整数&#xff0c;该值<1000000000000。 输入样例 3 3 输出样例 27 参考答案 #include<bits/stdc.h&…

C++常用类

1、QString 字符串类 QString 是Qt的字符串类&#xff0c;与C的std::string相比&#xff0c;不再使用ASCII编码。QString使用的Unicode编码。 QString 完全支持中文&#xff0c; 但是由于不同的技术可能会采用不同的编码。有时候也会遇到中文编码的一致性问题。 如果后续的学习…

无人机测绘助力实现高效、安全的城市规划

随着城市化进程的不断加快&#xff0c;城市规划显得尤为重要。而无人机测绘技术作为一种创新的工具&#xff0c;为城市规划提供了更加高效、安全的解决方案。它通过快速、精确的数据采集和分析&#xff0c;为行业提供有力的决策支持&#xff0c;助力城市规划的现代化和可持续发…

LeetCode刷题---基本计算器

解题思路&#xff1a; 根据题意&#xff0c;字符串中包含的运算符只有和- 使用辅助栈的方法来解决该问题 定义结果集res和符号位sign(用于判断对下一数的加减操作),接着对字符串进行遍历。 如果当前字符为数字字符&#xff0c;判断当前字符的下一个字符是否也是数字字符&#x…

决战排序之巅(二)

决战排序之巅&#xff08;二&#xff09; 排序测试函数 void verify(int* arr, int n) 归并排序递归方案代码可行性测试 非递归方案代码可行性测试 特点分析 计数排序代码实现代码可行性测试 特点分析 归并排序 VS 计数排序&#xff08;Release版本&#xff09;说明1w rand( ) …

Kafka 消息不能正常消费问题排查

订单宽表数据不同步 事情的起因是专员在 ze app 上查不到订单了&#xff0c;而订单数据是从 mysql 的 order_search_info 查询的&#xff0c;order_search_info 表的数据是从 oracel 的 BZ_ORDER_INFO 表同步过来的&#xff0c;查不到说明同步有问题 首先重启&#xff0c;同步…

【K8S 】K8S配置资源管理

一、Secret&#xff1a; 1、概念 用来保存密码。token&#xff0c;敏感的K8S资源 这类数据可以直接存放在镜像中&#xff0c;但是放在Secret中可以更方便的控制&#xff0c;减少暴露的风险 Secret&#xff1a;保存加密的信息 2、Secret类型&#xff1a; docker-registry&am…

第十二章 Java内存模型与线程(二)

文章目录 12.4 Java与线程12.4.1 线程的实现12.4.2 Java线程调度12.4.3 状态转换 12.5 Java与协程12.5.1 内核线程的局限12.5.2 协程的复苏12.5.3 Java的解决方案 12.4 Java与线程 12.4.1 线程的实现 实现线程主要有三种方式&#xff1a;使用内核线程实现&#xff08;1&#…

算法通关村第十六关—滑动窗口与堆结合(黄金)

滑动窗口与堆结合 堆与滑动窗口问题的结合 LeetCode239给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位&#xff0c;返回滑动窗口中的最大值。  对于最大值、K个最大这种场…

【教3妹学编程-算法题】最大频率元素计数

2哥 : 3妹&#xff0c;最近有个电视剧《繁花》非常火&#x1f525;&#xff0c;你听说了吗&#xff1f; 3妹&#xff1a;没有&#xff0c;最近一直在忙着找工作&#xff0c;哪有时间看电视啊 2哥 : 啊&#xff1f;大周末还不休息一下啊&#xff0c;这么辛苦。 3妹&#xff1a;当…

压力测试JMeter

一、JMeter概述 Apache JMeter是100%纯JAVA桌面应用程序&#xff0c;被设计为用于测试客户端/服务端结构的软件(例如web应用程序)。它可以用来测试静态和动态资源的性能&#xff0c;例如&#xff1a;静态文件&#xff0c;Java Servlet,CGI Scripts,Java Object,数据库和FTP服务…

k8s node节点加入集群,token过期

1、master01节点执行 kubeadm token create --print-join-command 2、执行命令 kubeadm join 192.168.0.236:16443 --token qucd8q.hsfq4a1afluzaky3 --discovery-token-ca-cert-hash sha256:92175a356db070deb2ddd3823e288e3005a4baeec9b68580dcc11ce4d3767195 3、查看node02…

FPGA节省资源篇------正确处理设计优先级

声明&#xff1a;以下文章来源于孤独的单刀&#xff0c;仅供学习用途 概述 假如现在有一种方法–可以在不怎么需要修改已有设计的情况下&#xff0c;就可以帮您节省50%的设计资源&#xff0c;那你会试试看吗&#xff1f; 当前市场环境下&#xff0c;更低廉的成本却可获得同等…

steam游戏搬砖项目还能火多久?

最近放假回到老家&#xff0c;见了不少亲戚朋友&#xff0c;大家不约而同都在感叹今年大环境不好&#xff0c;工作不顺&#xff0c;生意效益不好&#xff0c;公司状况不佳&#xff0c;反问我们生意如何&#xff1f;为了让他们心里好受一点&#xff0c;我也假装附和道:也不咋地&…

3000多个厂商默认帐号、默认密码

做网工这行&#xff0c;多少都会遇上各种各样的厂商设备&#xff0c;遇上一些新设备&#xff0c;虽然没有更改密码&#xff0c;但不知道初始默认账号和密码是啥。 今天就给你整理了一波&#xff0c;三千多个厂商默认帐号、默认密码&#xff0c;方便你查阅。 不过&#xff0c;…

自创C++题目——风扇

预估难度 简单 题目描述 有一个风扇&#xff0c;它有个旋转叶片&#xff0c;每个旋转叶片的编号是&#xff0c;请输出它旋转后&#xff0c;中心点与地面的直线距离哪个叶片最近&#xff0c;输出此旋转叶片的编号。默认以“”的形式。 当时&#xff1a; 当或时&#xff0c;…

MATLAB二维与三维绘图实验

本文MATLAB源码&#xff0c;下载后直接打开运行即可[点击跳转下载]-附实验报告https://download.csdn.net/download/Coin_Collecter/88740747 一、实验目的 掌握图形对象属性的基本操作。掌握利用图形对象进行绘图操作的方法。 二、实验内容 利用图形对象绘制曲线&#xff…

Java基础 - 黑马

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 知…

最佳实践分享:SQL性能调优

SQL性能调优是一个需要不断探索和实践的过程&#xff0c;旨在确保数据库查询的高效运行。本文将分享一些SQL性能调优的最佳实践&#xff0c;帮助您提升数据库性能&#xff0c;减少查询响应时间。 一、索引优化 索引是提高查询性能的关键。以下是一些关于索引优化的建议&#…