STM32F103-OLED使用教程

news2025/3/15 18:15:23

目录

  • 1. OLED屏介绍
  • 2. OLED如何显示一个点
  • 3. 配置OLED屏幕
  • 4. OLED显示字符串和汉字
  • 5. OLED屏幕显示图片
  • 6. 总结

1. OLED屏介绍

  • OLED(Organic Light Emitting Diode):有机发光二极管
  • OLED显示屏:性能优异的新型显示屏,具有功耗低、相应速度快、宽视角、轻薄柔韧等特点
    本文使用的是0.96寸OLED模块,小巧玲珑、占用接口少、简单易用,是电子设计中非常常见的显示屏模块。

OLED屏幕特点

供电:3~5.5V
通信协议:I2C/SPI
分辨率:128*64

OLED屏分两种,一种是4针OLED,通过IIC总线通信,另一种是7针OLED,通过SPI总线通信如下图所示:

本文使用的为4针OLED屏,接线说明如下:

在这里插入图片描述

OLED屏幕显存

在这里插入图片描述
OLED本身是没有显存的,他的现存是依赖SSD1306提供的,而SSD1306提供一块显存。
SSD1306显存总共为128*64bit大小,SSD1306将这些显存分成了8页。每页包含了128个字节。

OLED屏幕原理

STM32内部建立一个缓存(共128*8个字节),每次修改的时候,只是修改STM32上的缓存(实际上就是SRAM),修改完后一次性把STM32上的缓存数据写入到OLED的GRAM。这个方法也有坏处,对于SRAM很小的单片机(51系列)就比较麻烦。

OLED屏幕常用指令

在这里插入图片描述

  • 0X81: 设置对比度。包含两个字节,第一个0X81为命令,随后方法是的一个字节要设置这个对比度,值越大屏幕越亮。

  • 0XAE/0XAF: 0XAE为关闭显示命令,0XAF为开启显示命令。

  • 0X8D: 电荷泵设置,包含两个字节,第一个为命令字,第二个为设置值,第二个字节的BIT2表示电荷泵的开关状态,该位为1开启电荷泵,为0则关闭。模块初始化的时候,这个必须要开启,否则看不到屏幕显示。

  • 0XB0~B7:用于设置页地址,其低三位的值对应GRAM页地址。

  • 0X00~0X0F:用于设置显示时的起始列地址低四位。

  • 0X10~0X1F: 用于设置显示时的起始列地址高四位。

2. OLED如何显示一个点

OLED屏幕分为页寻址模式,水平地址模式,垂直地址模式。
本文主要介绍用的最多的页寻址模式,页寻址模式如下图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

首先把整个OLED屏幕分成八页,也就是把OLED的屏幕把宽平均分成了八份。
比如,想在第3行第0列的开头显示一个点,那就是按位来配置,0000 1000(0x08)。

3. 配置OLED屏幕

我们配置硬件IIC的步骤就是根据下面这张时序图,发送一次数据后不断获取不同的应答即可。
在这里插入图片描述

硬件IIC配置:

#include "stm32f10x.h"
#include "oled.h"
 
void IIC_Configuration(void)
{
	 GPIO_InitTypeDef  GPIO_InitStructure;
	 I2C_InitTypeDef   I2C_InitStructure;
	
	 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE	);
     RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C1, ENABLE	);
	 
	 //PB6--SCL   PB7--SDL
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	 GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	 I2C_DeInit(I2C1);
	 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	 I2C_InitStructure.I2C_ClockSpeed = 400000;
	 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	 I2C_InitStructure.I2C_OwnAddress1 = 0x30;
     I2C_Init(I2C1, &I2C_InitStructure);
	 I2C_Cmd(I2C1, ENABLE);
 
}
 
void I2C_WriteByte(uint8_t addr,uint8_t data)
{
	while( I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); //检查IIC总线是否繁忙
	
	I2C_GenerateSTART(I2C1, ENABLE);  //开启IIC,发送起始信号
	while(!I2C_CheckEvent(I2C1,  I2C_EVENT_MASTER_MODE_SELECT)); //EV5主模式
 
	I2C_Send7bitAddress(I2C1, OLED_ADDRESS ,  I2C_Direction_Transmitter);  //发送OLED地址
	while(!I2C_CheckEvent(I2C1,  I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //检查EV6
	
	I2C_SendData(I2C1, addr); //发送寄存器地址
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
	
    I2C_SendData(I2C1, data); //发送数据
	while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
 
    I2C_GenerateSTOP(I2C1, ENABLE);
}

写命令函数&写数据函数:

void WriteCmd(unsigned char IIC_Command)  //写命令
{
	 I2C_WriteByte(0x00,IIC_Command);
}
 
void WriteDat(unsigned char IIC_Data)  //写数据
{
	 I2C_WriteByte(0x40,IIC_Data);
}

OLED初始化:

void OLED_Init(void) //OELD屏幕初始化
{
  delay_ms(100);
	WriteCmd(0xAE); //display off
	WriteCmd(0x20);	//Set Memory Addressing Mode	
	WriteCmd(0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	WriteCmd(0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
	WriteCmd(0xc8);	//Set COM Output Scan Direction
	WriteCmd(0x00); //---set low column address
	WriteCmd(0x10); //---set high column address
	WriteCmd(0x40); //--set start line address
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //ÁÁ¶Èµ÷½Ú 0x00~0xff
	WriteCmd(0xa1); //--set segment re-map 0 to 127
	WriteCmd(0xa6); //--set normal display
	WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	WriteCmd(0xd3); //-set display offset
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
	WriteCmd(0xf0); //--set divide ratio
	WriteCmd(0xd9); //--set pre-charge period
	WriteCmd(0x22); //
	WriteCmd(0xda); //--set com pins hardware configuration
	WriteCmd(0x12);
	WriteCmd(0xdb); //--set vcomh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--set DC-DC enable
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--turn on oled panel
}

设置起点坐标:

void SetPos(unsigned char x,unsigned char y)  //设置起点坐标
{
	WriteCmd(0xb0+y);
	WriteCmd((x&0xf0)>>4|0x10); //取高位
	WriteCmd((x&0x0f)|0x01);    //取低位

全屏填充(可以全屏填充,也可用于清屏):

void OLED_Fill(unsigned char Fill_Data)  //全屏填充
{
	unsigned char m,n;
	
	for(m=0;m<8;m++){
		WriteCmd(0xb0+m);
		WriteCmd(0x00);
		WriteCmd(0x10);
	
	  for(n=0;n<128;n++){
		WriteDat(Fill_Data);
		}
	}
}

清屏:

void OLED_Clean(void)  //清屏
{
	OLED_Fill(0x00);
}

打开/关闭OLED:

void OLED_ON(void)   //打开OLED
{
	WriteCmd(0X8D);   //设置电荷泵
	WriteCmd(0X14);   //开启电荷泵
	WriteCmd(0XAF);   //OLED唤醒
}
 
void OLED_OFF(void)  //关闭OLED
{
	WriteCmd(0X8D);   //设置电荷泵
	WriteCmd(0X10);   //关闭电荷泵
	WriteCmd(0XAE);   //关闭OLED
}

4. OLED显示字符串和汉字

OLED显示字符串:

//显示字符串
void OLED_ShowStr(unsigned char x,unsigned char y,unsigned char ch[],unsigned TextSize)
{
    unsigned char c = 0,i = 0,j = 0;
	  switch(TextSize)
		{
			case 1:   //8*16模式
			{
				while(ch[j] != '\0')
				{
				   c = ch[j] - 32;
					if(x>126)
					{
					    x= 0;
						  y++;					
					}
					OLED_SetPos(x,y);
					for(i=0;i<6;i++)
           WriteDat( F6x8[c][i] );
					x+=6 ;
					j++;				
				}
				
				}break;
			case 2:    //16*16模式
			{
			   while(ch[j] !='\0')
				 {
						 c= ch[j] - 32;
					 if(x >120)
					 {
							 x = 0;
							 y++ ;
					 }
					 OLED_SetPos(x,y);
					 for(i = 0;i<8;i++)
					 WriteDat( F8X16[c*16+i] );
					 OLED_SetPos(x,y+1);
					 for(i = 0;i<8;i++)
					 WriteDat( F8X16[c*16+i+8] );
					 x+=8;
					 j++;
			 }	 
		}break;
			
	}
}	

OLED显示汉字:

//显示汉字 (x:横坐标  y:纵坐标  N:字数)
void OLED_ShowCN(unsigned char x,unsigned char y,unsigned char N)
{
    unsigned char wm=0;
	  unsigned int addr = 32*N;
		OLED_SetPos(x,y);
    for(wm=0;wm<16;wm++)
	{
		WriteDat( F16X16[addr]);
    addr +=1;	
	}
	 OLED_SetPos(x,y+1);
   for(wm=0;wm<16;wm++)
	{
		WriteDat( F16X16[addr]);
    addr +=1;	
	}
 
}

然后通过取字模软件(PCtoLCD2002),输入我们想显示的汉字和大小,通过软件生成字库,再添加到我们代码中的字库文件里。

以我自己的工程为例,如下:
在这里插入图片描述

5. OLED屏幕显示图片

//显示图片
//x0:横坐标;y0:纵坐标;x1:图片起点;y1:所占页数;BMP[]:选用的结构体名称
void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
	unsigned int j=0;
	unsigned char x,y;
	
	if(y1%8 == 0)
		y = y1/8;
	else
		y = y1/8 +1;
	for(y=y0;y<y1;y++)
	{
				OLED_SetPos(x0,y);
       for(x=x0;x<x1;x++)
		{	
				WriteDat(BMP[j++]);
		}		
	}
}

步骤:

  1. 选一张照片,保存格式改为.png
  2. 将大小调整为跟我们的屏幕一样的分辨率(128*64)
  3. 改完大小之后再保存为BMP格式。
  4. 打开我们的取模软件(Image2Lcd v2.9),生成一个文档。
  5. 然后把数组里面的内容粘贴到BMP1的数组里面。

最终效果:在这里插入图片描述

6. 总结

本文使用的是4针OLED屏,是通过硬件IIC驱动,当然大家也可以通过软件IIC实现,使用引脚更加灵活。同时大家也可以使用7针的OLED屏,通过SPI进行驱动。
文献:https://blog.csdn.net/aaaaaaaa123345/article/details/124350330

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue组件(详解)

目录 组件&#xff1a; 全局组件&#xff1a; 在HTML页面声明template&#xff1a; 局部组件&#xff1a; 局部组件第一种方式&#xff1a; 局部组件第二种方式&#xff1a; 插槽slot&#xff1a; 匿名插槽&#xff1a; 具名插槽&#xff1a; 父子组件通信&#xff1…

【双指针_和为 s 的两个数_C++】

和为s的两个数字 class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {int n nums.size();int left 0;int right n-1;while(left<right){if(nums[left]nums[right]>target) right--;else if(nums[left]nums[right]<tar…

Postman接口自动化测试实例

一.实例背景 在实际业务中&#xff0c;经常会出现让用户输入用户密码进行验证的场景。而为了安全&#xff0c;一般都会先请求后台服务器获取一个随机数做为盐值&#xff0c;然后将盐值和用户输入的密码通过前端的加密算法生成加密后串传给后台服务器&#xff0c;后台服务器接到…

车载以太网物理层

车载以太网物理层 O S I 参考模型的第 1 层&#xff08; 最底层&#xff09;。负责逻辑信号&#xff08; 比特流&#xff09;与物理信号&#xff08;电信号、光信号&#xff09;之间的互相转换&#xff0c;通过传输介质为数据链路层提供物理连接。 车载以太网与传统以太网相比…

matlab使用教程(16)—图论中图的定义与修改

1.修改现有图的节点和边 此示例演示如何使用 addedge 、 rmedge 、 addnode 、 rmnode 、 findedge 、 findnode 及 subgraph 函数访问和修改 graph 或 digraph 对象中的节点和/或边。 1.1 添加节点 创建一个包含四个节点和四条边的图。s 和 t 中的对应元素用于指定每条…

【教程】零成本将小米净化器改造为无叶风扇

某宝某多上&#xff0c;就这么点破塑料&#xff0c;就要买79&#xff1f;&#xff01;&#xff01; 我这枚韭菜可不上当。咱自己做一个&#xff01; 真香~

BBS项目day02、注册、登录(登录之随机验证码)、修改密码、退出登录、密码加密加盐

一、注册 1.注册之前端页面 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>注册页面</title><!--动态引入文件-->{% load static %}<script src"{% static js/jquery.min.js %…

jquery技术学习2

移动节点 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>移动节点</title><script type"text/javascript" src"../script/jquery-3.6.0.min.js"></script>&l…

【Spring】深入理解 Spring 事务及其传播机制

文章目录 一、Spring 事务是什么二、Spring 中事务的实现方法2.1 Spring 编程式事务&#xff08;手动&#xff09;2.1.1 编程式事务的使用演示2.1.2 编程式事务存在的问题 2.2 Spring 声明式事务&#xff08;自动&#xff09;2.2.1 Transactional 作用范围2.2.2 Transactional …

化繁为简,使用Hibernate Validator实现参数校验

前言 在之前的悦享校园的开发中使用了SSM框架&#xff0c;由于当时并没有使用参数参数校验工具&#xff0c;方法的入参判断使用了大量的if else语句&#xff0c;代码十分臃肿&#xff0c;因此最近在重构代码时&#xff0c;将框架改为SpringBoot后&#xff0c;引入了Hibernate V…

HCIP MPLS实验

MPLS实验 拓扑MPLS VPN配置PE与PE间建立MP-BPG邻居关系R7访问R2,R3,R4环回 拓扑 MPLS VPN配置 首先可以用OSPF协议将R2,R3,R4跑通&#xff0c;然后配置MPLS [R2]mpls lsr-id 2.2.2.2 定义MPLS的router-id&#xff0c;要为本地设备的真实ip地址&#xff0c;且邻居可达&#…

机器学习算法之-逻辑回归(2)

为什么需要逻辑回归 拟合效果太好 特征与标签之间的线性关系极强的数据&#xff0c;比如金融领域中的 信用卡欺诈&#xff0c;评分卡制作&#xff0c;电商中的营销预测等等相关的数据&#xff0c;都是逻辑回归的强项。虽然现在有了梯度提升树GDBT&#xff0c;比逻辑回归效果更…

【学习FreeRTOS】第8章——FreeRTOS列表和列表项

1.列表和列表项的简介 列表是 FreeRTOS 中的一个数据结构&#xff0c;概念上和链表有点类似&#xff0c;列表被用来跟踪 FreeRTOS中的任务。列表项就是存放在列表中的项目。 列表相当于链表&#xff0c;列表项相当于节点&#xff0c;FreeRTOS 中的列表是一个双向环形链表列表的…

【大数据之Kafka】三、Kafka生产者之消息发送流程及同步异步发送API

将外部传送给过来的数据发送到kafka集群。 1 发送原理 &#xff08;1&#xff09;创建main()线程&#xff0c;创建producer对象&#xff0c;调用send方法&#xff0c;经过拦截器&#xff08;可选&#xff09;、序列化器、分区器。 &#xff08;2&#xff09;分区器将数据发送…

java面试题(16):Mysql一致性视图是啥时候建立的

1 演示错误案例 先给大家来一个错误演示。 我们打开两个会话窗口&#xff0c;默认情况下隔离级别是可重复读&#xff0c;我们来看下&#xff1a; 首先在 A 会话中查看当前 user 表&#xff0c;查看完成后开启事务&#xff1a; 可以看到id3的数据sex是男。 接下来在 B 会话中…

场景入门12----关卡切换和流送

在游戏时往往需要切换关卡&#xff0c;有两种方法&#xff0c;关卡切换和推送。关卡切换的方法是进入了一个新的地图&#xff0c;这时人物的值都复原了&#xff0c;一般都是在一个地图上推送关卡。 关卡切换 首先&#xff0c;文件新建一个新关卡&#xff0c;命名。找到之前制…

地址解析协议-ARP

ARP协议 无论网络层使用何种协议&#xff0c;在实际网络的链路上传输数据帧时&#xff0c;最终必须使用硬件地址 地址解析协议&#xff08;Address Resolution Protocol&#xff0c;ARP&#xff09;&#xff1a;完成IP地址到MAC地址的映射&#xff0c;每个主机都有一个ARP高速缓…

C语言刷题训练DAY.4

1.计算体重指数 解题思路&#xff1a; 这里我们只需要按照他的要求写出公式。 注意&#xff1a;身高要换算成米&#xff0c;打印的结构是个浮点数&#xff0c;打印的格式要相对应 解题代码&#xff1a; #include<stdio.h> int main() {int weight 0;int height 0;…

Python自动化小技巧18——自动化资产月报(word设置字体表格样式,查找替换文字)

案例背景 每月都要写各种月报&#xff0c;经营管理月报&#xff0c;资产月报.....这些报告文字目标都是高度相似的&#xff0c;只是需要替换为每个月的实际数据就行&#xff0c;如下&#xff1a; (打码是怕信息泄露.....) 可以看到&#xff0c;这个报告的都是高度模板化&…

浏览器 - 事件循环机制详解

目录 1&#xff0c;浏览器进程模型进程线程浏览器的进程和线程1&#xff0c;浏览器进程2&#xff0c;网络进程3&#xff0c;渲染进程 2&#xff0c;渲染主线程事件循环异步同步 JS 为什么会阻塞渲染任务优先级 3&#xff0c;常见面试题1&#xff0c;如何理解 js 的异步2&#x…