一、内容
理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能:
1.显示自己的学号和姓名;
2.显示AHT20的温度和湿度;
3.上下或左右的滑动显示长字符,比如“Hello,欢迎来到重庆!”或者一段歌词或诗词(最好使用硬件刷屏模式)。
关于汉字点阵编码的原理可以参考上一篇博客!
二、关于SPI
SPI,是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola首先在其MC68HCXX系列处理器上定义的。 SPI接口主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。 SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,现在越来越多的芯片集成了这种通信协议,比如AT91RM9200。
AT91RM9200的SPI接口主要由4个引脚构成:SPICLK、MOSI、MISO及 /SS,其中SPICLK是整个SPI总线的公用时钟,MOSI、MISO作为主机,从机的输入输出的标志,MOSI是主机的输出,从机的输入,MISO 是主机的输入,从机的输出。/SS是从机的标志管脚,在互相通信的两个SPI总线的器件,/SS管脚的电平低的是从机,相反/SS管脚的电平高的是主机。在一个SPI通信系统中,必须有主机。SPI总线可以配置成单主单从,单主多从,互为主从。
SPI的片选可以扩充选择16个外设,这时PCS输出=NPCS,说NPCS0~3 接4-16译码器,这个译码器是需要外接4-16译码器,译码器的输入为NPCS0~3,输出用于16个外设的选择。
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)。
- SDO – 主设备数据输出,从设备数据输入对应MOSI master output slave input
- SDI – 主设备数据输入,从设备数据输出对应MISO master input slave output
- SCLK – 时钟信号,由主设备产生
- CS – 从设备使能信号,由主设备控制
注意 :SCK信号线只由主设备控制,从设备不能控制信号线。同样,在一个基于SPI的设备中,至少有一个主控设备。 这样传输的优点:
- 与普通的串行通讯不同,普通的串行通讯一次连续传送至少8位数据,而SPI允许数据一位一位的传送,甚至允许暂停,因为SCK时钟线由主控设备控制,当没有时钟跳变时,从设备不采集或传送数据,也就是说,主设备通过对SCK时钟线的控制可以完成对通讯的控制。
- SPI还是一个数据交换协议:因为SPI的数据输入和输出线独立,所以允许同时完成数据的输入和输出。不同的SPI设备的实现方式不尽相同,主要是数据改变和采集的时间不同,在时钟信号上沿或下沿采集有不同定义,具体请参考相关器件的文档。
- 在点对点的通信中,SPI接口不需要进行寻址操作,且为全双工通信,显得简单高效。在多个从设备的系统中,每个从设备需要独立的使能信号,硬件上比I2C系统要稍微复杂一些。
缺点: 没有指定的流控制,没有应答机制确认是否接收到数据。
三、关于OLED
通常我们所用的OLED屏有白色、蓝色、黄蓝双色等几种;屏的大小为0.96寸,像素点为128*64,所以我们也称之为0.96OLED屏或者12864屏。
内部驱动IC为SSD1306;通信方式一般为SPI或者I2C。
配置哪种模式主要是根据BS0、BS1和BS2这三个管脚的电平逻辑来的。 关于OLED的显存分布情况 我们可以理解为:水平方向分布了128个像素点,垂直方向分布了64个像素点(如图一所示)。而驱动芯片在点亮像素点的时候,是以8个像素点为单位的。官方的例程推荐的是垂直扫描的方式,也就是先画垂直方向的8个像素点(如下图二所示),所以我们在画点的时候Y的取值为0-7,X的取值为0-127,具体请看参考内容。
四、功能实现
1)实验准备
软件 :Keil uVision5、烧录软件、串口调试助手 硬件 :PC机、STM32芯片、OLED显示屏、若干杜邦线、USB TO TTL串口
2)代码准备
1、显示学号和姓名
Ⅰ、字模提取 首先,先进行字模提取,在提取之前,需要进行一些选项设置,具体如下图: 然后在下方输入框中输入想要显示的内容,点击生成字模即可看到对用的字模编码,然后点击保存字模即可: Ⅱ、代码完善
①下载路径:打开该博客,博主分享有完整代码; ②下载上述文件后,打开资料包,打开keil工程,如下图所示: 首先,将刚刚生成的字模编码添加到如下文件当中去,如下图所示: 然后打开test.c将以下函数的一部分修改为我们需要显示的内容: 函数说明
GUI_ShowString() 的参数
参数一:X 坐标参数二:Y 坐标参数三:字符串(ASCLL码中的)参数四:bit(表示字符显示格式,这里我用的 16,和汉字一样高)参数五:显示样式(1:白字黑底;0:黑字白底) GUI_ShowChinese() 的参数
参数一:X 坐标参数二:Y 坐标参数三:汉字点阵大小(这里使用的是 16×16 的,参数应该是16)参数四:要显示的汉字参数五:显示样式(1:白字黑底;0:黑字白底)
Ⅲ、主要代码展示
主函数mian.c :
int main(void)
{
delay_init(); //延时函数初始化
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
OLED_Init(); //初始化OLED
OLED_Clear(0); //清屏(全黑)
while(1)
{
TEST_MainPage(); //主界面显示测试
}
}
OLED 相关函数:
//OLED控制用函数
void OLED_WR_Byte(unsigned dat,unsigned cmd);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_Reset(void);
void OLED_Init_GPIO(void);
void OLED_Init(void);
void OLED_Set_Pixel(unsigned char x, unsigned char y,unsigned char color);
void OLED_Display(void);
void OLED_Clear(unsigned dat);
#endif
2、显示AHT20的温度和湿度
Ⅰ、工程路径 打开博客,文章底部有博主分享的完整代码;将文件下载下来,并打开其中的Keil工程,如下图所示: Ⅱ、主要代码 温湿度采集函数代码: 主函数main.c :
#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();
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
OLED_Init(); //初始化OLED
OLED_Clear(0);
while(1)
{
//printf("温度湿度显示");
read_AHT20_once();
OLED_Clear(0);
delay_ms(1500);
}
}
3、滑动显示长字符
Ⅰ、字模提取 这里我显示的是热爱可抵岁月漫长 ,在字模编码生成器当中如第一部分所示生成对应的字模编码并添加:
"热",0x10,0x40,0x10,0x40,0x10,0x40,0xFD,0xF8,0x10,0x48,0x10,0x48,0x1C,0xC8,0x30,0x48,
0xD0,0xAA,0x10,0xAA,0x51,0x06,0x22,0x02,0x00,0x00,0x48,0x88,0x44,0x44,0x84,0x44,
"爱",0x00,0x08,0x01,0xFC,0x7E,0x10,0x22,0x10,0x11,0x20,0x7F,0xFE,0x42,0x02,0x82,0x04,
0x7F,0xF8,0x04,0x00,0x07,0xF0,0x0A,0x10,0x11,0x20,0x20,0xC0,0x43,0x30,0x1C,0x0E,
"可",0x00,0x00,0x7F,0xFE,0x00,0x10,0x00,0x10,0x1F,0x10,0x11,0x10,0x11,0x10,0x11,0x10,
0x11,0x10,0x11,0x10,0x1F,0x10,0x11,0x10,0x00,0x10,0x00,0x10,0x00,0x50,0x00,0x20,
"抵",0x10,0x08,0x10,0x3C,0x13,0xE0,0x12,0x20,0xFE,0x20,0x12,0x20,0x12,0x20,0x13,0xFE,
0x1A,0x20,0x32,0x10,0xD2,0x10,0x12,0x12,0x12,0x0A,0x12,0x8A,0x53,0x26,0x22,0x12,
"岁",0x01,0x00,0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,0x02,0x00,0x02,0x00,0x07,0xF0,
0x08,0x10,0x14,0x10,0x22,0x20,0x01,0x40,0x00,0x80,0x03,0x00,0x1C,0x00,0xE0,0x00,
"月",0x00,0x00,0x1F,0xF8,0x10,0x08,0x10,0x08,0x10,0x08,0x1F,0xF8,0x10,0x08,0x10,0x08,
0x10,0x08,0x1F,0xF8,0x10,0x08,0x10,0x08,0x20,0x08,0x20,0x08,0x40,0x28,0x80,0x10,
"漫",0x03,0xF8,0x22,0x08,0x13,0xF8,0x12,0x08,0x83,0xF8,0x40,0x00,0x47,0xFC,0x14,0xA4,
0x14,0xA4,0x27,0xFC,0xE0,0x00,0x23,0xF8,0x21,0x10,0x20,0xE0,0x23,0x18,0x0C,0x06,
"长",0x08,0x00,0x08,0x10,0x08,0x20,0x08,0x40,0x08,0x80,0x09,0x00,0x08,0x00,0xFF,0xFE,
0x0A,0x00,0x09,0x00,0x08,0x80,0x08,0x40,0x09,0x20,0x0A,0x18,0x0C,0x06,0x08,0x00,
保存该编码文件后,将对应文字编码添加到工程文件oledfont.h 当中去。
Ⅱ、代码完善 首先,打开第一个板块:显示学号和姓名 中的工程; 然后将如下代码添加到oled.c 文件当中去: 代码如下:
void OLED_Display_scroll(void)
{
OLED_WR_Byte(0x2e,OLED_CMD);//关滚动
OLED_WR_Byte(0x2a,OLED_CMD);//29向右,2a向左(垂直水平滚动)
OLED_WR_Byte(0x00,OLED_CMD);//A:空字节
OLED_WR_Byte(0x00,OLED_CMD);//B:水平起始页
OLED_WR_Byte(0x00,OLED_CMD);//C:水平滚动速度
OLED_WR_Byte(0x07,OLED_CMD);//D:水平结束页
OLED_WR_Byte(0x01,OLED_CMD);//E:每次垂直滚动位移
OLED_WR_Byte(0x2f,OLED_CMD);//开滚动
}
再将该函数添加到oled.h 文件当中去,如下: 其次,将led.c 文件当中文字部分改成我们想要显示的内容:
void TEST_MainPage(void)
{
GUI_ShowCHinese(0,20,16,"热爱可抵岁月漫长",1);
//GUI_ShowString(40,32,"64X128",16,1);
//GUI_ShowString(4,48,"www.lcdwiki.com",16,1);
delay_ms(1500);
delay_ms(1500);
}
三、主要代码 主函数main.c :
int main(void)
{
delay_init(); //延时函数初始化
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
OLED_Init(); //初始化OLED
OLED_Clear(0); //清屏(全黑)
OLED_Display_scroll(); //滚动屏幕
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
while(1)
{
TEST_MainPage(); //主界面显示测试
}
}
3)结果展示
Ⅰ、电路连接 stm32芯片与USB TO TTL串口的连接方式可以参考我之前的博客
OLED和STM32芯片的连接方式,可以看工程打开时的函数开头所示,具体如下: 实物图为: Ⅱ、代码烧录 打开烧录软件,将以上三个部分生成的HEX文件分别烧录到芯片当中去,烧录成功如下图所示: Ⅲ、结果展示 烧录成功后,即可看到电子屏幕上的内容; ①显示学号和姓名(这里用的是同类型的内容代替 ②显示温湿度
③滚动显示长字符
五、参考内容
SPI协议详解 关于0.96OLED的显示过程详解(I2C通信方式) 基于STM32的温湿度采集——OLED显示
六、总结
此次实验实现了字符在OLED显示屏上显示,虽然中途遇到了很多问题,但最终通过查询资料和询问同学都得到了解决,详细内容请看参考博客。
另外,我之前遇到在Keil中无法输入中文的问题,如有相同问题请见解决方法
|