STM32F1与STM32CubeIDE快速入门-OLED-SSD1306-I2C驱动

OLED-SSD1306-I2C驱动

OLED显示屏是指有机电激发光二极管(OrganicLight-EmittingDiode,OLED)由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。

本次实例将实现对OLED SSD1306基于HAL实现驱动。

在这里插入图片描述

关于OLED驱动的描述在前面的文章中做了详细的描述,请参考:

1、OLED配置

STM32CubeIDE创建工程、系统配置、调试配置,在这里不再做介绍,请参考:

1)OLED的I2C接口参数配置

在这里插入图片描述

2、OLED-SSD1306 I2C驱动实现

2.1 基础驱动实现

2.1.1 驱动基本定义
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
// oled\_ssd1306\_i2c.h
#ifndef OLED\_SSD1306\_I2C\_H\_
#define OLED\_SSD1306\_I2C\_H\_

// 设备地址
#define SSD1306\_I2C\_ADDRESS 0x78
// OLED屏幕分辨率
#define SSD1306\_LCDWIDTH 128
#define SSD1306\_LCDHEIGHT 64

/\*OLED 寄存器命令\*/
#define SSD1306\_SETCONTRAST 0x81
#define SSD1306\_DISPLAYALLON\_RESUME 0xA4
#define SSD1306\_DISPLAYALLON 0xA5
#define SSD1306\_NORMALDISPLAY 0xA6
#define SSD1306\_INVERTDISPLAY 0xA7
#define SSD1306\_DISPLAYOFF 0xAE
#define SSD1306\_DISPLAYON 0xAF
#define SSD1306\_SETDISPLAYOFFSET 0xD3
#define SSD1306\_SETCOMPINS 0xDA
#define SSD1306\_SETVCOMDETECT 0xDB
#define SSD1306\_SETDISPLAYCLOCKDIV 0xD5
#define SSD1306\_SETPRECHARGE 0xD9
#define SSD1306\_SETMULTIPLEX 0xA8
#define SSD1306\_SETLOWCOLUMN 0x00
#define SSD1306\_SETHIGHCOLUMN 0x10
#define SSD1306\_SETSTARTLINE 0x40
#define SSD1306\_MEMORYMODE 0x20
#define SSD1306\_COLUMNADDR 0x21
#define SSD1306\_PAGEADDR 0x22
#define SSD1306\_COMSCANINC 0xC0
#define SSD1306\_COMSCANDEC 0xC8
#define SSD1306\_SEGREMAP 0xA0
#define SSD1306\_CHARGEPUMP 0x8D
#define SSD1306\_EXTERNALVCC 0x1
#define SSD1306\_SWITCHCAPVCC 0x2

/\*屏幕滚动命令\*/
#define SSD1306\_ACTIVATE\_SCROLL 0x2F
#define SSD1306\_DEACTIVATE\_SCROLL 0x2E
#define SSD1306\_SET\_VERTICAL\_SCROLL\_AREA 0xA3
#define SSD1306\_RIGHT\_HORIZONTAL\_SCROLL 0x26
#define SSD1306\_LEFT\_HORIZONTAL\_SCROLL 0x27
#define SSD1306\_VERTICAL\_AND\_RIGHT\_HORIZONTAL\_SCROLL 0x29
#define SSD1306\_VERTICAL\_AND\_LEFT\_HORIZONTAL\_SCROLL 0x2A

typedef enum
{
SCROLL_EVERY_5_FRAMES,
SCROLL_EVERY_64_FRAMES,
SCROLL_EVERY_128_FRAMES,
SCROLL_EVERY_256_FRAMES,
SCROLL_EVERY_3_FRAMES,
SCROLL_EVERY_4_FRAMES,
SCROLL_EVERY_25_FRAMES,
SCROLL_EVERY_2_FRAMES,
} scroll_horizontal_speed;

// 颜色定义
#define BLACK 0
#define WHITE 1
#define INVERSE 2

// 屏幕初始化
void SSD1306\_I2cInit(I2C_HandleTypeDef \*i2c);
// 打开屏幕
void SSD1306\_DisplayON(uint8_t On);
// 屏幕颜色反转
void SSD1306\_InvertColors(uint8_t Invert);
// 旋转屏幕
void SSD1306\_RotateDisplay(uint8_t Rotate);
// 设置对比度
void SSD1306\_SetContrast(uint8_t Contrast);
// 绘制像素
void SSD1306\_DrawPixel(int16_t x, int16_t y, uint8_t Color);
// 清屏
void SSD1306\_Clear(uint8_t Color);
// 显示绘制内容
void SSD1306\_Display(void);
// 绘制图像
void SSD1306\_Bitmap(uint8_t \*bitmap);

#endif

2.1.2 OLED驱动命令与数据发送
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// oled\_ssd1306\_i2c.c
#include "main.h"
#include "stm32f1xx\_hal.h"
#include "oled\_ssd1306\_i2c.h"
#include "i2c.h"
#include "string.h"
// I2C句柄
I2C_HandleTypeDef \*ssd1306_i2c;
// 页面缓存
static uint8_t buffer[SSD1306_LCDHEIGHT \* SSD1306_LCDWIDTH / 8];

// 发送命令
void SSD1306\_Command(uint8_t com){
// 向I2C总线写命令数据
HAL\_I2C\_Mem\_Write(ssd1306_i2c, SSD1306_I2C_ADDRESS, 0x00, 1, &com, sizeof(com), 100);
}

// 发送数据
void SSD1306\_Data(uint8_t dat){
// 向I2C总线写数据
HAL\_I2C\_Mem\_Write(ssd1306_i2c, SSD1306_I2C_ADDRESS, 0x40, 1, &dat, sizeof(dat), 100);
}

2.1.3 OLED初始化
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
void SSD1306\_Init(void){
SSD1306\_Command(0xAE); // 关闭显示

SSD1306\_Command(0x00);
SSD1306\_Command(0x10);
SSD1306\_Command(0x40);
SSD1306\_Command(0x20); // 设置地址模式
SSD1306\_Command(0x00); // 水平寻址

SSD1306\_SetContrast(0xFF); // 设置对比度

SSD1306\_RotateDisplay(1); // 旋转屏幕

SSD1306\_Command(0xA6); // 设置正常显示模式

SSD1306\_Command(0xA8); // 设置复用比率
SSD1306\_Command(0x3F); // Default => 0x3F (1/64 Duty) 0x1F(1/32 Duty)

SSD1306\_Command(0xD3); // 设置显示偏移
SSD1306\_Command(0x00); // 00H 重置

SSD1306\_Command(0xD5); // 设置显示时钟频率
SSD1306\_Command(0x80); // 105HZ

SSD1306\_Command(0xD9); // 设置预充电时间
SSD1306\_Command(0x22);

SSD1306\_Command(0xDA); // 设置 COM 硬件配置
SSD1306\_Command(0x12); // Alternative COM Pin---See IC Spec page 34
// (0x02)=> A4=0;Sequential COM pin configuration;A5=0;Disable COM Left/Right remap

SSD1306\_Command(0xDB); // 设置取消选择 Vcomh 电平
SSD1306\_Command(0x40);

SSD1306\_Command(0x8D); // 设置电荷泵
//SSD1306\_Command(0x10); // Disable Charge Pump
SSD1306\_Command(0x14); // 可终止电荷泵

SSD1306\_Command(0xA4); // 整个显示开启

SSD1306\_DisplayON(1);
}

void SSD1306\_I2cInit(I2C_HandleTypeDef \*i2c){
ssd1306_i2c = i2c;
SSD1306\_Init();
}

2.1.4 清屏
1
2
3
4
5
6
7
8
9
10
11
void SSD1306\_Clear(uint8_t Color){
switch (Color){
case WHITE:
memset(buffer, 0xFF, (SSD1306_LCDHEIGHT \* SSD1306_LCDWIDTH / 8));
break;
case BLACK:
memset(buffer, 0x00, (SSD1306_LCDHEIGHT \* SSD1306_LCDWIDTH / 8));
break;
}
}

2.1.5 绘制单个像素
1
2
3
4
5
6
7
8
9
10
11
void SSD1306\_DrawPixel(int16_t x, int16_t y, uint8_t Color){
if ((x < 0) || (x >= SSD1306_LCDWIDTH) || (y < 0) || (y >= SSD1306_LCDHEIGHT))
return;

switch(Color){
case WHITE: buffer[x+ (y/8)\*SSD1306_LCDWIDTH] |= (1 << (y&7)); break;
case BLACK: buffer[x+ (y/8)\*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break;
case INVERSE: buffer[x+ (y/8)\*SSD1306_LCDWIDTH] ^= (1 << (y&7)); break;
}
}

2.1.6 颜色反转
1
2
3
4
void SSD1306\_InvertColors(uint8_t Invert){
SSD1306\_Command(Invert ? SSD1306_INVERTDISPLAY : SSD1306_NORMALDISPLAY);
}

2.1.7 屏幕旋转
1
2
3
4
5
6
7
8
9
10
11
void SSD1306\_RotateDisplay(uint8_t Rotate){
if(Rotate > 1) Rotate = 1;
SSD1306\_Command(0xA0 | (0x01 & Rotate)); // Set Segment Re-Map Default
// 0xA0 (0x00) => column Address 0 mapped to 127
// 0xA1 (0x01) => Column Address 127 mapped to 0

SSD1306\_Command(0xC0 | (0x08 & (Rotate<<3))); // Set COM Output Scan Direction
// 0xC0 (0x00) => normal mode (RESET) Scan from COM0 to COM[N-1];Where N is the Multiplex ratio.
// 0xC8 (0xC8) => remapped mode. Scan from COM[N-1] to COM0;;Where N is the Multiplex ratio.
}

2.1.8 打开屏幕显示和对比度
1
2
3
4
5
6
7
8
9
void SSD1306\_DisplayON(uint8_t On){
SSD1306\_Command(On ? SSD1306_DISPLAYON : SSD1306_DISPLAYOFF);
}

void SSD1306\_SetContrast(uint8_t Contrast){
SSD1306\_Command(0x81); // Set Contrast Control
SSD1306\_Command(Contrast);
}

2.1.9 绘制图像
1
2
3
4
5
6
7
void SSD1306\_Bitmap(uint8_t \*bitmap){
SSD1306\_Command(0x22);
SSD1306\_Command(0x00);
SSD1306\_Command(0x07);
HAL\_I2C\_Mem\_Write(ssd1306_i2c, SSD1306_I2C_ADDRESS, 0x40, 1, bitmap, (SSD1306_LCDHEIGHT \* SSD1306_LCDWIDTH / 8), 100);
}

2.1.10 刷新显示缓存
1
2
3
4
5
6
7
8
void SSD1306\_Display(void){
SSD1306\_Command(0x22);
SSD1306\_Command(0x00);
SSD1306\_Command(0x07);

HAL\_I2C\_Mem\_Write(ssd1306_i2c, SSD1306_I2C_ADDRESS, 0x40, 1, (uint8_t\*)&buffer, (SSD1306_LCDHEIGHT \* SSD1306_LCDWIDTH / 8), 100);
}

2.2 高级图形绘制实现

2.2.1 基本定义
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
// oled\_ssd1306\_gfx.h
#ifndef \_OLED\_SSD1306\_GFX\_H\_
#define \_OLED\_SSD1306\_GFX\_H\_

#define GFX\_DrawPixel(x,y,color) SSD1306\_DrawPixel(x,y,color)
#define WIDTH SSD1306\_LCDWIDTH
#define HEIGHT SSD1306\_LCDHEIGHT
#define PIXEL\_BLACK BLACK
#define PIXEL\_WHITE WHITE
#define PIXEL\_INVERSE INVERSE
// 设置字体数据
void GFX\_SetFont(const uint8_t \*font_t);
// 设置字体大小
void GFX\_SetFontSize(uint8_t size_t);
// 获取字体高度
uint8_t GFX\_GetFontHeight(void);
// 获取字体宽度
uint8_t GFX\_GetFontWidth(void);
// 获取字体大小
uint8_t GFX\_GetFontSize(void);
// 绘制字符
void GFX\_DrawChar(int x, int y, char chr, uint8_t color, uint8_t background);
// 绘制字符串
void GFX\_DrawString(int x, int y, char \*str, uint8_t color, uint8_t background);
// 绘制直线
void GFX\_DrawLine(int x_start, int y_start, int x_end, int y_end, uint8_t color);
// 绘制矩形
void GFX\_DrawRectangle(int x, int y, uint16_t w, uint16_t h, uint8_t color);
// 矩形填充
void GFX\_DrawFillRectangle(int x, int y, uint16_t w, uint16_t h, uint8_t color);
// 绘制圆
void GFX\_DrawCircle(int x0, int y0, uint16_t r, uint8_t color);
// 圆形填充
void GFX\_DrawFillCircle(int x0, int y0, uint16_t r, uint8_t color);
// 绘制圆角矩形
void GFX\_DrawRoundRectangle(int x, int y, uint16_t w, uint16_t h, uint16_t r,uint8_t color);
// 圆角矩形填充
void GFX\_DrawFillRoundRectangle(int x, int y, uint16_t w, uint16_t h,uint16_t r, uint8_t color);
// 绘制三角形
void GFX\_DrawTriangle(int x0, int y0, int x1, int y1, int x2, int y2,uint8_t color);
// 三角形填充
void GFX\_DrawFillTriangle(int x0, int y0, int x1, int y1, int x2, int y2,uint8_t color);
// 绘制图片
void GFX\_Image(int x, int y, const uint8_t \*img, uint8_t w, uint8_t h,uint8_t color);
#endif

2.2.2 字体设置
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
// oled\_ssd1306\_gfx.c
#include "main.h"
#include "stm32f1xx\_hal.h"
#include "oled\_ssd1306\_i2c.h"
#include "oled\_ssd1306\_gfx.h"
#include <stdlib.h>
#include <math.h>

#define \_swap\_int(a, b) { int t = a; a = b; b = t; }

const uint8_t\* font;
uint8_t size = 1;

void GFX\_SetFont(const uint8_t\* font_t){
font = font_t;
}

void GFX\_SetFontSize(uint8_t size_t){
if(size_t != 0)
size = size_t;
}

uint8_t GFX\_GetFontHeight(void){
return font[0];
}

uint8_t GFX\_GetFontWidth(void){
return font[1];
}

uint8_t GFX\_GetFontSize(void){
return size;
}


2.2.3 绘制字符及字符串
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
void GFX\_DrawChar(int x, int y, char chr, uint8_t color, uint8_t background){
if(chr > 0x7E) return; // chr > '~'

for(uint8_t i=0; i<font[1]; i++ ){
uint8_t line = (uint8_t)font[(chr-0x20) \* font[1] + i + 2];

for(int8_t j=0; j<font[0]; j++, line >>= 1){
if(line & 1){
if(size == 1){
GFX\_DrawPixel(x+i, y+j, color);
}else{
GFX\_DrawFillRectangle(x+i\*size, y+j\*size, size, size, color);
}
}else if(background == 0){
if(size == 1){
GFX\_DrawPixel(x+i, y+j, background);
}else{
GFX\_DrawFillRectangle(x+i\*size, y+j\*size, size, size, background);
}
}
}
}
}

void GFX\_DrawString(int x, int y, char\* str, uint8_t color, uint8_t background){
int x_tmp = x;
char znak;
znak = \*str;
while(\*str++){
GFX\_DrawChar(x_tmp, y, znak, color, background);
x_tmp += ((uint8_t)font[1] \* size) + 1;
if(background == 0){
for(uint8_t i=0; i<(font[0]\*size); i++){
GFX\_DrawPixel(x_tmp-1, y+i, PIXEL_BLACK);
}
}
znak = \*str;
}
}

2.2.4 基本图形绘制-直线
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
void GFX\_WriteLine(int x_start, int y_start, int x_end, int y_end, uint8_t color){
int16_t steep = abs(y_end - y_start) > abs(x_end - x_start);

if (steep) {
\_swap\_int(x_start, y_start);
\_swap\_int(x_end, y_end);
}

if (x_start > x_end) {
\_swap\_int(x_start, x_end);
\_swap\_int(y_start, y_end);
}

int16_t dx, dy;
dx = x_end - x_start;
dy = abs(y_end - y_start);

int16_t err = dx / 2;
int16_t ystep;

if (y_start < y_end) {
ystep = 1;
} else {
ystep = -1;
}

for (; x_start<=x_end; x_start++) {
if (steep) {
GFX\_DrawPixel(y_start, x_start, color);
} else {
GFX\_DrawPixel(x_start, y_start, color);
}
err -= dy;
if (err < 0) {
y_start += ystep;
err += dx;
}
}
}

void GFX\_DrawFastVLine(int x_start, int y_start, int h, uint8_t color){
GFX\_WriteLine(x_start, y_start, x_start, y_start+h-1, color);
}

void GFX\_DrawFastHLine(int x_start, int y_start, int w, uint8_t color){
GFX\_WriteLine(x_start, y_start, x_start+w-1, y_start, color);
}

void GFX\_DrawLine(int x_start, int y_start, int x_end, int y_end, uint8_t color){
if(x_start == x_end){
if(y_start > y_end) \_swap\_int(y_start, y_end);
GFX\_DrawFastVLine(x_start, y_start, y_end - y_start + 1, color);
} else if(y_start == y_end){
if(x_start > x_end) \_swap\_int(x_start, x_end);
GFX\_DrawFastHLine(x_start, y_start, x_end - x_start + 1, color);
} else {
GFX\_WriteLine(x_start, y_start, x_end, y_end, color);
}
}

2.2.5 基本图形绘制-矩形
1
2
3
4
5
6
7
8
9
10
11
12
13
void GFX\_DrawRectangle(int x, int y, uint16_t w, uint16_t h, uint8_t color){
GFX\_DrawFastHLine(x, y, w, color);
GFX\_DrawFastHLine(x, y+h-1, w, color);
GFX\_DrawFastVLine(x, y, h, color);
GFX\_DrawFastVLine(x+w-1, y, h, color);
}

void GFX\_DrawFillRectangle(int x, int y, uint16_t w, uint16_t h, uint8_t color){
for (int i=x; i<x+w; i++) {
GFX\_DrawFastVLine(i, y, h, color);
}
}

2.2.6 基本图形绘制-圆形
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
void GFX\_DrawCircle(int x0, int y0, uint16_t r, uint8_t color){
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 \* r;
int16_t x = 0;
int16_t y = r;

GFX\_DrawPixel(x0 , y0+r, color);
GFX\_DrawPixel(x0 , y0-r, color);
GFX\_DrawPixel(x0+r, y0 , color);
GFX\_DrawPixel(x0-r, y0 , color);

while (x<y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;

GFX\_DrawPixel(x0 + x, y0 + y, color);
GFX\_DrawPixel(x0 - x, y0 + y, color);
GFX\_DrawPixel(x0 + x, y0 - y, color);
GFX\_DrawPixel(x0 - x, y0 - y, color);
GFX\_DrawPixel(x0 + y, y0 + x, color);
GFX\_DrawPixel(x0 - y, y0 + x, color);
GFX\_DrawPixel(x0 + y, y0 - x, color);
GFX\_DrawPixel(x0 - y, y0 - x, color);
}
}

void GFX\_DrawCircleHelper( int x0, int y0, uint16_t r, uint8_t cornername, uint8_t color){
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 \* r;
int16_t x = 0;
int16_t y = r;

while (x<y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;
if (cornername & 0x4) {
GFX\_DrawPixel(x0 + x, y0 + y, color);
GFX\_DrawPixel(x0 + y, y0 + x, color);
}
if (cornername & 0x2) {
GFX\_DrawPixel(x0 + x, y0 - y, color);
GFX\_DrawPixel(x0 + y, y0 - x, color);
}
if (cornername & 0x8) {
GFX\_DrawPixel(x0 - y, y0 + x, color);
GFX\_DrawPixel(x0 - x, y0 + y, color);
}
if (cornername & 0x1) {
GFX\_DrawPixel(x0 - y, y0 - x, color);
GFX\_DrawPixel(x0 - x, y0 - y, color);
}
}
}

void GFX\_DrawFillCircleHelper(int x0, int y0, uint16_t r, uint8_t cornername, int16_t delta, uint8_t color){

int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 \* r;
int16_t x = 0;
int16_t y = r;

while (x<y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x;

if (cornername & 0x1) {
GFX\_DrawFastVLine(x0+x, y0-y, 2\*y+1+delta, color);
GFX\_DrawFastVLine(x0+y, y0-x, 2\*x+1+delta, color);
}
if (cornername & 0x2) {
GFX\_DrawFastVLine(x0-x, y0-y, 2\*y+1+delta, color);
GFX\_DrawFastVLine(x0-y, y0-x, 2\*x+1+delta, color);
}
}
}

void GFX\_DrawFillCircle(int x0, int y0, uint16_t r, uint8_t color){
GFX\_DrawFastVLine(x0, y0-r, 2\*r+1, color);
GFX\_DrawFillCircleHelper(x0, y0, r, 3, 0, color);
}

2.2.7 基本图形绘制-圆角矩形
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void GFX\_DrawRoundRectangle(int x, int y, uint16_t w, uint16_t h, uint16_t r, uint8_t color){
GFX\_DrawFastHLine(x+r , y , w-2\*r, color); // Top
GFX\_DrawFastHLine(x+r , y+h-1, w-2\*r, color); // Bottom
GFX\_DrawFastVLine(x , y+r , h-2\*r, color); // Left
GFX\_DrawFastVLine(x+w-1, y+r , h-2\*r, color); // Right
// draw four corners
GFX\_DrawCircleHelper(x+r , y+r , r, 1, color);
GFX\_DrawCircleHelper(x+w-r-1, y+r , r, 2, color);
GFX\_DrawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
GFX\_DrawCircleHelper(x+r , y+h-r-1, r, 8, color);
}

void GFX\_DrawFillRoundRectangle(int x, int y, uint16_t w, uint16_t h, uint16_t r, uint8_t color){
// smarter version
GFX\_DrawFillRectangle(x+r, y, w-2\*r, h, color);
// draw four corners
GFX\_DrawFillCircleHelper(x+w-r-1, y+r, r, 1, h-2\*r-1, color);
GFX\_DrawFillCircleHelper(x+r , y+r, r, 2, h-2\*r-1, color);
}

2.2.8 基本图形绘制-三角形
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
void GFX\_DrawTriangle(int x0, int y0, int x1, int y1, int x2, int y2, uint8_t color){
GFX\_DrawLine(x0, y0, x1, y1, color);
GFX\_DrawLine(x1, y1, x2, y2, color);
GFX\_DrawLine(x2, y2, x0, y0, color);
}

void GFX\_DrawFillTriangle(int x0, int y0, int x1, int y1, int x2, int y2, uint8_t color){
int16_t a, b, y, last;
// Sort coordinates by Y order (y2 >= y1 >= y0)
if (y0 > y1) {
\_swap\_int(y0, y1); \_swap\_int(x0, x1);
}
if (y1 > y2) {
\_swap\_int(y2, y1); \_swap\_int(x2, x1);
}
if (y0 > y1) {
\_swap\_int(y0, y1); \_swap\_int(x0, x1);
}

if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
a = b = x0;
if(x1 < a) a = x1;
else if(x1 > b) b = x1;
if(x2 < a) a = x2;
else if(x2 > b) b = x2;
GFX\_DrawFastHLine(a, y0, b-a+1, color);
return;
}

int16_t
dx01 = x1 - x0,
dy01 = y1 - y0,
dx02 = x2 - x0,
dy02 = y2 - y0,
dx12 = x2 - x1,
dy12 = y2 - y1;
int32_t
sa = 0,
sb = 0;

// For upper part of triangle, find scanline crossings for segments
// 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
// is included here (and second loop will be skipped, avoiding a /0
// error there), otherwise scanline y1 is skipped here and handled
// in the second loop...which also avoids a /0 error here if y0=y1
// (flat-topped triangle).
if(y1 == y2) last = y1; // Include y1 scanline
else last = y1-1; // Skip it

for(y=y0; y<=last; y++) {
a = x0 + sa / dy01;
b = x0 + sb / dy02;
sa += dx01;
sb += dx02;
/\* longhand:
a = x0 + (x1 - x0) \* (y - y0) / (y1 - y0);
b = x0 + (x2 - x0) \* (y - y0) / (y2 - y0);
\*/
if(a > b) \_swap\_int(a,b);
GFX\_DrawFastHLine(a, y, b-a+1, color);
}

// For lower part of triangle, find scanline crossings for segments
// 0-2 and 1-2. This loop is skipped if y1=y2.
sa = dx12 \* (y - y1);
sb = dx02 \* (y - y0);
for(; y<=y2; y++) {
a = x1 + sa / dy12;
b = x0 + sb / dy02;
sa += dx12;
sb += dx02;
/\* longhand:
a = x1 + (x2 - x1) \* (y - y1) / (y2 - y1);
b = x0 + (x2 - x0) \* (y - y0) / (y2 - y0);
\*/
if(a > b) \_swap\_int(a,b);
GFX\_DrawFastHLine(a, y, b-a+1, color);
}
}

2.2.9 绘制图片
1
2
3
4
5
6
7
8
9
10
void GFX\_Image(int x, int y, const uint8_t \*img, uint8_t w, uint8_t h, uint8_t color){
uint8_t i, j, byteWidth = (w+7)/8;
for(j = 0; j < h; j++){
for(i = 0; i < w; i++){
if(img[j \*byteWidth + i /8] & (128 >> (i&7)) )
GFX\_DrawPixel(x+i, y+j, color);
}
}
}

2.3 主程序

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
// main.c
#include "main.h"
#include "i2c.h"
#include "gpio.h"

/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "OLED\_I2C/oled\_ssd1306\_i2c.h"
#include "OLED\_I2C/oled\_ssd1306\_gfx.h"
#include "oled\_font/fonts.h"

int main(void)
{
/\* USER CODE BEGIN 1 \*/

/\* USER CODE END 1 \*/

/\* MCU Configuration--------------------------------------------------------\*/

/\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/
HAL\_Init();

/\* USER CODE BEGIN Init \*/

/\* USER CODE END Init \*/

/\* Configure the system clock \*/
SystemClock\_Config();

/\* USER CODE BEGIN SysInit \*/

/\* USER CODE END SysInit \*/

/\* Initialize all configured peripherals \*/
MX\_GPIO\_Init();
MX\_I2C1\_Init();
/\* USER CODE BEGIN 2 \*/
SSD1306\_I2cInit(&hi2c1);
GFX\_SetFont(font_8x5);
GFX\_SetFontSize(1);
uint16_t frames = 0, fps = 0;
uint32_t loops = 0, loops_overal = 0;
char fps_c[20];
/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
if (!timer_1s) {
timer_1s = 1000;
fps = frames;
frames = 0;
loops_overal = loops;
loops = 0;
}
sprintf(fps_c, "loops: %02d", (int) loops_overal);
SSD1306\_Clear(BLACK);
GFX\_DrawString(10, 8, fps_c, WHITE, BLACK);
sprintf(fps_c, "FPS: %02d", fps);
GFX\_DrawString(10, 20, fps_c, WHITE, BLACK);
GFX\_DrawString(19, 40, "blog.csdn.net", WHITE, BLACK);
frames++;
SSD1306\_Display();
loops++;
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/
}
/\* USER CODE END 3 \*/
}

2.4 字体数据

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
// fonts.h
#ifndef FONT\_8X5\_H\_
#define FONT\_8X5\_H\_

// Font definition
const uint8_t font_8x5[] =
{
8, 5, //height, width
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5F, 0x00, 0x00,
0x00, 0x07, 0x00, 0x07, 0x00,
0x14, 0x7F, 0x14, 0x7F, 0x14,
0x24, 0x2A, 0x7F, 0x2A, 0x12,
0x23, 0x13, 0x08, 0x64, 0x62,
0x36, 0x49, 0x56, 0x20, 0x50,
0x00, 0x08, 0x07, 0x03, 0x00,
0x00, 0x1C, 0x22, 0x41, 0x00,
0x00, 0x41, 0x22, 0x1C, 0x00,
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
0x08, 0x08, 0x3E, 0x08, 0x08,
0x00, 0x80, 0x70, 0x30, 0x00,
0x08, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x60, 0x60, 0x00,
0x20, 0x10, 0x08, 0x04, 0x02,
0x3E, 0x51, 0x49, 0x45, 0x3E,
0x00, 0x42, 0x7F, 0x40, 0x00,
0x72, 0x49, 0x49, 0x49, 0x46,
0x21, 0x41, 0x49, 0x4D, 0x33,
0x18, 0x14, 0x12, 0x7F, 0x10,
0x27, 0x45, 0x45, 0x45, 0x39,
0x3C, 0x4A, 0x49, 0x49, 0x31,
0x41, 0x21, 0x11, 0x09, 0x07,
0x36, 0x49, 0x49, 0x49, 0x36,
0x46, 0x49, 0x49, 0x29, 0x1E,
0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x40, 0x34, 0x00, 0x00,
0x00, 0x08, 0x14, 0x22, 0x41,
0x14, 0x14, 0x14, 0x14, 0x14,
0x00, 0x41, 0x22, 0x14, 0x08,
0x02, 0x01, 0x59, 0x09, 0x06,
0x3E, 0x41, 0x5D, 0x59, 0x4E,
0x7C, 0x12, 0x11, 0x12, 0x7C,
0x7F, 0x49, 0x49, 0x49, 0x36,
0x3E, 0x41, 0x41, 0x41, 0x22,
0x7F, 0x41, 0x41, 0x41, 0x3E,
0x7F, 0x49, 0x49, 0x49, 0x41,
0x7F, 0x09, 0x09, 0x09, 0x01,
0x3E, 0x41, 0x41, 0x51, 0x73,
0x7F, 0x08, 0x08, 0x08, 0x7F,
0x00, 0x41, 0x7F, 0x41, 0x00,
0x20, 0x40, 0x41, 0x3F, 0x01,
0x7F, 0x08, 0x14, 0x22, 0x41,
0x7F, 0x40, 0x40, 0x40, 0x40,
0x7F, 0x02, 0x1C, 0x02, 0x7F,
0x7F, 0x04, 0x08, 0x10, 0x7F,
0x3E, 0x41, 0x41, 0x41, 0x3E,
0x7F, 0x09, 0x09, 0x09, 0x06,
0x3E, 0x41, 0x51, 0x21, 0x5E,
0x7F, 0x09, 0x19, 0x29, 0x46,
0x26, 0x49, 0x49, 0x49, 0x32,
0x03, 0x01, 0x7F, 0x01, 0x03,
0x3F, 0x40, 0x40, 0x40, 0x3F,
0x1F, 0x20, 0x40, 0x20, 0x1F,
0x3F, 0x40, 0x38, 0x40, 0x3F,
0x63, 0x14, 0x08, 0x14, 0x63,
0x03, 0x04, 0x78, 0x04, 0x03,
0x61, 0x59, 0x49, 0x4D, 0x43,
0x00, 0x7F, 0x41, 0x41, 0x41,
0x02, 0x04, 0x08, 0x10, 0x20,
0x00, 0x41, 0x41, 0x41, 0x7F,
0x04, 0x02, 0x01, 0x02, 0x04,
0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x03, 0x07, 0x08, 0x00,
0x20, 0x54, 0x54, 0x78, 0x40,
0x7F, 0x28, 0x44, 0x44, 0x38,
0x38, 0x44, 0x44, 0x44, 0x28,
0x38, 0x44, 0x44, 0x28, 0x7F,
0x38, 0x54, 0x54, 0x54, 0x18,
0x00, 0x08, 0x7E, 0x09, 0x02,
0x18, 0xA4, 0xA4, 0x9C, 0x78,
0x7F, 0x08, 0x04, 0x04, 0x78,
0x00, 0x44, 0x7D, 0x40, 0x00,
0x20, 0x40, 0x40, 0x3D, 0x00,
0x7F, 0x10, 0x28, 0x44, 0x00,
0x00, 0x41, 0x7F, 0x40, 0x00,
0x7C, 0x04, 0x78, 0x04, 0x78,
0x7C, 0x08, 0x04, 0x04, 0x78,
0x38, 0x44, 0x44, 0x44, 0x38,
0xFC, 0x18, 0x24, 0x24, 0x18,
0x18, 0x24, 0x24, 0x18, 0xFC,
0x7C, 0x08, 0x04, 0x04, 0x08,
0x48, 0x54, 0x54, 0x54, 0x24,
0x04, 0x04, 0x3F, 0x44, 0x24,
0x3C, 0x40, 0x40, 0x20, 0x7C,
0x1C, 0x20, 0x40, 0x20, 0x1C,
0x3C, 0x40, 0x30, 0x40, 0x3C,
0x44, 0x28, 0x10, 0x28, 0x44,
0x4C, 0x90, 0x90, 0x90, 0x7C,
0x44, 0x64, 0x54, 0x4C, 0x44,
0x00, 0x08, 0x36, 0x41, 0x00,
0x00, 0x00, 0x77, 0x00, 0x00,
0x00, 0x41, 0x36, 0x08, 0x00,
0x02, 0x01, 0x02, 0x04, 0x02,
};

#endif /\* FONT\_8X5\_H\_ \*/

3、运行结果

在这里插入图片描述

文章来源: https://iotsmart.blog.csdn.net/article/details/123651926