STM32F1与STM32CubeIDE编程实例-MAX7219驱动8位7段数码管(基于GPIO)

MAX7219驱动8位7段数码管(基于GPIO)

1、MAX7219介绍

MAX7219/MAX7221是紧凑型串行输入/输出共阴极显示驱动器,可将微处理器(μPs)连接至多达8位的7段数字LED显示器、条形图显示器或64个独立LED。 片上包括 BCD 代码 B 解码器、多路扫描电路、段和数字驱动器以及存储每个数字的 8x8 静态 RAM。 只需要一个外部电阻来设置所有 LED 的段电流。 MAX7221 与 SPI™、QSPI™ 和 MICROWIRE™ 兼容,并具有限摆率的段驱动器以降低 EMI。

在这里插入图片描述

一个方便的 4 线串行接口连接到所有常见的 μP。 可以在不重写整个显示的情况下寻址和更新单个数字。 MAX7219还允许用户为每个数字选择code-B解码或不解码。

这些器件包括一个 150μA 低功耗关断模式、模拟和数字亮度控制、一个允许用户显示 1 到 8 位数字的扫描限制寄存器,以及一个强制所有 LED 亮起的测试模式。

在这里插入图片描述

MAX7219具有如下特性:

  • 10MHz 串行接口
  • 单独的 LED 段控制
  • 解码/无解码数字选择
  • 150μA 低功耗关断(数据保留)
  • 数字和模拟亮度控制
  • 上电时显示空白
  • 驱动共阴极LED显示屏
  • 用于降低 EMI 的限摆率分段驱动器 (MAX7221)
  • SPI、QSPI、MICROWIRE 串行接口 (MAX7221)
  • 24 引脚 DIP 和 SO 封装

在前面的文章中对MAX7219的驱动及使用做了详细的介绍,请参考:

2、MAX7219的GPIO配置

开发环境搭建、系统时钟配置、调试配置及串口配置,请参考:

本次实例的MAX7219配置如下:

在这里插入图片描述

3、MAX7219驱动实现

1)MAX7219驱动基本定义

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
/\*
\* max7219\_gpio.h
\*
\* Created on: May 7, 2022
\* Author: jenson
\*/

#ifndef \_\_SPI\_MAX7219\_GPIO\_H\_\_
#define \_\_SPI\_MAX7219\_GPIO\_H\_\_

#include <stm32f1xx\_hal.h>
#include "main.h"
#include <stdio.h>
#include <stdbool.h>

// MAX7219控制命令
#define MAX7219\_NOOP\_REGISTER 0x00
#define MAX7219\_DIGIT0\_REGISTER 0x01
#define MAX7219\_DIGIT1\_REGISTER 0x02
#define MAX7219\_DIGIT2\_REGISTER 0x03
#define MAX7219\_DIGIT3\_REGISTER 0x04
#define MAX7219\_DIGIT4\_REGISTER 0x05
#define MAX7219\_DIGIT5\_REGISTER 0x06
#define MAX7219\_DIGIT6\_REGISTER 0x07
#define MAX7219\_DIGIT7\_REGISTER 0x08

#define MAX7219\_DECODE\_MODE\_REGISTER 0x09
#define MAX7219\_INTENSITY\_REGISTER 0x0A
#define MAX7219\_SCAN\_LIMIT\_REGISTER 0x0B
#define MAX7219\_SHUTDOWN\_REGISTER 0x0C
#define MAX7219\_DISPLAY\_TEST\_REGISTER 0x0F

// MAX7219亮度最小值
#define MAX7219\_INTENSITY\_MIN 0x00
// MAX7219亮度最大值
#define MAX7219\_INTENSITY\_MAX 0x0F

// MAX7219显示缓存长度
#define MAX7219\_MAX\_DIAPLAY\_BUFFER\_LEN 32

// MAX7219扫描类型
typedef enum {
MAX7219_SCAN_DIGIT_0 = 0,
MAX7219_SCAN_DIGIT_0_1 = 1,
MAX7219_SCAN_DIGIT_0_2 = 2,
MAX7219_SCAN_DIGIT_0_3 = 3,
MAX7219_SCAN_DIGIT_0_4 = 4,
MAX7219_SCAN_DIGIT_0_5 = 5,
MAX7219_SCAN_DIGIT_0_6 = 6,
MAX7219_SCAN_DIGIT_0_7 = 7,
} max7219\_scan\_limit\_type\_t;

// MAX7219编码模式
typedef enum {
MAX7219_NoDecode = 0,
MAX7219_DecodeFor0 = 1,
MAX7219_DecodeFor3_0 = 2,
MAX7219_DecodeFor7_0 = 3
} max7219\_decode\_mode\_t;

// MAX7219状态定义
typedef enum {
MAX7219_OK = 0,
MAX7219_ERROR = 1,
MAX7219_UNSUPPORTED_CHAR = 2,
MAX7219_OUT_OF_RANGE = 3
} MAX7219_STATUS;

typedef struct {
uint16\_t id; // 设备ID
GPIO_TypeDef \*CS_GPIOx; // CS端口
uint16\_t CS_Pin; // CS引脚
GPIO_TypeDef \*CLK_GPIOx; // CLK端口
uint16\_t CLK_Pin; // CLK引脚
GPIO_TypeDef \*DIN_GPIOx; // DIN端口
uint16\_t DIN_Pin; // DIN引脚
uint8\_t brightness; // 亮度
uint8\_t \*display_buffer; // 显示缓存
uint16\_t display_buffer_len; // 显示缓存长度
uint8\_t digits;
} max7219\_t;

// MAX7219对齐类型
typedef enum {
MAX7219_ALIGN_RIGHT = 0, //右对齐
MAX7219_ALIGN_LEFT, // 左对齐
} max7219\_align\_t;

// 初始化
void max7219\_init(max7219\_t \*dev);
// 释放
void max7219\_release(max7219\_t \*dev);

// 设置解码模式
MAX7219_STATUS max7219\_set\_decode\_mode(max7219\_t \*dev,
max7219\_decode\_mode\_t mode);
// 设置亮度
void max7219\_set\_brightness(max7219\_t \*dev, uint8\_t level);

// 清屏
void max7219\_clear(max7219\_t \*dev);

// 打开显示
void max7219\_turn\_on(max7219\_t \*dev);
// 关闭显示
void max7219\_turn\_off(max7219\_t \*dev);

// 测试开始
void max7219\_test\_start(max7219\_t \*dev);
// 测试停止
void max7219\_test\_stop(max7219\_t \*dev);

// 指定位置显示字符
void max7219\_display\_digit\_at(max7219\_t \*dev, uint8\_t digit, uint8\_t data,
bool dot);
// 显示数据
void max7219\_set\_display\_data(max7219\_t \*dev, const uint8\_t \*data);
// 显示对齐
void max7219\_display(max7219\_t \*dev, max7219\_align\_t align);

#endif /\* \_\_SPI\_MAX7219\_GPIO\_H\_\_ \*/


2)MAX7219驱动辅助函数定义

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
// max7219\_gpio.c
#include "max7219\_spi.h"
#include <stdbool.h>
#include <stdio.h>
#include "shift\_out.h"

static uint8\_t __display_buffer[MAX7219_MAX_DIAPLAY_BUFFER_LEN] = { 0x00 };
static const uint8\_t __s_max7219_digits[] = { 0x00, // Clear
0x7E, // 0
0x30, // 1
0x6D, // 2
0x79, // 3
0x33, // 4
0x5B, // 5
0x5F, // 6
0x70, // 7
0x7F, // 8
0x7B, // 9
0x77, // A
0x1F, // b
0x0D, // c
0x4E, // C
0x3D, // d
0x6F, // e
0x4F, // E
0x47, // F
0x1E, // h
0x37, // H
0x06, // I
0x38, // J
0x0E, // L
0x15, // n
0x1D, // o
0x67, // P
0x05, // r
// S - same as 5
0x1C, // u
0x3E, // U
0x3B, // y
// Z - same as 2
0x63, // \*
0x01, // -
};

void \_\_max7219\_din\_low(max7219\_t \*dev);
void \_\_max7219\_din\_high(max7219\_t \*dev);
void \_\_max7219\_clk\_low(max7219\_t \*dev);
void \_\_max7219\_clk\_high(max7219\_t \*dev);
void \_\_max7219\_send\_byte(max7219\_t \*dev, int8\_t data);
void \_\_max7219\_delay\_us(uint32\_t us);

void \_\_max7219\_cs\_low(max7219\_t \*dev);
void \_\_max7219\_cs\_high(max7219\_t \*dev);

void \_\_max7219\_write(max7219\_t \*dev, int8\_t reg_number, int8\_t data);

void \_\_max7219\_display\_mix(max7219\_t \*dev);

void \_\_max7219\_cs\_low(max7219\_t \*dev) {
HAL\_GPIO\_WritePin(dev->CS_GPIOx, dev->CS_Pin, GPIO_PIN_RESET);
}

void \_\_max7219\_cs\_high(max7219\_t \*dev) {
HAL\_GPIO\_WritePin(dev->CS_GPIOx, dev->CS_Pin, GPIO_PIN_SET);
}

void \_\_max7219\_din\_low(max7219\_t \*dev) {
HAL\_GPIO\_WritePin(dev->DIN_GPIOx, dev->DIN_Pin, GPIO_PIN_RESET);
}

void \_\_max7219\_din\_high(max7219\_t \*dev) {
HAL\_GPIO\_WritePin(dev->DIN_GPIOx, dev->DIN_Pin, GPIO_PIN_SET);
}

void \_\_max7219\_clk\_low(max7219\_t \*dev) {
HAL\_GPIO\_WritePin(dev->CLK_GPIOx, dev->CLK_Pin, GPIO_PIN_RESET);
}

void \_\_max7219\_clk\_high(max7219\_t \*dev) {
HAL\_GPIO\_WritePin(dev->CLK_GPIOx, dev->CLK_Pin, GPIO_PIN_SET);
}

void \_\_max7219\_delay\_us(uint32\_t us) {
for (int j = 0; j < us; j++) {
\_\_NOP();
}
}

void \_\_max7219\_send\_byte(max7219\_t \*dev, int8\_t data) {
uint8\_t dat = data;
for (uint8\_t i = 8; i >= 1; i--) {
\_\_max7219\_clk\_low(dev);
if (data & 0x80) {
\_\_max7219\_din\_high(dev);
} else {
\_\_max7219\_din\_low(dev);
}

dat = dat >> 1;
\_\_max7219\_clk\_high(dev);
}
}

void \_\_max7219\_write(max7219\_t \*dev, int8\_t reg_number, int8\_t data) {

\_\_max7219\_cs\_low(dev);
shift\_out(dev->DIN_GPIOx, dev->DIN_Pin, dev->CLK_GPIOx, dev->CLK_Pin, MSBFIRST, reg_number);
shift\_out(dev->DIN_GPIOx, dev->DIN_Pin, dev->CLK_GPIOx, dev->CLK_Pin, MSBFIRST, data);
\_\_max7219\_cs\_high(dev);

}

3)MAX7219驱动定义实现

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
232
233
234
235
236
237
238
239
240
// max7219\_gpio.h

void max7219\_init(max7219\_t \*dev) {

dev->display_buffer = __display_buffer;
dev->display_buffer_len = 16;
\_\_max7219\_write(dev, MAX7219_SCAN_LIMIT_REGISTER, MAX7219_SCAN_DIGIT_0_7);
\_\_max7219\_write(dev, MAX7219_DECODE_MODE_REGISTER, MAX7219_NoDecode);
max7219\_turn\_on(dev);
max7219\_test\_stop(dev);
max7219\_clear(dev);
max7219\_set\_brightness(dev, dev->brightness);
}

void max7219\_release(max7219\_t \*dev) {

}

void max7219\_display\_digit\_at(max7219\_t \*dev, uint8\_t digit, uint8\_t data,
bool dot) {
uint8\_t value_to_send;

if (digit > dev->digits || digit < 0) {
return;
}
switch (data) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
value_to_send = __s_max7219_digits[data + 1];
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value_to_send = __s_max7219_digits[data - 47];
break;
case ' ':
value_to_send = __s_max7219_digits[0];
break;
case 'a':
case 'A':
value_to_send = __s_max7219_digits[11];
break;
case 'b':
case 'B':
value_to_send = __s_max7219_digits[12];
break;
case 'c':
value_to_send = __s_max7219_digits[13];
break;
case 'C':
value_to_send = __s_max7219_digits[14];
break;
case 'd':
case 'D':
value_to_send = __s_max7219_digits[15];
break;
case 'e':
value_to_send = __s_max7219_digits[16];
break;
case 'E':
value_to_send = __s_max7219_digits[17];
break;
case 'F':
case 'f':
value_to_send = __s_max7219_digits[18];
break;
case 'h':
value_to_send = __s_max7219_digits[19];
break;
case 'H':
value_to_send = __s_max7219_digits[20];
break;
case 'i':
case 'I':
value_to_send = __s_max7219_digits[21];
break;
case 'j':
case 'J':
value_to_send = __s_max7219_digits[22];
break;
case 'l':
case 'L':
value_to_send = __s_max7219_digits[23];
break;
case 'n':
case 'N':
value_to_send = __s_max7219_digits[24];
break;
case 'o':
case 'O':
value_to_send = __s_max7219_digits[25];
break;
case 'p':
case 'P':
value_to_send = __s_max7219_digits[26];
break;
case 'r':
case 'R':
value_to_send = __s_max7219_digits[27];
break;
case 's':
case 'S':
value_to_send = __s_max7219_digits[6];
break;
case 'u':
value_to_send = __s_max7219_digits[28];
break;
case 'U':
value_to_send = __s_max7219_digits[29];
break;
case 'y':
case 'Y':
value_to_send = __s_max7219_digits[30];
break;
case 'z':
case 'Z':
value_to_send = __s_max7219_digits[3];
break;
case '\*':
value_to_send = __s_max7219_digits[31];
break;
case '-':
value_to_send = __s_max7219_digits[32];
break;
default:
return;
break;
}
value_to_send |= dot ? 0x80 : 0x00;

\_\_max7219\_write(dev, digit, value_to_send);
}



MAX7219_STATUS max7219\_set\_decode\_mode(max7219\_t \*dev,
max7219\_decode\_mode\_t mode) {
if (mode > 4) {
return MAX7219_ERROR;
}
\_\_max7219\_write(dev, MAX7219_DECODE_MODE_REGISTER, mode);
return MAX7219_OK;
}

void max7219\_clear(max7219\_t \*dev) {
for (uint8\_t i = 1; i <= dev->digits; i++) {
\_\_max7219\_write(dev, i, 0x00);
}
memset(dev->display_buffer, ' ', MAX7219_MAX_DIAPLAY_BUFFER_LEN);
}

void max7219\_turn\_on(max7219\_t \*dev) {
\_\_max7219\_write(dev, MAX7219_SHUTDOWN_REGISTER, 0x01);
}

void max7219\_turn\_off(max7219\_t \*dev) {
\_\_max7219\_write(dev, MAX7219_SHUTDOWN_REGISTER, 0x00);
}

void max7219\_test\_start(max7219\_t \*dev) {
\_\_max7219\_write(dev, MAX7219_DISPLAY_TEST_REGISTER, 0x01);
}

void max7219\_test\_stop(max7219\_t \*dev) {
\_\_max7219\_write(dev, MAX7219_DISPLAY_TEST_REGISTER, 0x00);
}

void max7219\_set\_brightness(max7219\_t \*dev, uint8\_t level) {
dev->brightness = level & 0x0F;
\_\_max7219\_write(dev, MAX7219_INTENSITY_REGISTER, dev->brightness);
}

void max7219\_set\_display\_data(max7219\_t \*dev, const uint8\_t \*data) {
size\_t len = strlen(data);
if (len > 0 && len < MAX7219_MAX_DIAPLAY_BUFFER_LEN) {
memset(dev->display_buffer, ' ', MAX7219_MAX_DIAPLAY_BUFFER_LEN);
dev->display_buffer_len = len;
memcpy(dev->display_buffer, data, len);
}
}

void max7219\_display(max7219\_t \*dev, max7219\_align\_t align) {
uint8\_t buffer_len = dev->display_buffer_len;
uint8\_t offset = 0;
uint8\_t dot = 0;
uint8\_t commas = 0;

for (uint8\_t i = 0; i < buffer_len; i++) {
if (dev->display_buffer[i] == '.' || dev->display_buffer[i] == ',') {
commas++;
}
}

switch (align) {
case MAX7219_ALIGN_RIGHT:
offset = dev->digits - buffer_len + commas;
offset %= dev->digits;
break;
case MAX7219_ALIGN_LEFT:
offset = 0;
break;
default:
return;

}

uint8\_t data;
for (uint8\_t i = 0; i < buffer_len;) {
data = dev->display_buffer[i];
if (dev->display_buffer[i + 1] == '.'
|| dev->display_buffer[i + 1] == ',') {
dot = 1;
i++;
} else {
dot = 0;
}

max7219\_display\_digit\_at(dev, dev->digits - (offset++), data, dot);
i++;
if (offset > dev->digits) { // 超出位数截断
break;
}
}
}

4)MAX7219数据按位发送底层实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/\*
\* shift\_out.h
\*
\* Created on: May 7, 2022
\* Author: jenson
\*/

#ifndef \_\_SHIFT\_OUT\_H\_\_
#define \_\_SHIFT\_OUT\_H\_\_

#include <stm32f1xx\_hal.h>

typedef enum {
LSBFIRST, MSBFIRST
} bit\_order\_t;

void shift\_out(GPIO_TypeDef \*data_port, uint16\_t data_pin,
GPIO_TypeDef \*clk_port, uint16\_t clk_pin, bit\_order\_t bit_order,
uint8\_t val);

#endif /\* SHIFT\_OUT\_H\_ \*/


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
/\*
\* shift\_out.c
\*
\* Created on: May 7, 2022
\* Author: jenson
\*/

#include "shift\_out.h"

void shift\_out(GPIO_TypeDef \*data_port, uint16\_t data_pin,
GPIO_TypeDef \*clk_port, uint16\_t clk_pin, bit\_order\_t bit_order,
uint8\_t val) {
uint8\_t i;

for (i = 0; i < 8; i++) {
if (bit_order == LSBFIRST) {
HAL\_GPIO\_WritePin(data_port, data_pin, !!(val & (1 << i)));
} else {
HAL\_GPIO\_WritePin(data_port, data_pin, !!(val & (1 << (7 - i))));
}
HAL\_GPIO\_WritePin(clk_port,clk_pin,GPIO_PIN_SET);
HAL\_GPIO\_WritePin(clk_port,clk_pin,GPIO_PIN_RESET);
}
}


4、MAX7219驱动测试

main.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
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include <stdio.h>
#include "max7219\_spi/max7219\_gpio.h"
/\* USER CODE END Includes \*/

/\* USER CODE BEGIN PV \*/
max7219\_t max7219;
uint8\_t display_buffer[16];
/\* USER CODE END PV \*/


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\_USART1\_UART\_Init();
/\* USER CODE BEGIN 2 \*/

max7219.CLK_GPIOx = MAX7219_CLK_GPIO_Port;
max7219.CLK_Pin = MAX7219_CLK_Pin;
max7219.CS_GPIOx = MAX7219_CS_GPIO_Port;
max7219.CS_Pin = MAX7219_CS_Pin;
max7219.DIN_GPIOx = MAX7219_DIN_GPIO_Port;
max7219.DIN_Pin = MAX7219_DIN_Pin;
printf("\*\*\*\*STM32CubeIDE:Max7219 8bits LED(GPIO)\*\*\*\*\r\n");

max7219.id = 1;
max7219.digits = 8;
max7219.brightness = 3;

max7219\_init(&max7219);

max7219\_set\_display\_data(&max7219, "-.-.-.-.-.-.-.-.");
max7219\_display(&max7219, MAX7219_ALIGN_RIGHT);
HAL\_Delay(1000);
max7219\_clear(&max7219);
printf("display 1\r\n");
max7219\_set\_display\_data(&max7219, "8.8.8.8.8.8.8.8.");
max7219\_display(&max7219, MAX7219_ALIGN_RIGHT);
HAL\_Delay(1000);
max7219\_clear(&max7219);
printf("display 2\r\n");
max7219\_set\_display\_data(&max7219, "-3.1415");
max7219\_display(&max7219, MAX7219_ALIGN_RIGHT);
printf("display 3\r\n");
/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/

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

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