基于SPI协议接口的OLED数据显示

基于SPI协议接口的OLED数据显示



任务摘要

理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能:

  1. 显示自己的学号和姓名;
  2. 显示AHT20的温度和湿度;
  3. 上下或左右的滑动显示长字符,比如“陪伴是最长情的告白!”。


一、SPI协议简介

SPI接口是在CPU和外围低速器件之间进行同步串行数据传输,在主器件的移位脉冲下,数据按位传输,高位在前,地位在后,为全双工通信,数据传输速度总体来说比I2C总线要快,速度可达到几Mbps。
SPI接口是以主从方式工作的,这种模式通常有一个主器件和一个或多个从器件,其接口包括以下四种信号:

  1. MOSI+–+主器件数据输出,从器件数据输入
  2. MISO+–+主器件数据输入,从器件数据输出
  3. SCLK+–+时钟信号,由主器件产生
  4. /SS+–+从器件使能信号,由主器件控制
    在点对点的通信中,SPI接口不需要进行寻址操作,且为全双工通信,显得简单高效。
    在这里插入图片描述
    在多个从器件的系统中,每个从器件需要独立的使能信号,硬件上比I2C系统要稍微复杂一些。
    SPI接口在内部硬件实际上是两个简单的移位寄存器,传输的数据为8位,在主器件产生的从器件使能信号和移位脉冲下,按位传输,高位在前,低位在后。如下图所示,在SCLK的下降沿上数。
    据改变,同时一位数据被存入移位寄存器。
    在这里插入图片描述
    SPI接口内部硬件图示
    SPI接口的一个缺点:没有指定的流控制,没有应答机制确认是否接收到数据。
    在这里插入图片描述

二、接口与程序

1.接口定义

模块引脚丝印图
在这里插入图片描述
模块背面图
在这里插入图片描述
1、本模块支持IIC、3线制SPI以及4线制SPI接口总线模式切换(如图2红框内所示),具体说明如下:
A、使用4.7K电阻只焊接R3、R4,则选择4线制SPI总线接口(默认);
B、使用4.7K电阻只焊接R2、R3,则选择3线制SPI总线接口;
C、使用4.7K电阻只焊接R1、R4、R6、R7、R8,则选择IIC总线接口;
2、接口总线模式切换后,需要选择相应配套的软件和相应的接线引脚(如图1所示),模块才能正常运行。相应的接线引脚说明如下:
A、选择4线制SPI总线接口,所有的引脚都需要使用;
B、选择3线制SPI总线接口,只有DC引脚不需要使用(可以不接),其他引脚都需要使用;
C、选择IIC总线接口,只需要使用GND、VCC、D0、D1这四个引脚,同时将RES接高电平(可以接VCC),DC和CS接电源地;
在这里插入图片描述

2.SPI接线

按照程序接线
在这里插入图片描述
接线图示
在这里插入图片描述
在这里插入图片描述

3.程序

从官网下载0.96inch SPI OLED Module程序
0.96inch SPI OLED Module.
在这里插入图片描述
下载完成后解压到当前文件夹
在这里插入图片描述
点击解压后的文件夹,选择demo
在这里插入图片描述
选择demoSTM32
在这里插入图片描述
选择0.96inch_OLED_Demo_STM32F103ZET6_Hardware_4-wire_SPI
在这里插入图片描述
打开project,选择OLED_uvprojx
在这里插入图片描述
打开后界面显示
在这里插入图片描述

4.程序烧录

点击魔法棒
在这里插入图片描述
点击debug
在这里插入图片描述
在右上use处,选择ST_link,点击setting
在这里插入图片描述
在port处,选择SW
在这里插入图片描述
点击flash download,点击reset and run,再点击add
在这里插入图片描述
点击add。选择第一个
在这里插入图片描述
最后添加、确定即可。
源程序烧录结果显示
在这里插入图片描述

三、OLED显示姓名学号

选择test.c进行修改,将void TEST_MainPage(void)函数修改

void TEST_MainPage(void)
{
    
    	
	GUI_ShowString(20,0,"631807060134",8,1);
	GUI_ShowCHinese(16,20,16,"周雄伟",1);
	delay_ms(1500);
}

修改完成,再进入main.c文件进行修改

#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "gui.h"
#include "test.h"
int main(void)
	{
    
    	
	delay_init();	    	         
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	
	
	OLED_Init();			         
	OLED_Clear(0);             
	while(1) 
	{
    
    	
		TEST_MainPage();         
		OLED_Clear(0); 
		
	}
}

利用PCtoLCD加入所需要显示的汉字模型
找到野火资料盘,打开开发软件
在这里插入图片描述
选择字模软件zip,解压到当前目录
在这里插入图片描述
打开。然后解压
在这里插入图片描述
在打开该文件夹,找到.exe,
在这里插入图片描述
双击,界面显示
在这里插入图片描述
在下面输入名字,生成字模
在这里插入图片描述
此处可以对字体进行旋转
在这里插入图片描述
点击生成字模
在这里插入图片描述
在oledfont.h头文件里添加个人需要显示的汉字字模

const typFNT_GB16 cfont16[] = 
{
    
    
	"周",0x00,0x01,0x00,0x06,0x7F,0xF8,0x41,0x00,0x49,0x00,0x49,0x78,0x49,0x48,0x7F,0x48,0x49,0x48,0x49,0x78,0x49,0x02,0x41,0x01,
       0x7F,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,/*"周",0*/
	"雄",0x00,0x20,0x10,0xC4,0x13,0x0E,0x1C,0x34,0xF1,0xC4,0x10,0x14,0x14,0x0E,0x08,0x00,0x3F,0xFF,0xD2,0x44,0x12,0x44,0x9F,0xFC,
       0x52,0x44,0x12,0x44,0x10,0x04,0x00,0x00,/*"雄",1*/
	"伟",0x00,0x80,0x01,0x00,0x06,0x00,0x1F,0xFF,0xE0,0x00,0x10,0x40,0x12,0x40,0x12,0x40,0x12,0x40,0xFF,0xFF,0x12,0x40,0x12,0x40,
       0x12,0x48,0x12,0x44,0x10,0x78,0x00,0x00,/*"伟",0*/
	
};

程序修改完成。烧录结果显示
在这里插入图片描述

四、显示温度-湿度

添加的内容
在这里插入图片描述
下载链接
stm32_AHT20_OLED.
显示温湿度的代码

void read_AHT20(void)
{
    
    
	uint8_t   i;
	for(i=0; i<6; i++)
	{
    
    
		readByte[i]=0;
	}

	//-------------
	I2C_Start();

	I2C_WriteByte(0x71);
	ack_status = Receive_ACK();
	readByte[0]= I2C_ReadByte();
	Send_ACK();

	readByte[1]= I2C_ReadByte();
	Send_ACK();

	readByte[2]= I2C_ReadByte();
	Send_ACK();

	readByte[3]= I2C_ReadByte();
	Send_ACK();

	readByte[4]= I2C_ReadByte();
	Send_ACK();

	readByte[5]= I2C_ReadByte();
	SendNot_Ack();
	//Send_ACK();

	I2C_Stop();

	//--------------
	if( (readByte[0] & 0x68) == 0x08 )
	{
    
    
		H1 = readByte[1];
		H1 = (H1<<8) | readByte[2];
		H1 = (H1<<8) | readByte[3];
		H1 = H1>>4;

		H1 = (H1*1000)/1024/1024;

		T1 = readByte[3];
		T1 = T1 & 0x0000000F;
		T1 = (T1<<8) | readByte[4];
		T1 = (T1<<8) | readByte[5];

		T1 = (T1*2000)/1024/1024 - 500;

		AHT20_OutData[0] = (H1>>8) & 0x000000FF;
		AHT20_OutData[1] = H1 & 0x000000FF;

		AHT20_OutData[2] = (T1>>8) & 0x000000FF;
		AHT20_OutData[3] = T1 & 0x000000FF;
	}
	else
	{
    
    
		AHT20_OutData[0] = 0xFF;
		AHT20_OutData[1] = 0xFF;

		AHT20_OutData[2] = 0xFF;
		AHT20_OutData[3] = 0xFF;
		printf("lyy");

	}
	/*通过串口显示采集得到的温湿度
	printf("\r\n");
	printf("温度:%d%d.%d",T1/100,(T1/10)%10,T1%10);
	printf("湿度:%d%d.%d",H1/100,(H1/10)%10,H1%10);
	printf("\r\n");*/
	t=T1/10;
	t1=T1%10;
	a=(float)(t+t1*0.1);
	h=H1/10;
	h1=H1%10;
	b=(float)(h+h1*0.1);
	sprintf(strTemp,"%.1f",a);   //调用Sprintf函数把DHT11的温度数据格式化到字符串数组变量strTemp中  
    sprintf(strHumi,"%.1f",b);    //调用Sprintf函数把DHT11的湿度数据格式化到字符串数组变量strHumi中  
	GUI_ShowCHinese(16,00,16,"温湿度显示",1);
	GUI_ShowCHinese(16,20,16,"温度",1);
	GUI_ShowString(53,20,strTemp,16,1);
	GUI_ShowCHinese(16,38,16,"湿度",1);
	GUI_ShowString(53,38,strHumi,16,1);
	delay_ms(1500);		
	delay_ms(1500);
}

添加相应的点阵字

	"温",0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,
  0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00,/*"温",0*/
	"湿",0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,
  0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E,/*"湿",0*/
	"度",0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8,
  0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00,/*"度",0*/
	"显",0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10,0x10,0x10,0x1F,0xF0,
  0x04,0x40,0x44,0x44,0x24,0x44,0x14,0x48,0x14,0x50,0x04,0x40,0xFF,0xFE,0x00,0x00,/*"显",0*/
	"示",0x00,0x00,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFE,0x01,0x00,
  0x01,0x00,0x11,0x10,0x11,0x08,0x21,0x04,0x41,0x02,0x81,0x02,0x05,0x00,0x02,0x00,/*"示",0*/

mian函数

#include "delay.h"
#include "usart.h"
#include "bsp_i2c.h"
#include "sys.h"
#include "oled.h"
#include "gui.h"
#include "test.h"
int main(void)
{
    
    	
	delay_init();	    	       //延时函数初始化    	  
	uart_init(115200);	 
	IIC_Init();
	OLED_Init();			         //初始化OLED  
	OLED_Clear(0); 
	while(1)
	{
    
    
		//printf("温度湿度显示");
		read_AHT20_once();
		OLED_Clear(0); 
		delay_ms(1500);
  }
}

烧录结果显示
在这里插入图片描述

五、OLED的滑屏显示

水平左右移

OLED_WR_Byte(0x2E,OLED_CMD);        //关闭滚动
OLED_WR_Byte(0x26,OLED_CMD);        //水平向左或者右滚动 26/27
OLED_WR_Byte(0x00,OLED_CMD);        //虚拟字节
OLED_WR_Byte(0x00,OLED_CMD);        //起始页 0
OLED_WR_Byte(0x07,OLED_CMD);        //滚动时间间隔
OLED_WR_Byte(0x07,OLED_CMD);        //终止页 7
OLED_WR_Byte(0x00,OLED_CMD);        //虚拟字节
OLED_WR_Byte(0xFF,OLED_CMD);        //虚拟字节
OLED_WR_Byte(0x2F,OLED_CMD);        //开启滚动

垂直和水平滚动

OLED_WR_Byte(0x2e,OLED_CMD);        //关闭滚动
OLED_WR_Byte(0x29,OLED_CMD);        //水平垂直和水平滚动左右 29/2a
OLED_WR_Byte(0x00,OLED_CMD);        //虚拟字节
OLED_WR_Byte(0x00,OLED_CMD);        //起始页 0
OLED_WR_Byte(0x07,OLED_CMD);        //滚动时间间隔
OLED_WR_Byte(0x07,OLED_CMD);        //终止页 1
OLED_WR_Byte(0x01,OLED_CMD);        //垂直滚动偏移量
OLED_WR_Byte(0x2F,OLED_CMD);        //开启滚动

文字字模
在这里插入图片描述
添加文字点阵

{
    
    
	"陪",0x00,0x00,0x7F,0xFF,0x40,0x10,0x44,0x08,0x5B,0x10,0x60,0xE0,0x01,0x00,0x29,0x3F,0x25,0x22,0xA1,0x22,0x61,0x22,0x25,0x22,
0x29,0x22,0x21,0x3F,0x01,0x00,0x00,0x00,/*"陪",0*/
	"伴",0x00,0x80,0x01,0x00,0x06,0x00,0x1F,0xFF,0xE0,0x40,0x04,0x40,0x44,0x40,0x34,0x40,0x04,0x40,0xFF,0xFF,0x04,0x40,0x14,0x40,
0x24,0x40,0x44,0x40,0x00,0x40,0x00,0x00,/*"伴",0*/
	"是",0x00,0x81,0x00,0x82,0x00,0x84,0xFE,0xB8,0x92,0x84,0x92,0x82,0x92,0x81,0x92,0xFF,0x92,0x91,0x92,0x91,0x92,0x91,0xFE,0x91,
0x00,0x91,0x00,0x81,0x00,0x81,0x00,0x00,/*"是",0*/
	"最",0x02,0x04,0x02,0x06,0x03,0xFC,0xFA,0xA4,0xAA,0xA8,0xAA,0xA8,0xAB,0xFF,0xAA,0x09,0xAA,0xE2,0xAA,0x94,0xAA,0x88,0xFA,0xB4,
0x02,0xC2,0x02,0x01,0x02,0x01,0x00,0x00,/*"最",3*/
  "长",0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xFF,0xFF,0x01,0x02,0x01,0x84,0x05,0x48,0x09,0x20,0x11,0x10,0x21,0x08,0x41,0x04,
0x01,0x04,0x01,0x02,0x01,0x02,0x00,0x00,/*"长",4*/
  "情",0x00,0x80,0x07,0x00,0x00,0x00,0xFF,0xFF,0x08,0x00,0x26,0x00,0x2A,0xFF,0x2A,0xA8,0x2A,0xA8,0xFE,0xA8,0x2A,0xAA,0x2A,0xA9,
0x2A,0xFE,0x22,0x00,0x02,0x00,0x00,0x00,/*"情",5*/
  "的",0x00,0x00,0x1F,0xFE,0x30,0x84,0xD0,0x84,0x10,0x84,0x10,0x84,0x1F,0xFE,0x02,0x00,0x0C,0x00,0xF1,0x00,0x10,0xC2,0x10,0x01,
0x10,0x02,0x1F,0xFC,0x00,0x00,0x00,0x00,/*"的",6*/
  "告",0x01,0x00,0x05,0x00,0x09,0x00,0x71,0x3F,0x11,0x22,0x11,0x22,0x11,0x22,0xFF,0x22,0x11,0x22,0x11,0x22,0x11,0x22,0x11,0x3F,
0x11,0x00,0x01,0x00,0x01,0x00,0x00,0x00,/*"告",7*/
  "白",0x00,0x00,0x00,0x00,0x1F,0xFF,0x10,0x82,0x10,0x82,0x30,0x82,0x50,0x82,0x90,0x82,0x10,0x82,0x10,0x82,0x10,0x82,0x10,0x82,
0x1F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,/*"白",8*/
};

主要代码

#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "gui.h"
#include "test.h"
int main(void)
{
    
    	
	delay_init();	    	       //延时函数初始化	  
	OLED_Init();			         //初始化OLED  
	OLED_Clear(0);             //清屏(全黑)
	OLED_WR_Byte(0x2E,OLED_CMD);        //关闭滚动
    OLED_WR_Byte(0x27,OLED_CMD);        //水平向左或者右滚动 26/27
    OLED_WR_Byte(0x00,OLED_CMD);        //虚拟字节
	OLED_WR_Byte(0x00,OLED_CMD);        //起始页 0
	OLED_WR_Byte(0x07,OLED_CMD);        //滚动时间间隔
	OLED_WR_Byte(0x07,OLED_CMD);        //终止页 7
	OLED_WR_Byte(0x00,OLED_CMD);        //虚拟字节
	OLED_WR_Byte(0xFF,OLED_CMD);        //虚拟字节
	TEST_MainPage();
	OLED_WR_Byte(0x2F,OLED_CMD);        //开启滚动
}

显示数据函数

void TEST_MainPage(void)
{
    
    	
	GUI_ShowCHinese(10,20,16,"陪伴是最长情的告白",1);
	delay_ms(1500);		
	delay_ms(1500);
}

烧录结果显示(字体有点歪,这里没有纠正,可以通过旋转纠正)
在这里插入图片描述
附上发送到QQ空间的视频
视频展示.


六、总结

本次作业完成,对SPI协议有了初步认识,运用SPI协议完成OLED接口的数据显示。通篇比较麻烦的是汉字点阵,生成字模容易,就是程序烧录后,显示的字体倾斜不一,需要我们多次旋转字体,慢慢去修正。

七、参考资料

SPI及SPI接口内容.
SPI接口详细讲解.
SSD1306(OLED驱动芯片)指令详解
.

猜你喜欢

转载自blog.csdn.net/QWERTYzxw/article/details/111820317