我是靠谱客的博主 失眠芒果,这篇文章主要介绍STM32用SPI方式控制OLED模块一、OLED二、GPIO模拟SPI三、STM32对OLED模块的控制四、用STM32的SPI资源(可选),现在分享给大家,希望可以做个参考。

一、OLED

1. OLED模块的外观

外观

2. OLED模块的电路图

电路图

3. OLED模块参数

项目说明
接口特性3.3V(串电阻后,可与 5V 系统连接)
通信接口4 线 SPI
屏幕分辨率128*64
屏幕尺寸0.96 寸
工作温度-40℃~70℃

颜色 纯蓝色、黄蓝双色
模块尺寸| 27mm*26mm

二、GPIO模拟SPI

1. 硬件连接

通过引脚和模块电路图可以分析出SPI的电路连接

复制代码
1
2
3
4
5
6
7
8
9
OLED STM32 GND <----------> GND VCC <----------> 3.3V D0 <----------> PA4(CLK) D1 <----------> PA3(MOSI) RES <----------> PA2(RET复位) DC <----------> PA1(命令|数据dc) CS <----------> GND

2. 软件驱动

SPI

由OLED模块数据手册上SPI的操作时序图写出由GPIO口模拟的SPI驱动代码

模块只支持向模块写数据不能读数据

所以只需要写SPI发送即可

2.1 “SPI.h”

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define OLED_CMD 0 //命令声明 #define OLED_DATA 1 //数据声明 #define OLED_CLK PAout(4) // CLK时钟 d0 #define OLED_MOSI PAout(3) // MOSI d1 #define OLED_RST PAout(2) // RET复位 ret #define OLED_DC PAout(1) // 命令|数据 dc (0表传输命令1表传输数据) void OLED_SPI_Init(void); //配置MCU的SPI void SPI_WriteByte(uint8_t addr,uint8_t data); //向寄存器地址写一个byte的数据 void WriteCmd(unsigned char cmd); //写命令 void WriteDat(unsigned char data); //写数据

2.2 “SPI.c”

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*************************************************************************/ /*函数功能: GPIO模拟SPI端口初始化 */ /*************************************************************************/ void OLED_SPI_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);//使能PA端口时钟 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; //端口配置 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//IO口速度为50MHz GPIO_Init(GPIOA,&GPIO_InitStructure);//根据设定参数初始化GPIOA } /*************************************************************************/ /*函数功能: 通过SPIO软件模拟SPI通信协议,向模块(SSD1306)写入一个字节 */ /*入口参数: */ /* data:要写入的数据/命令 */ /* cmd :数据/命令标志 0,表示命令;1,表示数据; */ /*************************************************************************/ void SPI_WriteByte(unsigned char data,unsigned char cmd) { unsigned char i=0; OLED_DC =cmd; OLED_CLK=0; for(i=0;i<8;i++) { OLED_CLK=0; if(data&0x80)OLED_MOSI=1; //从高位到低位 else OLED_MOSI=0; OLED_CLK=1; data<<=1; } OLED_CLK=1; OLED_DC=1; } /*************************************************************************/ /*函数功能: 写命令 */ /*************************************************************************/ void WriteCmd(unsigned char cmd) { SPI_WriteByte(cmd,OLED_CMD); } /*************************************************************************/ /*函数功能: 写数据 */ /*************************************************************************/ void WriteData(unsigned char data) { SPI_WriteByte(data,OLED_DATA); }

三、STM32对OLED模块的控制

3.1 指令集

序号HEX指令说明
081设置对比度值越大,屏幕越亮(默认 0X7F); 0X000XFF(1255)
1AE/AF设置显示开关AE,关闭显示;AF,开启显示
28D电荷泵设置0x10,关闭电荷泵;0x14开启电荷泵
3B0~B7设置页地址0~7 对应页 0~7
400~0F设置列地址(低四位)设置 8 位起始列地址的低四位
510~1F设置列地址(高四位)设置 8 位起始列地址的高四位

更多请查询SSD1306 的data sheet

3.2 “OLED.h"

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
void OLED_Init(void);//初始化OLED void OLED_ON(void);//唤醒OLED void OLED_OFF(void);//OLED休眠 void OLED_Refresh_Gram(void);//更新显存到OLED void OLED_Clear(void);//清屏 void OLED_DrawPoint(u8 x,u8 y,u8 t);//画点 void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);//填充 void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode);//显示字符 void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);//显示2个数字 void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size);//显示字符串

3.3 “OLED.c”

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
//OLED的显存 //存放格式如下. //[0]0 1 2 3 ... 127 //[1]0 1 2 3 ... 127 //[2]0 1 2 3 ... 127 //[3]0 1 2 3 ... 127 //[4]0 1 2 3 ... 127 //[5]0 1 2 3 ... 127 //[6]0 1 2 3 ... 127 //[7]0 1 2 3 ... 127 u8 OLED_GRAM[128][8]; /*************************************************************************/ /*函数功能: 软延时 */ /*************************************************************************/ void OLED_DLY_ms(unsigned int ms) { unsigned int a; while(ms) { a=1335; while(a--); ms--; } } /*************************************************************************/ /*函数功能: 初始化OLED模块 */ /*************************************************************************/ void OLED_Init(void) { OLED_SPI_Init(); OLED_CLK = 1; OLED_RST = 0; OLED_DLY_ms(100); OLED_RST = 1; //从上电到下面开始初始化要有足够的时间,即等待RC复位完毕 WriteCmd(0xAE); // Display Off (0x00) WriteCmd(0xD5); WriteCmd(0x80); // Set Clock as 100 Frames/Sec WriteCmd(0xA8); WriteCmd(0x3F); // 1/64 Duty (0x0F~0x3F) WriteCmd(0xD3); WriteCmd(0x00); // Shift Mapping RAM Counter (0x00~0x3F) WriteCmd(0x40 | 0x00); // Set Mapping RAM Display Start Line (0x00~0x3F) WriteCmd(0x8D); WriteCmd(0x10 | 0x04); // Enable Embedded DC/DC Converter (0x00/0x04) WriteCmd(0x20); WriteCmd(0x02); // Set Page Addressing Mode (0x00/0x01/0x02) WriteCmd(0xA0 | 0x01); // Set SEG/Column Mapping WriteCmd(0xC0); // Set COM/x Scan Direction WriteCmd(0xDA); WriteCmd(0x02 | 0x10); // Set Sequential Configuration (0x00/0x10) WriteCmd(0x81); WriteCmd(0xCF); // Set SEG Output Current WriteCmd(0xD9); WriteCmd(0xF1); // Set Pre-Charge as 15 Clocks & Discharge as 1 Clock WriteCmd(0xDB); WriteCmd(0x40); // Set VCOM Deselect Level WriteCmd(0xA4 | 0x00); // Disable Entire Display On (0x00/0x01) WriteCmd(0xA6 | 0x00); // Disable Inverse Display On (0x00/0x01) WriteCmd(0xAE | 0x01); // Display On (0x01) OLED_Clear(); //初始清屏 } /*************************************************************************/ /*函数功能: 将OLED从休眠中唤醒 */ /*************************************************************************/ void OLED_ON(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X14); //开启电荷泵 WriteCmd(0XAF); //OLED唤醒 } /*************************************************************************/ /*函数功能: 将OLED休眠 -- 休眠模式下,OLED功耗不到10uA */ /*************************************************************************/ void OLED_OFF(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X10); //关闭电荷泵 WriteCmd(0XAE); //OLED休眠 } /*************************************************************************/ /*函数功能: 更新显存到OLED */ /*************************************************************************/ void OLED_Refresh_Gram(void) { u8 i,n; for(i=0;i<8;i++) { WriteCmd(0xb0+i); //设置页地址(0~7) WriteCmd(0x00); //设置显示位置—列低地址 WriteCmd(0x10); //设置显示位置—列高地址 for(n=0;n<128;n++)WriteData(OLED_GRAM[n][i]); } } /*************************************************************************/ /*函数功能: 清屏 */ /*************************************************************************/ 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 */ /* dot:0,清空;1,填充 */ /*************************************************************************/ 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; } /*************************************************************************/ /*函数功能: 填充 */ /*入口参数: */ /* x1,y1,x2,y2 填充区域的对角坐标 */ /* 确保x1<=x2;y1<=y2 0<=x1<=127 0<=y1<=63 */ /* dot:0,清空;1,填充 */ /*************************************************************************/ void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot) { u8 x,y; for(x=x1;x<=x2;x++) { for(y=y1;y<=y2;y++)OLED_DrawPoint(x,y,dot); } OLED_Refresh_Gram();//更新显示 } /*************************************************************************/ /*函数功能: 在指定位置显示一个字符,包括部分字符 */ /*入口参数: */ /* x:0~12 */ /* 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; u8 csize=(size/8+((size%8)?1:0))*(size/2); //得到字体一个字符对应点阵集所占的字节数 chr=chr-' ';//得到偏移后的值 for(t=0;t<csize;t++) { if(size==12)temp=asc2_1206[chr][t]; //调用1206字体 else if(size==16)temp=asc2_1608[chr][t]; //调用1608字体 else if(size==24)temp=asc2_2412[chr][t]; //调用2412字体 else return; //没有的字库 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 mypow(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_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size) { u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/mypow(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:起点坐标 */ /* size:字体大小 */ /* *p:字符串起始地址 */ /*************************************************************************/ void OLED_ShowString(u8 x,u8 y,const u8 *p,u8 size) { while((*p<='~')&&(*p>=' '))//判断是不是非法字符! { if(x>(128-(size/2))){x=0;y+=size;} if(y>(64-size)){y=x=0;OLED_Clear();} OLED_ShowChar(x,y,*p,size,1); x+=size/2; p++; } }

四、用STM32的SPI资源(可选)

也可以不使用GPIO口模拟,使用STM32的SPI资源

驱动代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
void OLED_SPI_Init(void) { /* GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);//使能PA端口时钟 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4; //端口配置 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//IO口速度为50MHz GPIO_Init(GPIOA,&GPIO_InitStructure);//根据设定参数初始化GPIOA */ GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA| RCC_APB2Periph_SPI1, ENABLE ); //①GPIO,SPI 时钟使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_7); //①初始化 GPIO GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2;//端口配置 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//IO口速度为50MHz GPIO_Init(GPIOA,&GPIO_InitStructure);//根据设定参数初始化GPIOA SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置 SPI 全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置 SPI 工作模式:设置为主 SPI SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8 位帧结构 SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//选择了串行时钟的稳态:时钟悬空高 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //数据捕获于第二个时钟沿 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS 信号由硬件管理 SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; //预分频 256 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从 MSB 位开始 SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC 值计算的多项式 SPI_Init(SPI1, &SPI_InitStructure); //②根据指定的参数初始化外设 SPIx 寄存器 SPI_Cmd(SPI1, ENABLE); //③使能 SPI 外设 //SPI1_ReadWriteByte(0xff);//④启动传输 } void OLED_WB(uint8_t data) { /* Loop while DR register in not emplty */ while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); /* Send byte through the SPI2 peripheral */ SPI_I2S_SendData(SPI1, data); } void SPI_WriteByte(unsigned char data,unsigned char cmd) { unsigned char i=0; OLED_DC =cmd; OLED_WB(data); }

PS:可以通过添加公众号“山不高海不深”回复关键字“OLED代码“得到完整工程代码
在这里插入图片描述

回复关键字“OLED代码“得到完整工程代码

最后

以上就是失眠芒果最近收集整理的关于STM32用SPI方式控制OLED模块一、OLED二、GPIO模拟SPI三、STM32对OLED模块的控制四、用STM32的SPI资源(可选)的全部内容,更多相关STM32用SPI方式控制OLED模块一、OLED二、GPIO模拟SPI三、STM32对OLED模块内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(71)

评论列表共有 0 条评论

立即
投稿
返回
顶部