STM32F1与STM32CubeIDE编程实例-74HC595驱动4位7段数码管

74HC595驱动4位7段数码管

1、74HC595介绍

74HCT595 是一个 8 位串行输入/串行或并行输出移位寄存器,带有一个存储寄存器和三态输出。移位寄存器和存储寄存器都有独立的时钟。该器件具有串行输入 (DS) 和串行输出 (Q7S) 以启用级联和异步复位 MR 输入。 MR 上的低电平将复位移位寄存器。数据在 SHCP 输入的低电平到高电平转换时移位。移位寄存器中的数据在 STCP 输入从低电平到高电平转换时传输到存储寄存器。如果两个时钟连接在一起,移位寄存器将始终比存储寄存器早一个时钟脉冲。只要输出使能输入 (OE) 为低电平,存储寄存器中的数据就会出现在输出端。 OE 上的高电平会导致输出呈现高阻抗关断状态。 OE 输入的操作不会影响寄存器的状态。输入包括钳位二极管。这使得可以使用限流电阻将输入接口连接到超过 VCC 的电压。

在这里插入图片描述

在前面的文章中,对74HC595及其使用做了详细的介绍,请参考:

2、74HC595配置

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

本次实例的74HC595配置如下:

在这里插入图片描述

3、74HC595驱动数码管实现

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
/\*
\* 4bits\_7segments\_led.h
\*
\* Created on: May 5, 2022
\* Author: jenson
\*/

#ifndef \_\_7SEGMENTS\_LED\_H\_\_
#define \_\_7SEGMENTS\_LED\_H\_\_

#include <stm32f1xx\_hal.h>
#include <stdbool.h>

/\*\*
\* @brief 显示类型
\*/
typedef enum {
DEV_7SEG_DISPLAY_TYPE_NUMBER = (0x01 << 0),
DEV_7SEG_DISPLAY_TYPE_CHAR = (0x01 << 2),
DEV_7SEG_DISPLAY_TYPE_DIGIT_AND_CHAR = (0x01 << 3)
} dev\_7segments\_led\_display\_type\_t;

typedef struct {
uint16\_t id;
GPIO_TypeDef \*SCLK_GPIOx; // SCLK端口,Pulse
uint16\_t SCLK_GPIO_Pinx; // SCLK引脚
GPIO_TypeDef \*RCLK_GPIOx; // RCLK端口,Latch
uint16\_t RCLK_GPIO_Pinx; // RCLK引脚
GPIO_TypeDef \*DIO_GPIOx; // DIO端口,Data
uint16\_t DIO_GPIO_Pinx; // DIO引脚
uint8\_t digits; // 位数
uint16\_t refresh_duration; // 刷新时间 ms
uint8\_t \*display_buffer;
uint16\_t display_buffer_len;
dev\_7segments\_led\_display\_type\_t display_type;
} dev\_7segments\_led\_t;

void dev\_7segments\_led\_init(dev\_7segments\_led\_t \*dev);
void dev\_7segments\_led\_clear(dev\_7segments\_led\_t \*dev);
void dev\_7segments\_led\_display\_at(dev\_7segments\_led\_t \*dev, uint16\_t pos,
uint8\_t data, bool dot);
void dev\_7segments\_led\_release(dev\_7segments\_led\_t \*dev);
void dev\_7segments\_led\_set\_number(dev\_7segments\_led\_t \*dev,uint8\_t\* number);
void dev\_7segments\_led\_set\_char(dev\_7segments\_led\_t \*dev,uint8\_t\* data);
void dev\_7segments\_led\_set\_digit\_and\_char(dev\_7segments\_led\_t \*dev,uint8\_t\* data);

void dev\_7segments\_led\_display(dev\_7segments\_led\_t\* dev);
#endif /\* \_\_7SEGMENTS\_LED\_H\_\_ \*/


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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/\*
\* 7segments\_led.c
\*
\* Created on: May 5, 2022
\* Author: jenson
\*/

#include "7segments\_led.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
static uint8\_t __s_led_num[] = { /\*LED数字\*/
0xC0, //0
0xF9, //1
0xA4, //2
0xB0, //3
0x99, //4
0x92, //5
0x82, //6
0xF8, //7
0x80, //8
0x90, //9
0xBF, //-
0xA0, // a
0x83, // b
0xA7, // c
0xA1, // d
0x86, // E
0x8e, // F
};

// DIO引脚设置高电平
void \_\_dev\_7segment\_led\_dio\_low(dev\_7segments\_led\_t \*dev);
// DIO引脚设置低电平
void \_\_dev\_7segment\_led\_dio\_high(dev\_7segments\_led\_t \*dev);
// SCLK引脚设置高电平
void \_\_dev\_7segment\_led\_sclk\_low(dev\_7segments\_led\_t \*dev);
// SCLK引脚设置低电平
void \_\_dev\_7segment\_led\_sclk\_high(dev\_7segments\_led\_t \*dev);
// RCLK引脚设置高电平
void \_\_dev\_7segment\_led\_rclk\_low(dev\_7segments\_led\_t \*dev);
// RCLK引脚设置低电平
void \_\_dev\_7segment\_led\_rclk\_high(dev\_7segments\_led\_t \*dev);
// 开始发送数据
void \_\_dev\_7segment\_led\_pulse(dev\_7segments\_led\_t \*dev);
//锁存数据
void \_\_dev\_7segment\_led\_latch(dev\_7segments\_led\_t \*dev);

void \_\_dev\_7segment\_led\_send\_data(dev\_7segments\_led\_t \*dev, uint8\_t data);

void \_\_dev\_7segments\_led\_display\_number(dev\_7segments\_led\_t \*dev);
void \_\_dev\_7segments\_led\_display\_char(dev\_7segments\_led\_t \*dev);
void \_\_dev\_7segments\_led\_display\_digit\_and\_char(dev\_7segments\_led\_t \*dev);
void \_\_dev\_7segments\_led\_set\_data(dev\_7segments\_led\_t \*dev, uint8\_t \*data,
dev\_7segments\_led\_display\_type\_t type);

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
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
// DIO引脚设置高电平
void \_\_dev\_7segment\_led\_dio\_low(dev\_7segments\_led\_t \*dev) {
HAL\_GPIO\_WritePin(dev->DIO_GPIOx, dev->DIO_GPIO_Pinx, GPIO_PIN_RESET);
}
// DIO引脚设置低电平
void \_\_dev\_7segment\_led\_dio\_high(dev\_7segments\_led\_t \*dev) {
HAL\_GPIO\_WritePin(dev->DIO_GPIOx, dev->DIO_GPIO_Pinx, GPIO_PIN_SET);
}
// SCLK引脚设置高电平
void \_\_dev\_7segment\_led\_sclk\_low(dev\_7segments\_led\_t \*dev) {
HAL\_GPIO\_WritePin(dev->SCLK_GPIOx, dev->SCLK_GPIO_Pinx, GPIO_PIN_RESET);
}
// SCLK引脚设置低电平
void \_\_dev\_7segment\_led\_sclk\_high(dev\_7segments\_led\_t \*dev) {
HAL\_GPIO\_WritePin(dev->SCLK_GPIOx, dev->SCLK_GPIO_Pinx, GPIO_PIN_SET);
}
// RCLK引脚设置高电平
void \_\_dev\_7segment\_led\_rclk\_low(dev\_7segments\_led\_t \*dev) {
HAL\_GPIO\_WritePin(dev->RCLK_GPIOx, dev->RCLK_GPIO_Pinx, GPIO_PIN_RESET);
}
// RCLK引脚设置低电平
void \_\_dev\_7segment\_led\_rclk\_high(dev\_7segments\_led\_t \*dev) {
HAL\_GPIO\_WritePin(dev->RCLK_GPIOx, dev->RCLK_GPIO_Pinx, GPIO_PIN_SET);
}
// 开始发送数据
void \_\_dev\_7segment\_led\_pulse(dev\_7segments\_led\_t \*dev) {
\_\_dev\_7segment\_led\_sclk\_high(dev);
\_\_dev\_7segment\_led\_sclk\_low(dev);
}
//锁存数据
void \_\_dev\_7segment\_led\_latch(dev\_7segments\_led\_t \*dev) {
\_\_dev\_7segment\_led\_rclk\_low(dev);
\_\_dev\_7segment\_led\_rclk\_high(dev);
}

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

uint8\_t \_\_dev\_data\_to\_segment(uint8\_t data) {
if (data >= 0 && data <= 9) {
return __s_led_num[data];
} else if (data == '-') {
return __s_led_num[10];
} else if (data == 'A' || data == 'a') {
return __s_led_num[11];
} else if (data == 'B' || data == 'b') {
return __s_led_num[12];
} else if (data == 'C' || data == 'c') {
return __s_led_num[13];
} else if (data == 'D' || data == 'd') {
return __s_led_num[14];
} else if (data == 'E' || data == 'e') {
return __s_led_num[15];
} else if (data == 'F' || data == 'f') {
return __s_led_num[16];
} else {
return 0xFF;
}
}

void \_\_dev\_7segment\_led\_send\_data(dev\_7segments\_led\_t \*dev, uint8\_t data) {
uint8\_t temp = data;
for (uint8\_t i = 0; i < 8; i++) {
if (temp & (0x80 >> i)) {
\_\_dev\_7segment\_led\_dio\_high(dev);
} else {
\_\_dev\_7segment\_led\_dio\_low(dev);
}

\_\_dev\_7segment\_led\_pulse(dev);
}
}

void \_\_dev\_7segments\_led\_set\_data(dev\_7segments\_led\_t \*dev, uint8\_t \*data,
dev\_7segments\_led\_display\_type\_t type) {
uint8\_t len = strlen(data);
if (len > dev->digits \* 2) { // 数据长度不能超过位数的2倍
return;
}
dev->display_buffer_len = len;
dev->display_type = type;
memcpy(dev->display_buffer, data, sizeof(uint8\_t) \* len);
}

void \_\_dev\_7segments\_led\_display\_number(dev\_7segments\_led\_t \*dev) {
uint8\_t len = dev->display_buffer_len; // 数字长度
uint8\_t dot_pos = 0; // 小数点位置
while (len) {
// 查找小数点位置
if (dev->display_buffer[len - 1] == '.') {
dot_pos++;
break;
}
len--;
}
len = dev->display_buffer_len;
if (len - dot_pos > dev->digits) { // 超过显示位数
for (uint8\_t i = 1; i <= dev->digits; i++) {
dev\_7segments\_led\_display\_at(dev, i, '-', false);
}
len = 0;
return;
}

uint8\_t pos = 1;
bool show_dot = false;
// 处理负号
while (len) {
if (dev->display_buffer[len - 1] == '-') {
dev\_7segments\_led\_display\_at(dev, pos, '-', show_dot);
pos++;
} else if (dev->display_buffer[len - 1] == '.') {
show_dot = true;
} else if (dev->display_buffer[len - 1] == ' ') {
pos++;
} else {
dev\_7segments\_led\_display\_at(dev, pos,
dev->display_buffer[len - 1] - 0x30, show_dot);
show_dot = false;
pos++;
}
len--;
if (pos > dev->digits) { // 超过显示位数截断显示
break;
}
}

}

void \_\_dev\_7segments\_led\_display\_char(dev\_7segments\_led\_t \*dev) {
uint8\_t len = dev->display_buffer_len;
uint8\_t pos = 1;
while (len) {
dev\_7segments\_led\_display\_at(dev, pos, dev->display_buffer[len - 1],
false);
pos++;
len--;
}
}
void \_\_dev\_7segments\_led\_display\_digit\_and\_char(dev\_7segments\_led\_t \*dev) {
uint8\_t len = dev->display_buffer_len; // 数字长度
uint8\_t pos = 1;
bool show_dot = false;
// 处理负号
while (len) {
if (dev->display_buffer[len - 1] == '-') {
dev\_7segments\_led\_display\_at(dev, pos, '-', show_dot);
pos++;
} else if (dev->display_buffer[len - 1] == '.') {
show_dot = true;
} else if (dev->display_buffer[len - 1] == ' ') {
pos++;
} else {
uint8\_t dat = dev->display_buffer[len - 1];
if (isdigit(dat)) {
dev\_7segments\_led\_display\_at(dev, pos, dat - 0x30, show_dot);
} else {
dev\_7segments\_led\_display\_at(dev, pos, dat, show_dot);
}
show_dot = false;
pos++;
}
len--;
if (pos > dev->digits) { // 超过显示位数截断显示
break;
}
}
}

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
void dev\_7segments\_led\_init(dev\_7segments\_led\_t \*dev) {
dev->display_buffer = (uint8\_t\*) malloc(sizeof(uint8\_t) \* dev->digits \* 2);
}

void dev\_7segments\_led\_clear(dev\_7segments\_led\_t \*dev) {
for (uint8\_t i = 0; i < dev->digits; i++) {
dev\_7segments\_led\_display\_at(dev, i, 0xFF, false);
}
}

void dev\_7segments\_led\_display\_at(dev\_7segments\_led\_t \*dev, uint16\_t pos,
uint8\_t data, bool dot) {
if (pos <= 0 || pos > dev->digits) {
return;
}
uint8\_t _temp = \_\_dev\_data\_to\_segment(data);
if (dot) {
_temp &= 0x7F;
}
\_\_dev\_7segment\_led\_send\_data(dev, _temp);

for (uint8\_t i = 0; i < dev->digits; i++) {
if (pos == (i + 1)) {
\_\_dev\_7segment\_led\_send\_data(dev, 0x01 << i);
}
}

\_\_dev\_7segment\_led\_latch(dev);
\_\_dev\_7segment\_led\_delay\_us(10); //10us
}

void dev\_7segments\_led\_refresh(dev\_7segments\_led\_t \*dev) {
uint32\_t current = HAL\_GetTick();
uint32\_t last = HAL\_GetTick();
if (last - current > dev->refresh_duration \* 1000) {

}
}

void dev\_7segments\_led\_release(dev\_7segments\_led\_t \*dev) {
if (dev->display_buffer) {
free(dev->display_buffer);
dev->display_buffer = NULL;
}
}

void dev\_7segments\_led\_set\_number(dev\_7segments\_led\_t \*dev, uint8\_t \*number) {
\_\_dev\_7segments\_led\_set\_data(dev, number, DEV_7SEG_DISPLAY_TYPE_NUMBER);
}

void dev\_7segments\_led\_set\_char(dev\_7segments\_led\_t \*dev, uint8\_t \*data) {
\_\_dev\_7segments\_led\_set\_data(dev, data, DEV_7SEG_DISPLAY_TYPE_CHAR);
}
void dev\_7segments\_led\_set\_digit\_and\_char(dev\_7segments\_led\_t \*dev,
uint8\_t \*data) {
\_\_dev\_7segments\_led\_set\_data(dev, data,
DEV_7SEG_DISPLAY_TYPE_DIGIT_AND_CHAR);
}

void dev\_7segments\_led\_display(dev\_7segments\_led\_t \*dev) {
switch (dev->display_type) {
case DEV_7SEG_DISPLAY_TYPE_NUMBER:
\_\_dev\_7segments\_led\_display\_number(dev);
break;
case DEV_7SEG_DISPLAY_TYPE_CHAR:
\_\_dev\_7segments\_led\_display\_char(dev);
break;
case DEV_7SEG_DISPLAY_TYPE_DIGIT_AND_CHAR:
\_\_dev\_7segments\_led\_display\_digit\_and\_char(dev);
break;
}
}

4、驱动测试

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
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include "7segment\_led/7segments\_led.h"
/\* USER CODE END Includes \*/


/\* USER CODE BEGIN PV \*/
dev\_7segments\_led\_t dev_7segments_led;
/\* 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 \*/
dev_7segments_led.DIO_GPIOx = DIO_GPIO_Port;
dev_7segments_led.DIO_GPIO_Pinx = DIO_Pin;
dev_7segments_led.RCLK_GPIO_Pinx = RCLK_Pin;
dev_7segments_led.RCLK_GPIOx = RCLK_GPIO_Port;
dev_7segments_led.SCLK_GPIO_Pinx = SCLK_Pin;
dev_7segments_led.SCLK_GPIOx = SCLK_GPIO_Port;
dev_7segments_led.id = 1;
dev_7segments_led.digits = 8;

dev\_7segments\_led\_init(&dev_7segments_led);
dev\_7segments\_led\_clear(&dev_7segments_led);

/\* USER CODE END 2 \*/

/\* Infinite loop \*/
uint8\_t data[16] = { 0 };
uint32\_t counter = 0;
/\* USER CODE BEGIN WHILE \*/
while (1) {
/\* USER CODE END WHILE \*/
// dev\_7segments\_led\_display\_at(&dev\_7segments\_led, 0x01, 'A', false);
// dev\_7segments\_led\_display\_at(&dev\_7segments\_led, 0x02, 'B', false);
// dev\_7segments\_led\_display\_at(&dev\_7segments\_led, 0x03, 'C', false);
// dev\_7segments\_led\_display\_at(&dev\_7segments\_led, 0x04, 'D', false);
// dev\_7segments\_led\_display\_at(&dev\_7segments\_led, 0x05, 'E', false);
// dev\_7segments\_led\_display\_at(&dev\_7segments\_led, 0x06, 'F', false);

// dev\_7segments\_led\_set\_number(&dev\_7segments\_led, "-123412.3");
// dev\_7segments\_led\_display(&dev\_7segments\_led);

// dev\_7segments\_led\_set\_char(&dev\_7segments\_led, "ABCDEF");
// dev\_7segments\_led\_display(&dev\_7segments\_led);

dev\_7segments\_led\_set\_digit\_and\_char(&dev_7segments_led, "-E.0.0.3.A.F.E.");
dev\_7segments\_led\_display(&dev_7segments_led);
/\* USER CODE BEGIN 3 \*/

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

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