【STM32CubeIDE】软件&硬件SPI+六针OLED使用

前言

本文将介绍STM32 + 6针OLED的使用,分别使用软件和硬件两种SPI驱动方式,最终实现OLED显示TEST-ok字符和数字累加刷新显示

软件平台:STM32CubeIDE+HAL库

硬件:STM32F103ZET6(正点原子战舰V3)+六针OLED

题外话:

最近在学习STM32CubeIDE+HAL库,想做几个小模块练练手,结果遇到各种奇怪的异常,反复排查自己代码都不觉得问题,最后发现接触不良的原因,害。所以大家在写软件之前一定要确保自己硬件是ok的,遇到问题不要光埋头在软件里找原因,血泪的教训T.T

六针OLED简介

OLED工作机制和原理网上有很多资料,这里不过多赘述了

市面上常见的OLED0.96寸显示屏有4针、6针,7针三种。其中,7针屏幕CS端接地就是6针屏幕。

4针通常是使用IIC驱动,VCC、GND、SCL、SDA四脚即可;而6针、7针通常是用于SPI驱动(有些通过修改硬件也可以换成IIC驱动)

以下是6针/7针OLED引脚定义

引脚 定义
GND 接地端口
VCC 电源端口,接3.3V电源端口
D0 CLK时钟信号端口(SCL)
D1 数据端口(SDA)
RES 复位端口(RST)
D/C 数据/命令选择引脚
CS 片选引脚(低电平有效,悬空也可使用),6针默认已经接地,没有引出

软件SPI配置

1.创建新工程

image-20240522221917502

在此处搜索对应的芯片型号

image-20240505221008688

在右边选择要使用的芯片型号,按next下一步

常用的芯片型号可以加星,下次可以在搜索上边的星星里直接找到

image-20240505221119292

设置新建项目的名称,直接按Finish即可新建项目

next里边有一些设置,根据需要去更改,一般保持默认即可
image-20240505221322266

2.设置引脚

确定除电源和GND外,SPI协议要用的4个引脚,SCL、SDA、RES、DC,这里使用PC0/PC1/PC2/PC3

将4个引脚的GPIO mode都设置成Output Push Pull(推挽输出)

并设置对应的User Label(主要是为了生成宏兼容驱动,不改后边代码里自己定义宏也行)

image-20240522222358501

#define OLED_RS_Pin GPIO_PIN_0
#define OLED_RS_GPIO_Port GPIOC
#define OLED_SCLK_Pin GPIO_PIN_1
#define OLED_SCLK_GPIO_Port GPIOC
#define OLED_SDIN_Pin GPIO_PIN_2
#define OLED_SDIN_GPIO_Port GPIOC
#define OLED_RST_Pin GPIO_PIN_3
#define OLED_RST_GPIO_Port GPIOC

3.添加驱动文件

驱动文件一般厂家都会提供,网上购买的可以联系客服要。以下驱动文件可用于0.96寸6针OLED

在对应文件夹下添加oled.h、oled.c和oledfont.h文件,可以新建文件然后复制进来。用其他方法添加到工程也行,这里不过多赘述。
image-20240522223333027

oled.h

#ifndef OLED_H_
#define OLED_H_

#include "main.h"


#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
//-----------------OLED端口定义----------------
#define OLED_RST_Clr() HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_RESET)   //RST
#define OLED_RST_Set() HAL_GPIO_WritePin(OLED_RST_GPIO_Port, OLED_RST_Pin, GPIO_PIN_SET)   //RST

#define OLED_RS_Clr() HAL_GPIO_WritePin(OLED_RS_GPIO_Port, OLED_RS_Pin, GPIO_PIN_RESET)    //DC
#define OLED_RS_Set() HAL_GPIO_WritePin(OLED_RS_GPIO_Port, OLED_RS_Pin, GPIO_PIN_SET)    //DC

#define OLED_SCLK_Clr()  HAL_GPIO_WritePin(OLED_SCLK_GPIO_Port, OLED_SCLK_Pin, GPIO_PIN_RESET)  //SCL
#define OLED_SCLK_Set()  HAL_GPIO_WritePin(OLED_SCLK_GPIO_Port, OLED_SCLK_Pin, GPIO_PIN_SET)  //SCL

#define OLED_SDIN_Clr()  HAL_GPIO_WritePin(OLED_SDIN_GPIO_Port, OLED_SDIN_Pin, GPIO_PIN_RESET)   //SDA
#define OLED_SDIN_Set()  HAL_GPIO_WritePin(OLED_SDIN_GPIO_Port, OLED_SDIN_Pin, GPIO_PIN_SET)   //SDA

#define OLED_CMD  0	//写命令
#define OLED_DATA 1	//写数据
//OLED控制用函数
void OLED_WR_Byte(u8 dat,u8 cmd);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Refresh_Gram(void);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);
void OLED_ShowNumber(u8 x,u8 y,u32 num,u8 len,u8 size);
void OLED_ShowString(u8 x,u8 y,const u8 *p);
void OLED_ShowFloatNum(u8 x,u8 y,float num,u8 size1);
void OLED_ShowFloat(float value, uint8_t decimalPlaces, uint8_t x, uint8_t y);
void OLED_ShowFNum(u8 x,u8 y,float num,u8 len,u8 size,u8 mode);

#endif /* OLED_H_ */

oled.c

#include <oled.h>
#include "stdlib.h"
#include "oledfont.h"

u8 OLED_GRAM[128][8];

void OLED_Refresh_Gram(void)
{
   
	u8 i,n;
	for(i=0;i<8;i++)
	{
   
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
		for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
	}
}

//向OLED写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
   
	u8 i;
	if(cmd)
	  OLED_RS_Set();
	else
	  OLED_RS_Clr();
	for(i=0;i<8;i++)
	{
   
		OLED_SCLK_Clr();
		if(dat&0x80)
		   OLED_SDIN_Set();
		else
		   OLED_SDIN_Clr();
		OLED_SCLK_Set();
		dat<<=1;
	}
	OLED_RS_Set();
}


//开启OLED显示
void OLED_Display_On(void)
{
   
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
   
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
   
	u8 i,n;
	for(i=0;i<8;i++)for(n=0;n<128;n++)OLED_GRAM[n][i]=0X00;
	OLED_Refresh_Gram();//更新显示
}
//画点
//x:0~127
//y:0~63
//t:1 填充 0,清空
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
   
	u8 pos,bx,temp=0;
	if(x>127||y>63)return;//超出范围了.
	pos=7-y/8;
	bx=y%8;
	temp=1<<(7-bx);
	if(t)OLED_GRAM[x][pos]|=temp;
	else OLED_GRAM[x][pos]&=~temp;
}

//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
{
   
	u8 temp,t,t1;
	u8 y0=y;
	chr=chr-' ';//得到偏移后的值
    for(t=0;t<size;t++)
    {
   
		if(size==12)temp=oled_asc2_1206[chr][t];  //调用1206字体
		else temp=oled_asc2_1608[chr][t];		 //调用1608字体
        for(t1=0;t1<8;t1++)
		{
   
			if(temp&0x80)OLED_DrawPoint(x,y,mode);
			else OLED_DrawPoint(x,y,!mode);
			temp<<=1;
			y++;
			if((y-y0)==size)
			{
   
				y=y0;
				x++;
				break;
			}
		}
    }
}

//m^n函数
u32 oled_pow(u8 m,u8 n)
{
   
	u32 result=1;
	while(n--)result*=m;
	return result;
}

//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNumber(u8 x,u8 y,u32 num,u8 len,u8 size)
{
   
	u8 t,temp;
	u8 enshow=0;
	for(t=0;t<len;t++)
	{
   
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
   
			if(temp==0)
			{
   
				OLED_ShowChar(x+(size/2)*t,y,' ',size,1);
				continue;
			}else enshow=1;

		}
	 	OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1);
	}
}

//显示字符串
//x,y:起点坐标
//*p:字符串起始地址
//用16字体
void OLED_ShowString(u8 x,u8 y,const u8 *p)
{
   
#define MAX_CHAR_POSX 122
#define MAX_CHAR_POSY 58
    while(*p!='\0')
    {
   
        if(x>MAX_CHAR_POSX){
   x=0;y+=16;}
        if(y>MAX_CHAR_POSY){
   y=x=0;OLED_Clear();}
        OLED_ShowChar(x,y,*p,12,1);
        x+=8;
        p++;
    }
}

//显示浮点数字
//x,y :起点坐标
//value :要显示的值
//decimalPlaces,小数点后位数,
// 显示浮点数函数
void OLED_ShowFloat(float value, uint8_t decimalPlaces, uint8_t x, uint8_t y)
{
   
    char buffer[16];

    // 将浮点数转换为字符串格式,并指定小数位数
    snprintf(buffer, sizeof(buffer), "%.*f", decimalPlaces, value);

    // 在指定位置显示字符串
    for (uint8_t i = 0; i < strlen(buffer); i++)
    {
   
        OLED_ShowChar(x + i * 8, y, buffer[i], 16, 1);
    }
}

//初始化OLED
void OLED_Init(void)
{
   
	OLED_RST_Clr();
	HAL_Delay(100);
	OLED_RST_Set();

	OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
	OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
	OLED_WR_Byte(80,OLED_CMD);   //[3:0],分频因子;[7:4],震荡频率
	OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
	OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64)
	OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
	OLED_WR_Byte(0X00,OLED_CMD); //默认为0

	OLED_WR_Byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.

	OLED_WR_Byte(0x8D,OLED_CMD); //电荷泵设置
	OLED_WR_Byte(0x14,OLED_CMD); //bit2,开启/关闭
	OLED_WR_Byte(0x20,OLED_CMD); //设置内存地址模式
	OLED_WR_Byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
	OLED_WR_Byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
	OLED_WR_Byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
	OLED_WR_Byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
	OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置

	OLED_WR_Byte(0x81,OLED_CMD); //对比度设置
	OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
	OLED_WR_Byte(0xD9,OLED_CMD); //设置预充电周期
	OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
	OLED_WR_Byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
	OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

	OLED_WR_Byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
	OLED_WR_Byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示
	OLED_WR_Byte(0xAF,OLED_CMD); //开启显示
	OLED_Clear();
}
/*
 * OLED.c
 *
 *  Created on: May 22, 2024
 *      Author: 30985
 */

oledfont.h

#ifndef OLEDFONT_H_
#define OLEDFONT_H_

//常用ASCII表
//偏移量32
//ASCII字符集
//偏移量32
//大小:12*6
const unsigned char oled_asc2_1206[95][12]={
   
{
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
{
   0x00,0x00,0x00,0x00,0x3F,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/
{
   0x00,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x40,0x00,0x00,0x00},/*""",2*/
{
   0x09,
### 关于 Arduino Mega 2560 和 OLED 显示屏的相关教程及驱动下载 Arduino Mega 2560 是一款功能强大的开发板,基于 ATmega2560 微控制器构建而成[^1]。此款开发板提供了丰富的 I/O 资源,包括多达 54 个数字输入/输出引脚(其中 15 个支持 PWM 输出)、16 个模拟输入通道、4 组 UART 接口以及其他通信接口。 对于 OLED 显示屏而言,通常指的是带有 SPI 或者 IIC/I&sup2;C 接口的小型显示器模块。这类显示屏由于其紧凑的设计和低功耗特性,在嵌入式项目中广泛应用。特别是 SSD1306 驱动芯片的 OLED 屏幕因其良好的兼容性和易于编程而受到青睐[^3]。 #### 获取适用于 Arduino Mega 2560 的 OLED 显示屏教程与库文件: 为了使 Arduino Mega 2560 成功连接并控制 OLED 显示屏,建议按照如下方法操作: - **安装 Adafruit GFX 库**:这是用于图形绘制的基础库; - **安装 Adafruit SSD1306 库**:专门对 SSD1306 控制器优化过的库; 可以通过 Arduino IDE 自带的库管理工具来完成上述两个库的安装过程。打开 Arduino IDE 后依次点击 `Sketch` -&gt; `Include Library` -&gt; `Manage Libraries...` ,然后在弹出窗口内搜索对应的库名进行安装即可。 此外,网络上有许多现成的例子可以帮助理解如何配置这两者的交互工作模式。例如 Adafruit 提供了一个详细的指南页面介绍了从硬件连线到编写代码的具体步骤。 ```cpp #include &lt;Wire.h&gt; #include &lt;Adafruit_GFX.h&gt; #include &lt;Adafruit_SSD1306.h&gt; #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &amp;Wire, OLED_RESET); void setup() { if(!display.begin(SSD1306_I2C_ADDRESS, OLED_RESET)) { Serial.println(F(&quot;SSD1306 allocation failed&quot;)); for(;;); } delay(2000); // Pause for 2 seconds // Clear the buffer. display.clearDisplay(); } void loop() { display.setTextSize(1); display.setTextColor(SSD1306_WHITE); display.setCursor(0,0); display.print(&quot;Hello, world!&quot;); display.display(); } ``` 这段简单的 C++ 程序展示了怎样初始化一个通过 I2C 总线连接至 Arduino Mega 2560 的 128x64 像素分辨率的 OLED 显示屏,并向屏幕上打印字符串 &quot;Hello, world!&quot;。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值