VFD屏幕驱动

文章目录
  1. 1. VFD介绍
  2. 2. VFD代码部分
    1. 2.1. 屏幕相关
      1. 2.1.1. SPI通信规格
      2. 2.1.2. 内置字库
      3. 2.1.3. 自定义字模
    2. 2.2. 单片机部分
      1. 2.2.1. 主菜单
      2. 2.2.2. 动画实现
      3. 2.2.3. 按键读取逻辑
      4. 2.2.4. main.c代码
    3. 2.3. 写在最后

VFD介绍

VFD(Vacuum Fluorescent Display)真空荧光显示器件,一种低能电子发光显示器件,工作原理与CRT类似,主要特点是亮度高与无需背光照明,并且工作电压比较低,主要是很帅。

本文中作者使用的VFD屏幕型号为:8-MD-06INKM

在某宝上购入时已经包含了屏幕驱动模块因此只需要使用SPI协议并且提供5V直流电即可驱动了。

VFD屏幕模块

屏幕模块背后有7个接口从上到下分别是

  1. DIN
  2. CLK
  3. CS
  4. RESET
  5. EN
  6. VCC_5V
  7. GND

前三个接口为SPI通信接口,RESET为低电平重置,一般接高电平即可,EN为使能,高电平即开启屏幕,后两个接口为电源正与接地。

VFD代码部分

屏幕相关

SPI通信规格

串口波特率 9600
停止位 1
无校验
数据长度 12
数据结构 帧头+显示数据+显示亮度+帧尾

内置字库

帧头 FE 49 hex
显示数据 字符 ASCII
显示亮度 01-255 hex
帧尾 1 hex

例如:FE 49 30 31 32 33 34 35 36 37 F0 01

内置字库表

自定义字模

帧头 FE 50 hex
显示位置 0-7 hex
显示字模 字模数据 hex
显示亮度 01-255 hex
帧尾 1 hex

例如:FE50 00 02 05 32 48 48 00 00 F0 01

自定义字符规则

取字模网站

大小选择8行5列,列顺序,小段,每列对齐,最底下一行必须留空,或者干脆用7行5列。

单片机部分

本文中使用的单片机型号为STM32F103C8T6

代码整体上是个前后台系统,通过按键触发中断来实现屏幕切换,时间设定,亮度设定等操作,并通过外部中断来触发定时器中断来判断长按与短按。主菜单通过一大堆神秘的Switch函数来跳转到一个个功能当中。
大概这样子

其实菜单界面早就改了几次了但是我的ST-link丢失了暂时无法确认

主菜单

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
// 系统菜单界面
switch (Key_Flag)
{
case 0: VFD_Show_Time_0(); break;
case 1: VFD_Show_Time_Line_1(); break;
case 2: VFD_Show_Year_2(); break;
case 3: VFD_Show_Mon_3(); break;
case 4: VFD_Show_Day_4(); break;
case 5: VFD_Show_Set_Time_5(); break;
case 6: VFD_Show_Set_Time_Hour_6(); break;
case 7: VFD_Show_Set_Time_Min_7(); break;
case 8: VFD_Show_Set_Time_Sec_8(); break;
case 9: VFD_Show_Set_Date_9(); break;
case 10: VFD_Show_Set_Date_Year_10(); break;
case 11: VFD_Show_Set_Date_Mon_11(); break;
case 12: VFD_Show_Set_Date_Day_12(); break;
case 13: VFD_System_Set_13(); break;
case 14: VFD_System_Set_14(); break;
case 15: VFD_System_Set_Brightness_15(); break;
case 16: VFD_System_Set_Sleep_Time_16(); break;
case 17: VFD_System_Set_17(); break;
case 18: VFD_System_Set_Show_Speed_18(); break;

default : VFD_Show_Time_0();Key_Flag = 0;break;
}

动画实现

动画的实现用了一种很神秘的办法,说实话我现在已经看不太懂了,之前的我真是天才(雾),大致上就是输入两个代表你想显示的数字的数组,然后将其分别切为一大一小两部分,再将不同的大与小部分拼接起来合成一个新数组来显示,从而实现数字的交换,具体效果可以查看BV1WGCBYhEem

顺带一提

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
/**
* @brief 从上向下滑动
* @param position -- 要改变的位置
* @param char_1 -- 一开始显示的字符
* @param char_2 -- 改变后显示的字符
* @param delay_time -- 动画速度,此数值越大动画越慢
* @param ram -- 缓存地址选择,一般和position相同即可
* @retval None
*/
void change_char(uint8_t position, uint8_t char_1, uint8_t char_2, uint8_t delay_time, uint8_t ram)
{
uint8_t s_temp;
uint8_t s_temp_1[5];
uint8_t s_temp_2[5];

for (uint8_t i = 0; i < 5; i++)
{
s_temp_1[i] = custom_h_num[char_1][i];
s_temp_2[i] = custom_h_num[char_2][i];
}

for (uint8_t n = 0; n < 8; n++)
{
for (uint8_t i = 0; i < 5; i++)
{
s_temp_1[i] <<= 0x01;

s_temp = s_temp_2[i];

s_temp &= 0x80;
s_temp >>= 7;

s_temp_1[i] |= s_temp;

s_temp_2[i] = (s_temp_2[i] >> 7 | (s_temp_2[i] << 1 ));

vfd_wtire_custom_char(ram, s_temp_1);
vfd_display_char(position, ram);

}
delay_ms(delay_time);
}
}

按键读取逻辑

大概思路就是使用TIM计时器通过设置psc与arr来将TIM计时器溢出一次的时间设置为一个比较短的时间,我使用的是0.01s,也即是72M/72100010=100hz72M/72*1000*10 = 100hz当按键被按下时触发外部中断进入外部中断函数,在外部中断中先清空然后启动TIM计时器,计时器开始计数并且每0.01s溢出1次并进入计时器溢出中断给标志位加1,此时通过判断计时器溢出标志位的大小即可实现长按与短按的区分,并且可以设置短按的下限以调整按键的死区,最后关闭计时器并清除中断标志。

上面的一堆中断代码其实存在一个十分神秘的bug,即有时候删掉bsp_tim.h中的位带操作之后会导致按键失效,可是我明明就没有在中断函数中使用这个!

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
...
TIM2_IC_Init(72, 1000*10);
TIM3_IC_Init(72, 1000*10);
...

/**
* @brief TIM3中断服务函数。
* @param None
* @retval None
*/
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update)) {
if((Tim3_cnt++ >= 100) && KEY1_STATE()) {
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); // 关闭定时器计数
if (Key_long_flag_2)
Key_long_flag_2 = 0;
else
Key_long_flag_2 = 1;
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
/**
* @brief KEY1中断服务函数。
* @param None
* @retval None
*/
void KEY1_EXTIn_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1) != RESET) {
if(KEY1_STATE()) {
Tim3_cnt = 0; // 清空tim3计算器
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 开启定时器计数
}
else if((Tim3_cnt++ < 100 && Tim3_cnt > 4) && !KEY1_STATE())
{
Tim3_cnt = 0; // 清空tim3计算器
if (Key_short_flag_2)
Key_short_flag_2 = 0;
else
Key_short_flag_2 = 1;
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); // 关闭定时器计数
}
EXTI_ClearITPendingBit(EXTI_Line1); // 清除中断标志
}
}
/**
* @brief TIM2中断服务函数。
* @param None
* @retval None
*/
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update)) {
if((Tim2_cnt++ >= 100) && KEY0_STATE()) {
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); // 关闭定时器计数
if (Key_long_flag_1)
Key_long_flag_1 = 0;
else
Key_long_flag_1 = 1;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
/**
* @brief KEY0中断服务函数。
* @param None
* @retval None
*/
void KEY0_EXTIn_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
if(KEY0_STATE()) {
Tim2_cnt = 0; // 清空tim2计算器
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 开启定时器计数
}
else if((Tim2_cnt++ < 100 && Tim2_cnt > 4) && !KEY0_STATE())
{
Tim2_cnt = 0; // 清空tim2计算器
if (Key_short_flag_1)
Key_short_flag_1 = 0;
else
Key_short_flag_1 = 1;
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); // 关闭定时器计数
}
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志
}
}

bsp_tim.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
#include "bsp_tim.h"

//extern uint8_t KEY_flag;

/**
* @brief tim2输入捕获初始化
* @param psc -- 预分频值
* @param arr -- 自动重装载值
* @retval None
*/
void TIM2_IC_Init(uint32_t psc, uint32_t arr)
{
TIM_TimeBaseInitTypeDef tim2_init_struct;
NVIC_InitTypeDef NVIC_init_struct;

// 1、开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

// 3、tim2时基初始化
tim2_init_struct.TIM_ClockDivision = TIM_CKD_DIV1; //不分频
tim2_init_struct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
tim2_init_struct.TIM_Prescaler = psc - 1; //预分频值
tim2_init_struct.TIM_Period = arr - 1; //自动重装置值
tim2_init_struct.TIM_RepetitionCounter = 0; //重复计数器; 高级定时器才使用
TIM_TimeBaseInit(TIM2, &tim2_init_struct);

// 4、tim2选择内部时钟
TIM_InternalClockConfig(TIM2);

// 6、选择触发源及从模式
TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);//触发源TI1FP1
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);//从模式复位

// 7、tim2中断配置
TIM_ITConfig(TIM2, TIM_IT_Trigger, ENABLE);

// 8、tim2设置中断优先级
NVIC_init_struct.NVIC_IRQChannel = TIM2_IRQn;
NVIC_init_struct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_init_struct.NVIC_IRQChannelSubPriority = 0;
NVIC_init_struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_init_struct);

// 9、启动tim2
TIM_Cmd(TIM2, ENABLE);
}

/**
* @brief TIM3输入捕获初始化
* @param psc -- 预分频值
* @param arr -- 自动重装载值
* @retval None
*/
void TIM3_IC_Init(uint32_t psc, uint32_t arr)
{
TIM_TimeBaseInitTypeDef TIM3_init_struct;
NVIC_InitTypeDef NVIC_init_struct;

// 1、开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

// 3、TIM3时基初始化
TIM3_init_struct.TIM_ClockDivision = TIM_CKD_DIV1; //不分频
TIM3_init_struct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM3_init_struct.TIM_Prescaler = psc - 1; //预分频值
TIM3_init_struct.TIM_Period = arr - 1; //自动重装置值
TIM3_init_struct.TIM_RepetitionCounter = 0; //重复计数器; 高级定时器才使用
TIM_TimeBaseInit(TIM3, &TIM3_init_struct);

// 4、TIM3选择内部时钟
TIM_InternalClockConfig(TIM3);

// 6、选择触发源及从模式
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//触发源TI1FP1
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//从模式复位

// 7、TIM3中断配置
TIM_ITConfig(TIM3, TIM_IT_Trigger, ENABLE);

// 8、TIM3设置中断优先级
NVIC_init_struct.NVIC_IRQChannel = TIM3_IRQn;
NVIC_init_struct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_init_struct.NVIC_IRQChannelSubPriority = 0;
NVIC_init_struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_init_struct);

// 9、启动TIM3
TIM_Cmd(TIM3, ENABLE);

}

bsp_tim.h

1
2
3
4
5
#define KEY0_STATE()		PBin(0)
#define KEY1_STATE() PBin(1)

void TIM2_IC_Init(uint32_t psc, uint32_t arr);
void TIM3_IC_Init(uint32_t psc, uint32_t arr);

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
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "VFD.h"
#include "MyRTC.h"
#include "bsp_tim.h"
#include "Key.h"
#include <time.h>

uint16_t FLASH_TIME = 50; // 动画速度

uint8_t Ramdom_Time_Set = 1; // 随机时间选择
uint16_t MyRTC_Time[] = {2024, 12, 26, 11, 42, 10}; //定义全局的时间数组,数组内容分别为年、月、日、时、分、秒
uint8_t num_zero[] = {0x3e,0x51,0x49,0x45,0x3e}; //0

uint16_t TIme_seed = 0;
uint8_t char_t[10] = {'0','1','2','3','4','5','6','7','8','9'};

uint16_t Bright_Set_Num = 10;
uint16_t System_Sleep_Time= 1;

uint16_t Tim2_cnt = 0;
uint16_t Tim3_cnt = 0;

uint16_t Key_Flag = 0;
uint8_t Key_long_flag_1 = 0;
uint8_t Key_short_flag_1 = 0;

uint8_t Key_long_flag_2 = 0;
uint8_t Key_short_flag_2 = 0;

uint8_t s = 0;
uint8_t sd = 0;
uint8_t m = 0;
uint8_t md = 0;
uint8_t h = 0;
uint8_t hd = 0;

time_t sleep_cnt_h = 0;
time_t sleep_cnt_t = 0;

uint8_t temp = 0;

void BKP_Init(void);

void VFD_Show_Time_0(void);
void VFD_Show_Time_Line_1(void);
void VFD_Show_Began(void);
void VFD_Show_Year_2(void);
void VFD_Show_Mon_3(void);
void VFD_Show_Day_4(void);
void VFD_Show_Set_Time_5(void);
void VFD_Show_Set_Time_Hour_6(void);
void VFD_Show_Set_Time_Min_7(void);
void VFD_Show_Set_Time_Sec_8(void);
void VFD_Show_Set_Date_9(void);
void VFD_Show_Set_Date_Year_10(void);
void VFD_Show_Set_Date_Mon_11(void);
void VFD_Show_Set_Date_Day_12(void);
void VFD_System_Set_13(void);
void VFD_System_Set_14(void);
void VFD_System_Set_17(void);
void VFD_System_Set_Brightness_15(void);
void VFD_System_Set_Sleep_Time_16(void);
void VFD_System_Set_Show_Speed_18(void);

int main(void)
{
delay_init(72);
vfd_init();
MyRTC_Init();
KEY_Init();

TIM2_IC_Init(72, 1000*10);
TIM3_IC_Init(72, 1000*10);

VFD_Show_Began();

MyRTC_ReadTime();
sleep_cnt_t = RTC_GetCounter() + 8 * 60 * 60;

BKP_Init();

while(1)
{
// 按键扫描
if (Key_long_flag_1)
{
sleep_cnt_h = RTC_GetCounter() + 8 * 60 * 60;

switch (Key_Flag)
{
case 0:
case 1:
case 2:
case 3:
case 4: Key_Flag = 5; break;

case 5: Key_Flag = 6; break;
case 6: Key_Flag = 7; break;
case 7: Key_Flag = 8; break;
case 8: Key_Flag = 5; MyRTC_SetTime(); break;

case 9: Key_Flag = 10; break;
case 10: Key_Flag = 11; break;
case 11: Key_Flag = 12; break;
case 12: Key_Flag = 9; MyRTC_SetTime(); break;

case 13: Key_Flag = 15; break;
case 14: Key_Flag = 16; break;

case 15: Key_Flag = 13; break;
case 16: Key_Flag = 14; break;

case 17: Key_Flag = 18; break;
case 18: Key_Flag = 17; break;
default : break;
}
Key_long_flag_1 = 0;
}

else if (Key_short_flag_1)
{
sleep_cnt_t = RTC_GetCounter() + 8 * 60 * 60;
switch (Key_Flag)
{
case 0: Key_Flag = 1; break;
case 1: Key_Flag = 2; break;
case 2: Key_Flag = 3; break;
case 3: Key_Flag = 4; break;
case 4: Key_Flag = 0; break;

case 6: if (MyRTC_Time[3]++ < 23) {}
else {MyRTC_Time[3] = 0;} break;
case 7: if (MyRTC_Time[4]++ < 59) {}
else {MyRTC_Time[4] = 0;} break;
case 8: if (MyRTC_Time[5]++ < 59) {}
else {MyRTC_Time[5] = 0;} break;

case 5: Key_Flag = 9; break;
case 9: Key_Flag = 13; break;
case 13: Key_Flag = 14; break;
case 14: Key_Flag = 17; break;
case 17: Key_Flag = 5; break;

case 15: if (Bright_Set_Num++ < 10) {}
else {Bright_Set_Num = 1;} break;

case 16: if (System_Sleep_Time++ < 10) {}
else {System_Sleep_Time = 0;}break;

case 10: if (MyRTC_Time[0]++ < 2050) {}
else {MyRTC_Time[0] = 2000;} break;
case 11: if (MyRTC_Time[1]++ < 12) {}
else {MyRTC_Time[1] = 1;} break;
case 12: if (MyRTC_Time[2]++ < 31) {}
else {MyRTC_Time[2] = 1;} break;

case 18: if (FLASH_TIME == 50) {FLASH_TIME = 5;}
else {FLASH_TIME = 50;} break;

default : break;
}
Key_short_flag_1 = 0;
}

if (Key_long_flag_2)
{
sleep_cnt_t = RTC_GetCounter() + 8 * 60 * 60;
switch (Key_Flag)
{
case 0:
case 1:
case 2:
case 3:
case 4: Key_Flag = 0; break;
case 5: Key_Flag = 0; break;
case 6: Key_Flag = 5; break;
case 7: Key_Flag = 6; break;
case 8: Key_Flag = 7; break;
case 9: Key_Flag = 0; break;
case 10: Key_Flag = 9; break;
case 11: Key_Flag = 10; break;
case 12: Key_Flag = 11; break;
case 13: Key_Flag = 0; break;
case 14: Key_Flag = 0; break;
case 15: Key_Flag = 13; break;
case 16: Key_Flag = 14; break;
case 17: Key_Flag = 0; break;
case 18: Key_Flag = 17; break;
default : break;
}
Key_long_flag_2 = 0;
}

else if (Key_short_flag_2)
{
sleep_cnt_t = RTC_GetCounter() + 8 * 60 * 60;
switch (Key_Flag)
{
case 0: Key_Flag = 4; break;
case 1: Key_Flag = 0; break;
case 2: Key_Flag = 1; break;
case 3: Key_Flag = 2; break;
case 4: Key_Flag = 3; break;

case 6: if (MyRTC_Time[3]-- > 0) {}
else {MyRTC_Time[3] = 23;} break;
case 7: if (MyRTC_Time[4]-- > 0) {}
else {MyRTC_Time[4] = 59;} break;
case 8: if (MyRTC_Time[5]-- > 0) {}
else {MyRTC_Time[5] = 59;} break;

case 5: Key_Flag = 17; break;
case 9: Key_Flag = 5; break;
case 13: Key_Flag = 9; break;
case 14: Key_Flag = 13; break;
case 17: Key_Flag = 14; break;

case 15: if (Bright_Set_Num-- > 1) {}
else {Bright_Set_Num = 10;} break;
case 16: if (System_Sleep_Time-- > 0) {}
else {System_Sleep_Time = 10;}break;

case 10: if (MyRTC_Time[0]-- > 2000) {}
else {MyRTC_Time[0] = 2050;} break;
case 11: if (MyRTC_Time[1]-- > 1) {}
else {MyRTC_Time[1] = 12;} break;
case 12: if (MyRTC_Time[2]-- > 1) {}
else {MyRTC_Time[2] = 31;} break;

case 18: if (FLASH_TIME == 50) {FLASH_TIME = 5;}
else {FLASH_TIME = 50;} break;

default : break;
}
Key_short_flag_2 = 0;
}

if (Key_Flag > 50)
{
Key_Flag = 0;
}

// 系统菜单界面
switch (Key_Flag)
{
case 0: VFD_Show_Time_0(); break;
case 1: VFD_Show_Time_Line_1(); break;
case 2: VFD_Show_Year_2(); break;
case 3: VFD_Show_Mon_3(); break;
case 4: VFD_Show_Day_4(); break;
case 5: VFD_Show_Set_Time_5(); break;
case 6: VFD_Show_Set_Time_Hour_6(); break;
case 7: VFD_Show_Set_Time_Min_7(); break;
case 8: VFD_Show_Set_Time_Sec_8(); break;
case 9: VFD_Show_Set_Date_9(); break;
case 10: VFD_Show_Set_Date_Year_10(); break;
case 11: VFD_Show_Set_Date_Mon_11(); break;
case 12: VFD_Show_Set_Date_Day_12(); break;
case 13: VFD_System_Set_13(); break;
case 14: VFD_System_Set_14(); break;
case 15: VFD_System_Set_Brightness_15(); break;
case 16: VFD_System_Set_Sleep_Time_16(); break;
case 17: VFD_System_Set_17(); break;
case 18: VFD_System_Set_Show_Speed_18(); break;

default : VFD_Show_Time_0();Key_Flag = 0;break;
}

// 定时熄屏
sleep_cnt_h = RTC_GetCounter() + 8 * 60 * 60;
if (System_Sleep_Time)
{
if (sleep_cnt_h >= sleep_cnt_t)
{
if (sleep_cnt_h - sleep_cnt_t >= System_Sleep_Time*60)
{
vfd_display_pow_set(1);
}
else
{
vfd_display_pow_set(0);
}
}
else
{
if (sleep_cnt_h - sleep_cnt_t + 60 >= System_Sleep_Time*60)
{
vfd_display_pow_set(1);
}
else
{
vfd_display_pow_set(0);
}
}
}

}
}

/**
* @brief 初始化显示内存。
* @param None
* @retval None
*/
void VFD_Show_Began(void)
{
vfd_wtire_custom_char(0,num_zero);
vfd_wtire_custom_char(1,num_zero);

vfd_display_char(2,0x3a); // 冒号

vfd_wtire_custom_char(3,num_zero);
vfd_wtire_custom_char(4,num_zero);

vfd_display_char(5,0x3a);

vfd_wtire_custom_char(6,num_zero);
vfd_wtire_custom_char(7,num_zero);
}

/**
* @brief 带动画的时间显示,调用RTC时间
* @param None
* @retval None
*/
void VFD_Show_Time_0(void)
{
RTC_WaitForSynchro(); //等待同步
RTC_WaitForLastTask(); //等待上一次操作完成

// 读取时间
MyRTC_ReadTime();
s = MyRTC_Time[5];
m = MyRTC_Time[4];
h = MyRTC_Time[3];

// 刷新屏幕防止信号干扰
if (h/10 == 0)
vfd_display_char(0,'0');
else
vfd_display_char(0,0);

vfd_display_char(1,1);
vfd_display_char(2,0x3a);
if (m/10 == 0)
vfd_display_char(3,'0');
else
vfd_display_char(3,3);

vfd_display_char(4,4);
vfd_display_char(5,0x3a);
if (s/10 == 0)
vfd_display_char(6,'0');
else
vfd_display_char(6,6);

vfd_display_char(7,7);

// 更新秒个位
if (sd%10 != 9 && sd%10 != s%10)
{
change_char(7, sd%10, s%10, FLASH_TIME, 7);
}

// 更新秒十位
if (sd/10 != s/10)
{
change_two_char(6,7,sd/10,s/10,sd%10,s%10,FLASH_TIME,6,7);
}

// 更新分个位
if (md%10 != 9 && md%10 != m%10)
{
change_char(4,md%10,m%10,FLASH_TIME,4);
}

// 更新分十位
if (md/10 != m/10)
{
change_two_char(3,4,md/10,m/10,md%10,m%10,FLASH_TIME,3,4);
}

// 更新时个位
if (hd%10 != 3 && hd%10 != h%10)
{
change_char(1,hd%10,h%10,FLASH_TIME,1);
}

// 更新时十位
if (hd/10 != h/10)
{
change_two_char(0,1,(hd - 1)/10,h/10,hd%10,h%10,FLASH_TIME,0,1);
}

sd = s;
md = m;
hd = h;
if(TIme_seed < 30)
TIme_seed = s + m%10 + h%5;
else
TIme_seed = 0;
}

void VFD_Show_Year_2(void)
{
// RTC_WaitForLastTask();
//
// MyRTC_SetTime();

vfd_display_char(0,'Y');
vfd_display_char(1,'E');
vfd_display_char(2,'A');
vfd_display_char(3,'R');
vfd_display_char(4, MyRTC_Time[0]/1000+48);
vfd_display_char(5,(MyRTC_Time[0]%1000)/100+48);
vfd_display_char(6,(MyRTC_Time[0]%100)/10+48);
vfd_display_char(7,(MyRTC_Time[0]%10)+48);
}

void VFD_Show_Mon_3(void)
{
vfd_display_char(0,'M');
vfd_display_char(1,'O');
vfd_display_char(2,'N');
vfd_display_char(3,'T');
vfd_display_char(4,'H');
vfd_display_char(5,0x3a);
vfd_display_char(6,(MyRTC_Time[1]%100)/10+48);
vfd_display_char(7,(MyRTC_Time[1]%10)+48);
}

void VFD_Show_Day_4(void)
{
vfd_display_char(0,'D');
vfd_display_char(1,'A');
vfd_display_char(2,'Y');
vfd_display_char(3,0x3a);
vfd_display_char(4,(MyRTC_Time[2]%100)/10+48);
vfd_display_char(5,(MyRTC_Time[2]%10)+48);
vfd_display_char(6,0x1c);
vfd_display_char(7,0x1c);
}

void VFD_Show_Set_Time_5(void)
{
vfd_display_char(0,'S');
vfd_display_char(1,'E');
vfd_display_char(2,'T');
vfd_display_char(3,0x1b);
vfd_display_char(4,'T');
vfd_display_char(5,'I');
vfd_display_char(6,'M');
vfd_display_char(7,'E');
}
void VFD_Show_Set_Time_Hour_6(void)
{
vfd_display_char(0,'H');
vfd_display_char(1,'o');
vfd_display_char(2,'u');
vfd_display_char(3,'r');
vfd_display_char(4,0x3a);
vfd_display_char(5,MyRTC_Time[3]/10+48);
vfd_display_char(6,MyRTC_Time[3]%10+48);
vfd_display_char(7,0x10);
}
void VFD_Show_Set_Time_Min_7(void)
{
vfd_display_char(0,'M');
vfd_display_char(1,'i');
vfd_display_char(2,'n');
vfd_display_char(3,0x3a);
vfd_display_char(4,MyRTC_Time[4]/10+48);
vfd_display_char(5,MyRTC_Time[4]%10+48);
vfd_display_char(6,0x10);
vfd_display_char(7,0x10);
}
void VFD_Show_Set_Time_Sec_8(void)
{
vfd_display_char(0,'S');
vfd_display_char(1,'e');
vfd_display_char(2,'c');
vfd_display_char(3,0x3a);
vfd_display_char(4,MyRTC_Time[5]/10+48);
vfd_display_char(5,MyRTC_Time[5]%10+48);
vfd_display_char(6,0x10);
vfd_display_char(7,0x10);
}
void VFD_Show_Set_Date_9(void)
{
vfd_display_char(0,'S');
vfd_display_char(1,'E');
vfd_display_char(2,'T');
vfd_display_char(3,0x1b);
vfd_display_char(4,'D');
vfd_display_char(5,'A');
vfd_display_char(6,'T');
vfd_display_char(7,'E');
}
void VFD_Show_Set_Date_Year_10(void)
{
vfd_display_char(0,'Y');
vfd_display_char(1,'E');
vfd_display_char(2,'A');
vfd_display_char(3,'R');
vfd_display_char(4, MyRTC_Time[0]/1000+48);
vfd_display_char(5,(MyRTC_Time[0]%1000)/100+48);
vfd_display_char(6,(MyRTC_Time[0]%100)/10+48);
vfd_display_char(7,(MyRTC_Time[0]%10)+48);
}
void VFD_Show_Set_Date_Mon_11(void)
{
vfd_display_char(0,'M');
vfd_display_char(1,'o');
vfd_display_char(2,'n');
vfd_display_char(3,0x3a);
vfd_display_char(4,MyRTC_Time[1]/10+48);
vfd_display_char(5,MyRTC_Time[1]%10+48);
vfd_display_char(6,0x10);
vfd_display_char(7,0x10);
}
void VFD_Show_Set_Date_Day_12(void)
{
vfd_display_char(0,'D');
vfd_display_char(1,'a');
vfd_display_char(2,'y');
vfd_display_char(3,0x3a);
vfd_display_char(4,MyRTC_Time[2]/10+48);
vfd_display_char(5,MyRTC_Time[2]%10+48);
vfd_display_char(6,0x10);
vfd_display_char(7,0x10);
}

void VFD_System_Set_13(void)
{
vfd_display_char(0,'S');
vfd_display_char(1,'E');
vfd_display_char(2,'T');
vfd_display_char(3,0x1b);
vfd_display_char(4,'L');
vfd_display_char(5,'I');
vfd_display_char(6,'G');
vfd_display_char(7,'H');

vfd_display_brightness(Bright_Set_Num);
}
void VFD_System_Set_14(void)
{
vfd_display_char(0,'S');
vfd_display_char(1,'E');
vfd_display_char(2,'T');
vfd_display_char(3,0x1b);
vfd_display_char(4,'S');
vfd_display_char(5,'T');
vfd_display_char(6,'I');
vfd_display_char(7,'M');
}
void VFD_System_Set_Brightness_15(void)
{
vfd_display_char(0,'B');
vfd_display_char(1,'R');
vfd_display_char(2,'I');
vfd_display_char(3,'G');
vfd_display_char(4,'H');
vfd_display_char(5,0x3a);
vfd_display_char(6,Bright_Set_Num/10+48);
vfd_display_char(7,Bright_Set_Num%10+48);

BKP_WriteBackupRegister(BKP_DR3, Bright_Set_Num);
}

void VFD_System_Set_Sleep_Time_16(void)
{
vfd_display_char(0,'S');
vfd_display_char(1,'T');
vfd_display_char(2,'I');
vfd_display_char(3,'M');
vfd_display_char(4,'E');
vfd_display_char(5,0x3a);
vfd_display_char(6,System_Sleep_Time/10+48);
vfd_display_char(7,System_Sleep_Time%10+48);

BKP_WriteBackupRegister(BKP_DR4, System_Sleep_Time);
}

void VFD_System_Set_17(void)
{
vfd_display_char(0,'S');
vfd_display_char(1,'E');
vfd_display_char(2,'T');
vfd_display_char(3,0x1b);
vfd_display_char(4,'S');
vfd_display_char(5,'P');
vfd_display_char(6,'E');
vfd_display_char(7,'D');
}
void VFD_System_Set_Show_Speed_18(void)
{
if (FLASH_TIME == 5)
{
vfd_display_char(0,'F');
vfd_display_char(1,'A');
vfd_display_char(2,'S');
vfd_display_char(3,'T');
}
else
{
vfd_display_char(0,'S');
vfd_display_char(1,'N');
vfd_display_char(2,'O');
vfd_display_char(3,'W');
}

vfd_display_char(4,0x10);
vfd_display_char(5,0x10);
vfd_display_char(6,0x10);
vfd_display_char(7,0x10);
BKP_WriteBackupRegister(BKP_DR2, FLASH_TIME);
}
/**
* @brief 带动画的时间线跳跃检测器,改变宏定义可在随机时间线与固定时间线之间切换
* @param None
* @retval None
*/
void VFD_Show_Time_Line_1(void)
{
// 伪随机时间线检测装置
if (TIme_seed > (m*s)%60+61)
{
if (!Ramdom_Time_Set)
{
vfd_display_char(0,'1');
vfd_display_char(1,0x2e);
vfd_display_char(2,'7');
vfd_display_char(3,'4');
vfd_display_char(4,'3');
vfd_display_char(5,'2');
vfd_display_char(6,'1');
vfd_display_char(7,'5');
}
else
{
vfd_display_char(0,char_t[TIme_seed*s %10]);
vfd_display_char(1,0x2e);
vfd_display_char(2,char_t[(TIme_seed+1)*m %10]);
vfd_display_char(3,char_t[(TIme_seed+6)*2 %10]);
vfd_display_char(4,char_t[(TIme_seed-2)*3 %10]);
vfd_display_char(5,char_t[(TIme_seed+1)*(s%10) %10]);
vfd_display_char(6,char_t[(TIme_seed+9)*(h%5) %10]);
vfd_display_char(7,char_t[(TIme_seed+2)*s %10]);
}
}
else
{
vfd_display_char(0,char_t[TIme_seed*13 %10]);
vfd_display_char(1,0x2e);
vfd_display_char(2,char_t[TIme_seed*1 %10]);
vfd_display_char(3,char_t[TIme_seed*2 %10]);
vfd_display_char(4,char_t[TIme_seed*3 %10]);
vfd_display_char(5,char_t[TIme_seed*17 %10]);
vfd_display_char(6,char_t[TIme_seed*7 %10]);
vfd_display_char(7,char_t[TIme_seed*11 %10]);

TIme_seed += 1;
}

delay_ms(50);
}

/**
* @brief 读取备份寄存器中的系统设置数据。
* @param None
* @retval None
*/
void BKP_Init(void)
{
if (BKP_ReadBackupRegister(BKP_DR2) != 0x0000)
{
FLASH_TIME = BKP_ReadBackupRegister(BKP_DR2);
}
if (BKP_ReadBackupRegister(BKP_DR3) != 0x0000)
{
Bright_Set_Num = BKP_ReadBackupRegister(BKP_DR3);
}
if (BKP_ReadBackupRegister(BKP_DR4) != 0x0000)
{
System_Sleep_Time = BKP_ReadBackupRegister(BKP_DR4);
}
}

/**
* @brief TIM3中断服务函数。
* @param None
* @retval None
*/
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update)) {
if((Tim3_cnt++ >= 100) && KEY1_STATE()) {
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); // 关闭定时器计数
if (Key_long_flag_2)
Key_long_flag_2 = 0;
else
Key_long_flag_2 = 1;
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
/**
* @brief KEY1中断服务函数。
* @param None
* @retval None
*/
void KEY1_EXTIn_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1) != RESET) {
if(KEY1_STATE()) {
Tim3_cnt = 0; // 清空tim3计算器
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 开启定时器计数
}
else if((Tim3_cnt++ < 100 && Tim3_cnt > 4) && !KEY1_STATE())
{
Tim3_cnt = 0; // 清空tim3计算器
if (Key_short_flag_2)
Key_short_flag_2 = 0;
else
Key_short_flag_2 = 1;
TIM_ITConfig(TIM3, TIM_IT_Update, DISABLE); // 关闭定时器计数
}
EXTI_ClearITPendingBit(EXTI_Line1); // 清除中断标志
}
}
/**
* @brief TIM2中断服务函数。
* @param None
* @retval None
*/
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update)) {
if((Tim2_cnt++ >= 100) && KEY0_STATE()) {
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); // 关闭定时器计数
if (Key_long_flag_1)
Key_long_flag_1 = 0;
else
Key_long_flag_1 = 1;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
/**
* @brief KEY0中断服务函数。
* @param None
* @retval None
*/
void KEY0_EXTIn_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
if(KEY0_STATE()) {
Tim2_cnt = 0; // 清空tim2计算器
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 开启定时器计数
}
else if((Tim2_cnt++ < 100 && Tim2_cnt > 4) && !KEY0_STATE())
{
Tim2_cnt = 0; // 清空tim2计算器
if (Key_short_flag_1)
Key_short_flag_1 = 0;
else
Key_short_flag_1 = 1;
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); // 关闭定时器计数
}
EXTI_ClearITPendingBit(EXTI_Line0); // 清除中断标志
}
}

写在最后

本质上这个东西只是为我以后作为参考的一个笔记,不过如果有人看到了这里并且想要源码的话 真的会有吗 麻烦访问这里私信一下up就行了