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

TM1637驱动4位7段数码管

1、TM1637介绍

TM1637 是一种带键盘扫描接口的LED(发光二极管显示器) 驱动控制专用电路, 内部集成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。本产品性能优良,质量可靠。主要应用于电磁炉、微波炉及小家电产品的显示屏驱动。

在这里插入图片描述

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

2、TM1637配置

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

本次实例的TM1637配置如下:

在这里插入图片描述

3、TM1637驱动实现

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

#ifndef TM1637\_SIMPLE\_TM1637\_SIMPLE\_H\_
#define TM1637\_SIMPLE\_TM1637\_SIMPLE\_H\_

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

#define TM1637\_ADDR\_AUTO 0x40 // 自动地址
#define TM1637\_ADDR\_FIXED 0x44 // 固定地址

#define MINUS\_SIGN\_IDX 16
#define TM1637\_DELAY\_US 3
#define TM1637\_MAX\_BRIGHTNESS 0x07
#define TM\_DEG 0x63

#define INDEX\_NEGATIVE\_SIGN 16
#define INDEX\_BLANK 0 // 17 nothing ,0 zero beter for clock

typedef struct {
uint16\_t id;
GPIO_TypeDef \*CLK_GPIOx; // CLK端口
uint16\_t CLK_GPIO_Pinx; // CLK引脚
GPIO_TypeDef \*DIO_GPIOx; // DIO端口
uint16\_t DIO_GPIO_Pinx; // DIO引脚
uint8\_t brightness; // 亮度
uint8\_t digital_bits; // 位数
bool dot_blink_state;
} tm1637\_t;

/\*\*
\* @brief 初始化
\* @param tm1637 tm1637\_t对象
\*/
void tm1637\_init(tm1637\_t \*tm1637);

/\*\*
\* @brief 设置亮度
\* @param tm1637 tm1637\_t对象
\* @param level uint8\_t 亮度级别,最大值为7
\*/
void tm1637\_set\_brightness(tm1637\_t \*tm1637, uint8\_t level);

/\*\*
\* @brief 在指定位显示数字
\* @param tm1637 tm1637\_t对象
\* @param segment\_idx uint8\_t 位数,不能超过tm1637\_t对象的最大位数
\* @param number uint8\_t 需要显示的数字(0~9)
\* @param dot bool 是否显示点
\*/
void tm1637\_set\_segment\_number(tm1637\_t \*tm1637, uint8\_t segment_idx,
const uint8\_t number, const bool dot);

/\*\*
\* @brief 显示带有前导0及小数点的数字
\* @param tm1637 tm1637\_t对象
\* @param number uint16\_t 所要显示的数字,数字最大位数和小点和前导0的总位数不能超过tm1637\_t的最大位数。
\* @param lead\_zero bool 是否显示前导0
\* @param dot\_mask uint8\_t 点掩码
\*/
void tm1637\_set\_number\_lead\_dot(tm1637\_t \*tm1637, uint16\_t number,
bool lead_zero, const uint8\_t dot_mask);

/\*\*
\* @brief 显示温度
\* @param tm1637 tm1637\_t对象
\* @param temperature uint16\_t 温度值,值范围为[-99~999]之间
\*/
void tm1637\_display\_temperature(tm1637\_t \*tm1637, int16\_t temperature);

/\*\*
\* @brief 显示温度
\* @param tm1637 tm1637\_t对象
\* @param number int16\_t 数字,范围[-999~9999]
\*/
void tm1637\_display\_number(tm1637\_t \*tm1637, int16\_t number);

/\*\*
\* @brieef 显示浮点值
\* @param tm1637 tm1637\_t对象
\* @param value float 显示的浮点值
\*/
void tm1637\_display\_float(tm1637\_t \*tm1637, float value);

/\*\*
\* @brief 显示字符
\* @param tm1637 tm1637\_t对象
\* @param data uint8\_t\* 字符
\*/
void tm1637\_display\_string(tm1637\_t \*tm1637, const int8\_t \*data);

/\*\*
\* @brief 显示时间
\* @param tm1637 tm1637\_t对象
\* @param hours uint8\_t 时
\* @param minutes uint8\_t 分
\*/
void tm1637\_display\_time(tm1637\_t\* tm1637,uint8\_t hours,uint8\_t minutes,bool dot_blink);

/\*\*
\* @brief 清屏
\* @param tm1637 tm1637\_t对象
\*/
void tm1637\_clear(tm1637\_t \*tm1637);

#endif /\* TM1637\_SIMPLE\_TM1637\_SIMPLE\_H\_ \*/


2)7段数码管定义

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
/\*
\* 七段管定义
//Segments
// --0x01--
// | |
//0x20 0x02
// | |
// --0x40- -
// | |
//0x10 0x04
// | |
// --0x08--
\* \*/

static const int8\_t __tm1637_symbols[] = {
// XGFEDCBA
0x3f,// 0b00111111, // 0
0x06, // 0b00000110, // 1
0x5b, // 0b01011011, // 2
0x4f, // 0b01001111, // 3
0x66, // 0b01100110, // 4
0x6d, // 0b01101101, // 5
0x7d, // 0b01111101, // 6
0x07, // 0b00000111, // 7
0x7f, // 0b01111111, // 8
0x6f, // 0b01101111, // 9
0x77, // 0b01110111, // A
0x7c, // 0b01111100, // b
0x39, // 0b00111001, // C
0x5e, // 0b01011110, // d
0x79, // 0b01111001, // E
0x71, // 0b01110001 // F
0x40, // 0b01000000 // minus sign
};

static const uint8\_t __s_ascii[] = { 0x00, // 032 (Space)
0x30, // 033 !
0x22, // 034 "
0x41, // 035 #
0x6D, // 036 $
0x52, // 037 %
0x7C, // 038 &
0x20, // 039 '
0x39, // 040 (
0x0F, // 041 )
0x21, // 042 \*
0x70, // 043 +
0x08, // 044 ,
0x40, // 045 -
0x80, // 046 .
0x52, // 047 /
0x3F, // 048 0
0x06, // 049 1
0x5B, // 050 2
0x4F, // 051 3
0x66, // 052 4
0x6D, // 053 5
0x7D, // 054 6
0x07, // 055 7
0x7F, // 056 8
0x6F, // 057 9
0x48, // 058 :
0x48, // 059 ;
0x39, // 060 <
0x48, // 061 =
0x0F, // 062 >
0x53, // 063 ?
0x5F, // 064 @
0x77, // 065 A
0x7C, // 066 B
0x39, // 067 C
0x5E, // 068 D
0x79, // 069 E
0x71, // 070 F
0x3D, // 071 G
0x76, // 072 H
0x30, // 073 I
0x1E, // 074 J
0x7A, // 075 K
0x38, // 076 L
0x55, // 077 M
0x54, // 078 N
0x5C, // 079 O
0x73, // 080 P
0x67, // 081 Q
0x50, // 082 R
0x6D, // 083 S
0x78, // 084 T
0x3E, // 085 U
0x7E, // 086 V
0x6A, // 087 W
0x36, // 088 X
0x6E, // 089 Y
0x48, // 090 Z
0x39, // 091 [
0x64, // 092 (backslash)
0x0F, // 093 ]
0x23, // 094 ^
0x08, // 095 \_
0x20, // 096 `
0x77, // 097 a
0x7C, // 098 b
0x58, // 099 c
0x5E, // 100 d
0x79, // 101 e
0x71, // 102 f
0x3D, // 103 g
0x74, // 104 h
0x10, // 105 i
0x1E, // 106 j
0x7A, // 107 k
0x18, // 108 l
0x55, // 109 m
0x54, // 110 n
0x5C, // 111 o
0x73, // 112 p
0x67, // 113 q
0x50, // 114 r
0x6D, // 115 s
0x78, // 116 t
0x1C, // 117 u
0x1C, // 118 v
0x6A, // 119 w
0x36, // 120 x
0x6E, // 121 y
0x48, // 122 z
0x39, // 123 {
0x30, // 124 |
0x0F, // 125 }
0x40, // 126 ~
0x00 // 127 
};

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
// CLK引脚设置高电平
void \_\_tm1637\_clk\_high(tm1637\_t \*tm1637);
// CLK引脚设置低电平
void \_\_tm1637\_clk\_low(tm1637\_t \*tm1637);
// DIO引脚设置高电平
void \_\_tm1637\_dio\_high(tm1637\_t \*tm1637);
// DIO引脚设置低电平
void \_\_tm1637\_dio\_low(tm1637\_t \*tm1637);
// 将DIO设置为输入
void \_\_tm1637\_dio\_set\_input(tm1637\_t \*tm1637);
// 将DIO设置为输出
void \_\_tm1637\_dio\_set\_output(tm1637\_t \*tm1637);
void \_\_tm1637\_delay\_us(uint32\_t us);
// TM1637固定延时3us
void \_\_tm1637\_delay();
// 发送开始信号
void \_\_tm1637\_start(tm1637\_t \*tm1637);
// 发送结束信号
void \_\_tm1637\_stop(tm1637\_t \*tm1637);

// 读取响应
void \_\_tm1637\_ack(tm1637\_t \*tm1637);

// 发送一位数据
void \_\_tm1637\_send\_byte(tm1637\_t \*tm1637, uint8\_t byte);
// 调节亮度
void \_\_tm1637\_adjust\_brightness(tm1637\_t \*tm1637);
// 向TM1637发送数据
void \_\_tm1637\_set\_segment\_raw\_data(tm1637\_t \*tm1637, const uint8\_t segment_idx,
const uint8\_t data);
// 设置前导点
void \_\_tm1637\_set\_lead\_dot(tm1637\_t \*tm1637, const bool lead_zero);
// 查找ASCII表码
uint8\_t \_\_tm1637\_encode(uint8\_t chr);
// 查询位
uint8\_t \_\_tm1637\_digit\_map(tm1637\_t \*tm1637, uint8\_t digits, uint8\_t digit);

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
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
static inline float nearestf(float val, int precision) {
int scale = pow(10, precision);
return roundf(val \* scale) / scale;
}

// CLK引脚设置高电平
void \_\_tm1637\_clk\_high(tm1637\_t \*tm1637) {
HAL\_GPIO\_WritePin(tm1637->CLK_GPIOx, tm1637->CLK_GPIO_Pinx, GPIO_PIN_SET);
}

// CLK引脚设置低电平
void \_\_tm1637\_clk\_low(tm1637\_t \*tm1637) {
HAL\_GPIO\_WritePin(tm1637->CLK_GPIOx, tm1637->CLK_GPIO_Pinx, GPIO_PIN_RESET);
}

// DIO引脚设置高电平
void \_\_tm1637\_dio\_high(tm1637\_t \*tm1637) {
HAL\_GPIO\_WritePin(tm1637->DIO_GPIOx, tm1637->DIO_GPIO_Pinx, GPIO_PIN_SET);
}

// DIO引脚设置低电平
void \_\_tm1637\_dio\_low(tm1637\_t \*tm1637) {
HAL\_GPIO\_WritePin(tm1637->DIO_GPIOx, tm1637->DIO_GPIO_Pinx, GPIO_PIN_RESET);
}

// 将DIO设置为输入
void \_\_tm1637\_dio\_set\_input(tm1637\_t \*tm1637) {
GPIO_InitTypeDef GPIO_InitStruct = { 0 }; //To read ACK from TM1637 and to write data to it
GPIO_InitStruct.Pin = tm1637->DIO_GPIO_Pinx;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
HAL\_GPIO\_Init(tm1637->DIO_GPIOx, &GPIO_InitStruct);
}

// 将DIO设置为输出
void \_\_tm1637\_dio\_set\_output(tm1637\_t \*tm1637) {
GPIO_InitTypeDef GPIO_InitStruct = { 0 }; //To read ACK from TM1637 and to write data to it
GPIO_InitStruct.Pin = tm1637->DIO_GPIO_Pinx;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL\_GPIO\_Init(tm1637->DIO_GPIOx, &GPIO_InitStruct);
}

// TM1637固定延时3us
void \_\_tm1637\_delay() {
// \_\_tm1637\_delay\_us(TM1637\_DELAY\_US);
\_\_tm1637\_delay\_us(TM1637_DELAY_US);
}

// 发送开始信号
void \_\_tm1637\_start(tm1637\_t \*tm1637) {
\_\_tm1637\_clk\_high(tm1637);
\_\_tm1637\_dio\_high(tm1637);
\_\_tm1637\_delay\_us(2);
\_\_tm1637\_dio\_low(tm1637);
}

// 发送结束信号
void \_\_tm1637\_stop(tm1637\_t \*tm1637) {

\_\_tm1637\_clk\_low(tm1637);
\_\_tm1637\_delay\_us(2);
\_\_tm1637\_dio\_low(tm1637);
\_\_tm1637\_delay\_us(2);
\_\_tm1637\_clk\_high(tm1637);
\_\_tm1637\_delay\_us(2);
\_\_tm1637\_dio\_high(tm1637);
}

void \_\_tm1637\_ack(tm1637\_t \*tm1637) {

\_\_tm1637\_clk\_low(tm1637);
\_\_tm1637\_delay\_us(5);
\_\_tm1637\_clk\_high(tm1637);
\_\_tm1637\_delay\_us(2);
\_\_tm1637\_clk\_low(tm1637);
}

// 发送一位数据
void \_\_tm1637\_send\_byte(tm1637\_t \*tm1637, uint8\_t byte) {
uint8\_t data = byte;
for (uint8\_t i = 0; i < 8; ++i) {
\_\_tm1637\_clk\_low(tm1637);
if (data & 0x01) {
\_\_tm1637\_dio\_high(tm1637);
} else {
\_\_tm1637\_dio\_low(tm1637);
}
\_\_tm1637\_delay();
data >>= 1;
\_\_tm1637\_clk\_high(tm1637);
\_\_tm1637\_delay();
}
/\*
\* TM1637 通过在发送第 8 位后将 DIO 从 CLK 的下降沿拉低到 CLK 的下一个下降沿来发出 ACK 信号。
\* 在此期间需要将 DIO 设置为输入。
\* \*/

\_\_tm1637\_dio\_set\_input(tm1637);

// 开始ACK信号
\_\_tm1637\_clk\_low(tm1637);
\_\_tm1637\_delay();

\_\_tm1637\_clk\_high(tm1637);
\_\_tm1637\_delay();

// 结束ACK信号
\_\_tm1637\_clk\_low(tm1637);
\_\_tm1637\_delay();

\_\_tm1637\_dio\_set\_output(tm1637);
}

// 调节亮度
void \_\_tm1637\_adjust\_brightness(tm1637\_t \*tm1637) {

if (tm1637->brightness < 0) {
tm1637->brightness = 0;
} else if (tm1637->brightness > TM1637_MAX_BRIGHTNESS) {
tm1637->brightness = TM1637_MAX_BRIGHTNESS;
}

// 发送开开始信号
\_\_tm1637\_start(tm1637);

\_\_tm1637\_send\_byte(tm1637, tm1637->brightness | 0x88);

// 发送结束信号
\_\_tm1637\_stop(tm1637);
}

// 向TM1637发送数据
void \_\_tm1637\_set\_segment\_raw\_data(tm1637\_t \*tm1637, const uint8\_t segment_idx,
const uint8\_t data) {
// 发送开开始信号
\_\_tm1637\_start(tm1637);
// 选择地址
\_\_tm1637\_send\_byte(tm1637, TM1637_ADDR_FIXED);
// 发送结束信号
\_\_tm1637\_stop(tm1637);

// 发送数据
// 发送开开始信号
\_\_tm1637\_start(tm1637);
\_\_tm1637\_send\_byte(tm1637, segment_idx | 0xC0);
\_\_tm1637\_send\_byte(tm1637, data);
// 发送结束信号
\_\_tm1637\_stop(tm1637);

// 调节亮度
\_\_tm1637\_adjust\_brightness(tm1637);
}

// 设置前导点
void \_\_tm1637\_set\_lead\_dot(tm1637\_t \*tm1637, const bool lead_zero) {
tm1637\_set\_number\_lead\_dot(tm1637, lead_zero, lead_zero, 0x00);
}

// 查找ASCII表码
uint8\_t \_\_tm1637\_encode(uint8\_t chr) {
if (chr > 127 || chr < 32) {
return 0;
}
return __s_ascii[chr - 32];
}

// 查询位
uint8\_t \_\_tm1637\_digit\_map(tm1637\_t \*tm1637, uint8\_t digits, uint8\_t digit) {
uint8\_t result = digit;
if (digits == 6) {
switch (digit) {
case 0:
result = 2;
break;
case 1:
result = 1;
break;
case 2:
result = 0;
break;
case 3:
result = 5;
break;
case 4:
result = 4;
break;
case 5:
result = 3;
break;
}
}
return result;
}

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

5)驱动函数实现

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
void tm1637\_init(tm1637\_t \*tm1637) {
// dwt\_init();

\_\_tm1637\_clk\_low(tm1637);
\_\_tm1637\_delay();

\_\_tm1637\_dio\_high(tm1637);
\_\_tm1637\_delay();

\_\_tm1637\_clk\_high(tm1637);
\_\_tm1637\_delay();

\_\_tm1637\_adjust\_brightness(tm1637);

}

void tm1637\_set\_brightness(tm1637\_t \*tm1637, uint8\_t level) {
if (level < 0) {
tm1637->brightness = 0;
} else if (level > TM1637_MAX_BRIGHTNESS) {
tm1637->brightness = TM1637_MAX_BRIGHTNESS;
}
\_\_tm1637\_adjust\_brightness(tm1637);
}

void tm1637\_set\_segment\_number(tm1637\_t \*tm1637, uint8\_t segment_idx,
const uint8\_t number, const bool dot) {
uint8\_t seg_data = 0x00;

// 查询显示段符号
if (number < (sizeof(__tm1637_symbols) / sizeof(__tm1637_symbols[0]))) {
seg_data = __tm1637_symbols[number];
}

// 如果显示点
if (dot) {
seg_data |= 0x80;
}

\_\_tm1637\_set\_segment\_raw\_data(tm1637, segment_idx, seg_data);
}

void tm1637\_set\_number\_lead\_dot(tm1637\_t \*tm1637, uint16\_t number,
bool lead_zero, const uint8\_t dot_mask) {
uint8\_t lead_number = lead_zero ? 0xFF : __tm1637_symbols[0];
// 对数字进行按位分类处理
if (number < 10) {
tm1637\_set\_segment\_number(tm1637, 3, number, dot_mask & 0x01);
tm1637\_set\_segment\_number(tm1637, 2, lead_number, dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 1, lead_number, dot_mask & 0x04);
tm1637\_set\_segment\_number(tm1637, 0, lead_number, dot_mask & 0x08);
} else if (number < 100) {
tm1637\_set\_segment\_number(tm1637, 3, number % 10, dot_mask & 0x01);
tm1637\_set\_segment\_number(tm1637, 2, (number / 10) % 10,
dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 1, lead_number, dot_mask & 0x04);
tm1637\_set\_segment\_number(tm1637, 0, lead_number, dot_mask & 0x08);
} else if (number < 1000) {
tm1637\_set\_segment\_number(tm1637, 3, number % 10, dot_mask & 0x01);
tm1637\_set\_segment\_number(tm1637, 2, (number / 10) % 10,
dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 1, (number / 100) % 10,
dot_mask & 0x04);
tm1637\_set\_segment\_number(tm1637, 0, lead_number, dot_mask & 0x08);
} else {
tm1637\_set\_segment\_number(tm1637, 3, number % 10, dot_mask & 0x01);
tm1637\_set\_segment\_number(tm1637, 2, (number / 10) % 10,
dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 1, (number / 100) % 10,
dot_mask & 0x04);
tm1637\_set\_segment\_number(tm1637, 0, (number / 1000) % 10,
dot_mask & 0x08);
}
}

void tm1637\_display\_temperature(tm1637\_t \*tm1637, int16\_t temperature) {
int16\_t number = temperature;
if (number < -100) {
number = -99;
} else if (number > 999) {
number = 999;
}

uint8\_t lead_number = __tm1637_symbols[0];
uint8\_t dot_mask = 0x00;

// 显示度数符号
\_\_tm1637\_set\_segment\_raw\_data(tm1637, 3, TM_DEG);

if (number >= 0) {
if (number < 10) {
tm1637\_set\_segment\_number(tm1637, 2, number, dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 1, lead_number, dot_mask & 0x04);
tm1637\_set\_segment\_number(tm1637, 0, lead_number, dot_mask & 0x08);
} else if (number < 100) {
tm1637\_set\_segment\_number(tm1637, 2, number % 10, dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 1, (number / 10) % 10,
dot_mask & 0x04);
tm1637\_set\_segment\_number(tm1637, 0, lead_number, dot_mask & 0x08);
} else if (number < 1000) {
tm1637\_set\_segment\_number(tm1637, 2, number % 10, dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 1, (number / 10) % 10,
dot_mask & 0x04);
tm1637\_set\_segment\_number(tm1637, 0, (number / 100) % 10,
dot_mask & 0x08);
}
} else {
number = -1 \* number;
if (number < 10) {
// 显示负号
tm1637\_set\_segment\_number(tm1637, 1, MINUS_SIGN_IDX, 0x00);

tm1637\_set\_segment\_number(tm1637, 2, number, dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 0, lead_number, dot_mask & 0x80);
} else if (number < 100) {
// 显示负号
tm1637\_set\_segment\_number(tm1637, 0, MINUS_SIGN_IDX, 0x00);
tm1637\_set\_segment\_number(tm1637, 2, number % 10, dot_mask & 0x02);
tm1637\_set\_segment\_number(tm1637, 1, (number / 10) % 10,
dot_mask & 0x04);
}
}
}

void tm1637\_display\_float(tm1637\_t \*tm1637, float value) {
if (value < 0) {
tm1637\_set\_segment\_number(tm1637, 0, MINUS_SIGN_IDX, 0x00);
// 计算整数部分与小数部分
float absn = nearestf(fabs(value), 1);
int int_part = (int) absn;
int fx_part = absn - int_part;
if (absn < 10) {
tm1637\_set\_segment\_number(tm1637, 1, (int) (absn + 0.5), 0x01);
tm1637\_set\_segment\_number(tm1637, 2, (int) ((fx_part / 10) % 10),
0x00);
tm1637\_set\_segment\_number(tm1637, 3, (int) (fx_part % 10), 0x00);
} else if (absn < 100) {
fx_part \*= 100;
uint8\_t f = fx_part % 10;
tm1637\_set\_segment\_number(tm1637, 1, (int_part / 10) % 10, 0x00);
tm1637\_set\_segment\_number(tm1637, 2, int_part % 10, 0x01);
tm1637\_set\_segment\_number(tm1637, 3,
((int) fx_part / 10) % 10 + ((f > 4) ? 1 : 0), 0x00);
} else if (absn < 1000) {
tm1637\_set\_segment\_number(tm1637, 1, (int_part / 100) % 10, 0x01);
tm1637\_set\_segment\_number(tm1637, 2, (int_part / 10) % 10, 0x00);
tm1637\_set\_segment\_number(tm1637, 3,
int_part % 10 + ((fx_part >= 0.5) ? 1 : 0), 0x00);
}
} else {
int int_part = (int) value;
float fx_part = value - int_part;
if (value < 10) {
float n = nearestf(value, 1);
int_part = (int) n;
fx_part = 10000 \* (n - int_part);
tm1637\_set\_segment\_number(tm1637, 0, int_part, 0x01);
tm1637\_set\_segment\_number(tm1637, 1, ((int) fx_part / 1000) % 10,
0x00);
tm1637\_set\_segment\_number(tm1637, 2, ((int) fx_part / 100) % 10,
0x00);
tm1637\_set\_segment\_number(tm1637, 3, ((int) fx_part / 10) % 10,
0x00);
} else if (value < 100) {
float n = nearestf(value, 2);
int_part = (int) n;
fx_part = 1000 \* (n - int_part);
tm1637\_set\_segment\_number(tm1637, 0, (int_part / 10) % 10, 0x00);
tm1637\_set\_segment\_number(tm1637, 1, int_part % 10, 0x01);
tm1637\_set\_segment\_number(tm1637, 2, ((int) fx_part / 100) % 10,
0x00);
tm1637\_set\_segment\_number(tm1637, 3, ((int) fx_part / 10) % 10,
0x00);
} else if (value < 1000) {
float n = nearestf(value, 2);
int_part = (int) n;
fx_part = 100 \* (n - int_part);

tm1637\_set\_segment\_number(tm1637, 0, (int_part / 100) % 10, 0x00);
tm1637\_set\_segment\_number(tm1637, 1, (int_part / 10) % 10, 0x01);
tm1637\_set\_segment\_number(tm1637, 2, int_part % 10, 0x01);
tm1637\_set\_segment\_number(tm1637, 3, ((int) fx_part / 10) % 10,
0x00);
}
}
}

void tm1637\_display\_string(tm1637\_t \*tm1637, const int8\_t \*data) {
\_\_tm1637\_start(tm1637);
\_\_tm1637\_send\_byte(tm1637, 0x40);
\_\_tm1637\_stop(tm1637);

for (size\_t i = 0; i < 4; i++) {
\_\_tm1637\_start(tm1637);
\_\_tm1637\_send\_byte(tm1637, \_\_tm1637\_digit\_map(tm1637, 4, i) | 0xC0);
\_\_tm1637\_send\_byte(tm1637, \_\_tm1637\_encode(data[i]));
\_\_tm1637\_stop(tm1637);
}

\_\_tm1637\_adjust\_brightness(tm1637);
}

void tm1637\_clear(tm1637\_t \*tm1637) {
uint8\_t i;
for (i = 0; i < 4; i++)
tm1637\_set\_segment\_number(tm1637, i, 0x7f, 0x00);
}

void tm1637\_display\_number(tm1637\_t \*tm1637, int16\_t number) {
tm1637\_set\_number\_lead\_dot(tm1637, number, false, 0x00);
}

void tm1637\_display\_time(tm1637\_t \*tm1637, uint8\_t hours, uint8\_t minutes,
bool dot_blink) {
uint8\_t _hours = hours;
uint8\_t _minutes = minutes;
uint8\_t time[4] = { 0, 0, 0, 0 };
if (_hours > 23 || _minutes > 59) { // 无效时间
return;
}
time[0] = _hours / 10;
time[1] = _hours % 10;
time[2] = minutes / 10;
time[3] = minutes % 10;

tm1637\_set\_segment\_number(tm1637, 0, time[0], tm1637->dot_blink_state);
tm1637\_set\_segment\_number(tm1637, 1, time[1], tm1637->dot_blink_state);
tm1637\_set\_segment\_number(tm1637, 2, time[2], tm1637->dot_blink_state);
tm1637\_set\_segment\_number(tm1637, 3, time[3], tm1637->dot_blink_state);
tm1637->dot_blink_state = !tm1637->dot_blink_state;
}

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include <stdio.h>
#include "tm1637\_simple/tm1637\_simple.h"
/\* USER CODE END Includes \*/

/\* USER CODE BEGIN PV \*/
tm1637\_t tm1637;
/\* 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 \*/
tm1637.CLK_GPIO_Pinx = TM1637_CLK_Pin;
tm1637.CLK_GPIOx = TM1637_CLK_GPIO_Port;
tm1637.DIO_GPIO_Pinx = TM1637_DIO_Pin;
tm1637.DIO_GPIOx = TM1637_DIO_GPIO_Port;
tm1637.brightness = 1;
tm1637.digital_bits = 4;
tm1637.id = 1;

//
tm1637\_init(&tm1637);
// tm1637\_init(&tm1637,TM1637\_CLK\_GPIO\_Port,TM1637\_CLK\_Pin,TM1637\_DIO\_GPIO\_Port,TM1637\_DIO\_Pin);
printf("\*\*\*\*STM32CubeIDE:TM1637(4Bits)\*\*\*\*\r\n");
tm1637\_display\_string(&tm1637, (const int8\_t\*) "HELL");
HAL\_Delay(1000);
tm1637\_clear(&tm1637);
tm1637\_display\_number(&tm1637, 1234);
HAL\_Delay(1000);
tm1637\_clear(&tm1637);
tm1637\_display\_float(&tm1637, 123.4);
HAL\_Delay(1000);
tm1637\_clear(&tm1637);
tm1637\_display\_temperature(&tm1637, 123);
HAL\_Delay(1000);

/\* USER CODE END 2 \*/

/\* Infinite loop \*/
/\* USER CODE BEGIN WHILE \*/
uint8\_t hour = 0, minute = 0, second = 0;
tm1637.dot_blink_state = false;
while (1) {
/\* USER CODE END WHILE \*/

/\* USER CODE BEGIN 3 \*/

tm1637\_display\_time(&tm1637, hour, minute,true);
if (second == 59) {
second = 0;
minute++;
}
if (minute == 59) {
hour++;
minute = 0;
}
if (hour >= 24) {
hour = 0;
}
second++;
HAL\_Delay(1000);
}
/\* USER CODE END 3 \*/
}


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