数显仪表盘显示“速度、方向、计数器”的跑马灯

本节小项目,意在“人机界面”与“过程控制”如何关联的练习。 程序功能如下: (1)数码管显示的格式是“S.D.CC”。其中S是代表3档速度,能显示的数字范围是“1、2、3”,分别代表“慢、中、快”3档速度。D代表方向,往右跑显示符号“r”(right的首字母),往左跑显示符号“L”(Left的首字母)。CC代表计数器,跑马灯每跑完一次,计数器自动加1,范围是0到99。 (2)【速度】按键K1。每按一次【速度】按键K1,速度档位显示的数字在“1、2、3”之间切换。 (3)【方向】按键K2。跑马灯上电后默认处于“往右跑”的方向,默认显示字符“r”。每按一次【方向】按键K2,跑马灯就在“往右跑”与“往左跑”两个方向之间切换,显示的字符在“r、L”之间切换。 (4)【启动暂停】按键K3。上电后,按下【启动暂停】按键K3启动之后,跑马灯处于“启动”状态,4个LED灯挨个依次循环的变亮,给人“跑”起来的感觉,此时再按一次【启动暂停】按键K3,则跑马灯处于“暂停”状态,接着又按一次【启动暂停】按键K3,跑马灯又变回“启动”状态。因此,【启动暂停】按键K3是专门用来切换“启动”和“暂停”这两种状态。 代码如下:

  1#include "REG52.H"
  2
  3#define KEY_FILTER_TIME  25
  4
  5#define SCAN_TIME  1
  6#define VOICE_TIME   50
  7
  8#define RUN_TIME_SLOW    500   //“慢”档速度的时间参数
  9#define RUN_TIME_MIDDLE  300   //“中”档速度的时间参数
 10#define RUN_TIME_FAST    100   //“快”档速度的时间参数
 11
 12void T0_time();
 13void SystemInitial(void) ;
 14void Delay(unsigned long u32DelayTime) ;
 15void PeripheralInitial(void) ;
 16
 17void KeyScan(void);
 18void KeyTask(void);
 19void RunTask(void);   //跑马灯的任务函数
 20
 21void VoiceScan(void);
 22void DisplayScan(void);
 23void DisplayTask(void);
 24void Wd1(void);   //窗口1。
 25void BeepOpen(void);
 26void BeepClose(void);
 27
 28sbit KEY_INPUT1 = P2 ^ 2;
 29sbit KEY_INPUT2 = P2 ^ 1;
 30sbit KEY_INPUT3 = P2 ^ 0;
 31
 32sbit P1_0 = P1 ^ 0;
 33sbit P1_1 = P1 ^ 1;
 34sbit P1_2 = P1 ^ 2;
 35sbit P1_3 = P1 ^ 3;
 36
 37sbit P3_4 = P3 ^ 4;
 38
 39//4个跑马灯的输出口
 40sbit P1_4 = P1 ^ 4;
 41sbit P1_5 = P1 ^ 5;
 42sbit P1_6 = P1 ^ 6;
 43sbit P3_3 = P3 ^ 3;
 44
 45
 46//数码管转换表
 47code unsigned char Cu8DigTable[] =
 48{
 49    0x3f,  //0       序号0
 50    0x06,  //1       序号1
 51    0x5b,  //2       序号2
 52    0x4f,  //3       序号3
 53    0x66,  //4       序号4
 54    0x6d,  //5       序号5
 55    0x7d,  //6       序号6
 56    0x07,  //7       序号7
 57    0x7f,  //8       序号8
 58    0x6f,  //9       序号9
 59    0x00,  //不显示  序号10
 60    0x40,  //横杠-   序号11
 61    0x38,  //字符L   序号12
 62    0x70,  //字符r   序号13
 63};
 64
 65volatile unsigned char vGu8ScanTimerFlag = 0;
 66volatile unsigned int vGu16ScanTimerCnt = 0;
 67
 68volatile unsigned char vGu8BeepTimerFlag = 0;
 69volatile unsigned int vGu16BeepTimerCnt = 0;
 70
 71unsigned char Gu8Wd = 0; //窗口选择变量。人机交互程序框架的支点。
 72unsigned char Gu8WdUpdate = 0; //整屏更新变量。
 73
 74unsigned char Gu8PartUpdate_1 = 0; //局部1的更新变量,
 75unsigned char Gu8PartUpdate_2 = 0; //局部2的更新变量
 76unsigned char Gu8PartUpdate_3 = 0; //局部3的更新变量,
 77
 78volatile unsigned char vGu8Display_Righ_4 = 0;
 79volatile unsigned char vGu8Display_Righ_3 = 0;
 80volatile unsigned char vGu8Display_Righ_2 = 0;
 81volatile unsigned char vGu8Display_Righ_1 = 0;
 82
 83volatile unsigned char vGu8Display_Righ_Dot_4 = 1; //需要显示的小数点
 84volatile unsigned char vGu8Display_Righ_Dot_3 = 1; //需要显示的小数点
 85volatile unsigned char vGu8Display_Righ_Dot_2 = 0;
 86volatile unsigned char vGu8Display_Righ_Dot_1 = 0;
 87
 88volatile unsigned char vGu8KeySec = 0;
 89
 90unsigned char Gu8RunCounter = 0;  //计数器,范围是0到99
 91
 92unsigned char Gu8RunStep = 0; //运行的步骤
 93unsigned char Gu8RunStart = 0;    //控制跑马灯启动的总开关
 94
 95unsigned char Gu8RunStatus = 0;   //标识跑马灯当前的状态。0代表停止,1代表启动,2代表暂停。
 96unsigned char Gu8RunDirection = 0; //标识跑马灯当前的方向。0代表往右跑,1代表往左跑。
 97unsigned char Gu8RunSpeed = 1;    //当前的速度档位。1代表“慢”,2代表“中”,3代表“快”。
 98unsigned int  Gu16RunSpeedTimeDate = 0; //承接各速度档位的时间参数的变量
 99
100volatile unsigned char vGu8RunTimerFlag = 0; //用于控制跑马灯跑动速度的定时器
101volatile unsigned int vGu16RunTimerCnt = 0;
102
103void main()
104{
105    SystemInitial();
106    Delay(10000);
107    PeripheralInitial();
108
109    while(1)
110    {
111        KeyTask();      //按键的任务函数
112        DisplayTask();  //数码管显示的上层任务函数
113        RunTask();    //跑马灯的任务函数
114    }
115}
116
117void RunTask(void)    //跑马灯的任务函数,放在主函数内
118{
119    if(0 == Gu8RunStart) //如果是停止的状态
120    {
121        return;  //如果是停止的状态,退出当前函数,不扫描余下代码。
122    }
123
124    switch(Gu8RunStep) //屡见屡爱的switch又来了
125    {
126        case 0:
127            vGu8RunTimerFlag = 0;
128            vGu16RunTimerCnt = 0; //定时器清零
129            Gu8RunStep = 1; //切换到下一步,启动
130
131            break;
132
133        case 1:
134            if(1 == Gu8RunStatus && 0 == vGu16RunTimerCnt) //当前处于“启动”状态,并且定时器等于0
135            {
136                P1_4 = 0; //第1个灯亮
137                P1_5 = 1; //第2个灯灭
138                P1_6 = 1; //第3个灯灭
139                P3_3 = 1; //第4个灯灭
140
141                vGu8RunTimerFlag = 0;
142                vGu16RunTimerCnt = Gu16RunSpeedTimeDate; //速度时间参数变量的大小,决定了速度
143                vGu8RunTimerFlag = 1; //启动定时器
144
145//灵活切换“步骤变量”
146                if(0 == Gu8RunDirection) //往右跑
147                {
148                    Gu8RunStep = 2;
149                }
150                else  //往左跑
151                {
152                    if(Gu8RunCounter < 99)
153                    {
154                        Gu8RunCounter++; //往左边跑完一次,运行的计数器自加1
155                    }
156
157                    Gu8PartUpdate_3 = 1; //局部3的更新变量,更新显示计数器
158
159                    Gu8RunStep = 4;
160                }
161
162            }
163
164            break;
165
166        case 2:
167            if(1 == Gu8RunStatus && 0 == vGu16RunTimerCnt) //当前处于“启动”状态,并且定时器等于0
168            {
169                P1_4 = 1; //第1个灯灭
170                P1_5 = 0; //第2个灯亮
171                P1_6 = 1; //第3个灯灭
172                P3_3 = 1; //第4个灯灭
173
174                vGu8RunTimerFlag = 0;
175                vGu16RunTimerCnt = Gu16RunSpeedTimeDate; //速度时间参数变量的大小,决定了速度
176                vGu8RunTimerFlag = 1; //启动定时器
177
178//灵活切换“步骤变量”
179                if(0 == Gu8RunDirection) //往右跑
180                {
181                    Gu8RunStep = 3;
182                }
183                else  //往左跑
184                {
185                    Gu8RunStep = 1;
186                }
187            }
188
189            break;
190
191        case 3:
192            if(1 == Gu8RunStatus && 0 == vGu16RunTimerCnt) //当前处于“启动”状态,并且定时器等于0
193            {
194                P1_4 = 1; //第1个灯灭
195                P1_5 = 1; //第2个灯灭
196                P1_6 = 0; //第3个灯亮
197                P3_3 = 1; //第4个灯灭
198
199                vGu8RunTimerFlag = 0;
200                vGu16RunTimerCnt = Gu16RunSpeedTimeDate; //速度时间参数变量的大小,决定了速度
201                vGu8RunTimerFlag = 1; //启动定时器
202
203//灵活切换“步骤变量”
204                if(0 == Gu8RunDirection) //往右跑
205                {
206                    Gu8RunStep = 4;
207                }
208                else  //往左跑
209                {
210                    Gu8RunStep = 2;
211                }
212            }
213
214            break;
215
216        case 4:
217            if(1 == Gu8RunStatus && 0 == vGu16RunTimerCnt) //当前处于“启动”状态,并且定时器等于0
218            {
219                P1_4 = 1; //第1个灯灭
220                P1_5 = 1; //第2个灯灭
221                P1_6 = 1; //第3个灯灭
222                P3_3 = 0; //第4个灯亮
223
224                vGu8RunTimerFlag = 0;
225                vGu16RunTimerCnt = Gu16RunSpeedTimeDate; //速度时间参数变量的大小,决定了速度
226                vGu8RunTimerFlag = 1; //启动定时器
227
228//灵活切换“步骤变量”
229                if(0 == Gu8RunDirection) //往右跑
230                {
231                    if(Gu8RunCounter < 99)
232                    {
233                        Gu8RunCounter++; //往右边跑完一次,运行的计数器自加1
234                    }
235
236                    Gu8PartUpdate_3 = 1; //局部3的更新变量,更新显示计数器
237
238                    Gu8RunStep = 1;
239                }
240                else  //往左跑
241                {
242                    Gu8RunStep = 3;
243                }
244            }
245
246            break;
247
248    }
249
250}
251
252void KeyTask(void)    //按键的任务函数
253{
254    if(0 == vGu8KeySec)
255    {
256        return;
257    }
258
259    switch(vGu8KeySec)
260    {
261        case 1:     //【速度】按键K1
262            switch(Gu8Wd) //在某个窗口下
263            {
264                case 1:     //窗口1。
265
266                    //每按一次K1按键,Gu8RunSpeed就在1、2、3三者之间切换,
267//并且根据Gu8RunSpeed的数值,对Gu16RunSpeedTimeDate赋值
268//不同的速度时间参数,从而控制速度档位。
269
270                    if(1 == Gu8RunSpeed)
271                    {
272                        Gu8RunSpeed = 2; //“中”档
273                        Gu16RunSpeedTimeDate = RUN_TIME_MIDDLE; //赋值“中”档的时间参数
274                    }
275                    else if(2 == Gu8RunSpeed)
276                    {
277                        Gu8RunSpeed = 3; //“快”档
278                        Gu16RunSpeedTimeDate = RUN_TIME_FAST; //赋值“快”档的时间参数
279                    }
280                    else
281                    {
282                        Gu8RunSpeed = 1; //“慢”档
283                        Gu16RunSpeedTimeDate = RUN_TIME_SLOW; //赋值“慢”档的时间参数
284                    }
285
286                    Gu8PartUpdate_1 = 1; //局部1的更新变量,更新显示“速度”
287
288                    vGu8BeepTimerFlag = 0;
289                    vGu16BeepTimerCnt = VOICE_TIME; //蜂鸣器发出“滴”一声
290                    vGu8BeepTimerFlag = 1;
291                    break;
292            }
293
294            vGu8KeySec = 0;
295            break;
296
297        case 2:     //【方向】按键K2
298
299            switch(Gu8Wd) //在某个窗口下
300            {
301                case 1:     //窗口1。
302
303                    //每按一次K2按键,Gu8RunDirection就在0和1之间切换,从而控制方向
304                    if(0 == Gu8RunDirection)
305                    {
306                        Gu8RunDirection = 1;
307                    }
308                    else
309                    {
310                        Gu8RunDirection = 0;
311                    }
312
313                    Gu8PartUpdate_2 = 1; //局部2更新显示,更新显示“方向”
314
315                    vGu8BeepTimerFlag = 0;
316                    vGu16BeepTimerCnt = VOICE_TIME; //蜂鸣器发出“滴”一声
317                    vGu8BeepTimerFlag = 1;
318                    break;
319            }
320
321            vGu8KeySec = 0;
322            break;
323
324        case 3:     //【启动暂停】按键K3
325            switch(Gu8Wd) //在某个窗口下
326            {
327                case 1:     //窗口1。
328                    if(0 == Gu8RunStatus) //当跑马灯处于“停止”状态时
329                    {
330                        Gu8RunStep = 0;  //运行步骤从0开始
331                        Gu8RunStart = 1; //总开关“打开”。
332                        Gu8RunStatus = 1; //状态切换到“启动”状态
333                    }
334                    else if(1 == Gu8RunStatus) //当跑马灯处于“启动”状态时
335                    {
336                        Gu8RunStatus = 2; //状态切换到“暂停”状态
337                    }
338                    else  //当跑马灯处于“暂停”状态时
339                    {
340                        Gu8RunStatus = 1; //状态切换到“启动”状态
341                    }
342
343                    vGu8BeepTimerFlag = 0;
344                    vGu16BeepTimerCnt = VOICE_TIME; //蜂鸣器发出“滴”一声
345                    vGu8BeepTimerFlag = 1;
346                    break;
347            }
348
349            vGu8KeySec = 0;
350            break;
351    }
352}
353
354void DisplayTask(void) //数码管显示的上层任务函数
355{
356    switch(Gu8Wd)  //以窗口选择Gu8Wd为支点,去执行对应的窗口显示函数。又一次用到switch语句
357    {
358        case 1:
359            Wd1();   //窗口1。
360            break;
361    }
362}
363
364void Wd1(void)   //窗口1。
365{
366//需要借用的中间变量,用来拆分数据位。
367    static unsigned char Su8Temp_4, Su8Temp_3, Su8Temp_2, Su8Temp_1; //需要借用的中间变量
368
369    if(1 == Gu8WdUpdate) //如果需要整屏更新
370    {
371        Gu8WdUpdate = 0; //及时清零,只更新一次显示即可,避免一直进来更新显示
372
373//属于静态数据,起“装饰”作用,切换窗口后只扫描一次的代码。
374        vGu8Display_Righ_Dot_4 = 1; //显示小数点
375        vGu8Display_Righ_Dot_3 = 1; //显示小数点
376        vGu8Display_Righ_Dot_2 = 0;
377        vGu8Display_Righ_Dot_1 = 0;
378
379        Gu8PartUpdate_1 = 1; //局部1更新显示
380        Gu8PartUpdate_2 = 1; //局部2更新显示
381        Gu8PartUpdate_3 = 1; //局部3更新显示
382    }
383
384    if(1 == Gu8PartUpdate_1) //局部1更新显示,速度
385    {
386        Gu8PartUpdate_1 = 0; //及时清零,只更新一次显示即可,避免一直进来更新显示
387
388        Su8Temp_4 = Gu8RunSpeed;
389
390        vGu8Display_Righ_4 = Su8Temp_4; //过渡需要显示的数据到底层驱动变量
391    }
392
393    if(1 == Gu8PartUpdate_2) //局部2更新显示,方向
394    {
395        Gu8PartUpdate_2 = 0; //及时清零,只更新一次显示即可,避免一直进来更新显示
396
397        if(0 == Gu8RunDirection) //往右跑
398        {
399            Su8Temp_3 = 13; //数码管的字模转换表序号13代表显示字符“r”
400        }
401        else
402        {
403            Su8Temp_3 = 12; //数码管的字模转换表序号12代表显示字符“L”
404        }
405
406        vGu8Display_Righ_3 = Su8Temp_3; //过渡需要显示的数据到底层驱动变量
407    }
408
409    if(1 == Gu8PartUpdate_3) //局部3更新显示,计数器
410    {
411        Gu8PartUpdate_3 = 0; //及时清零,只更新一次显示即可,避免一直进来更新显示
412
413        Su8Temp_2 = Gu8RunCounter % 100 / 10; //提取十位
414        Su8Temp_1 = Gu8RunCounter % 10 / 1; //提取个位
415
416        vGu8Display_Righ_2 = Su8Temp_2; //过渡需要显示的数据到底层驱动变量
417        vGu8Display_Righ_1 = Su8Temp_1; //过渡需要显示的数据到底层驱动变量
418    }
419
420}
421
422
423void KeyScan(void)  //按键底层的驱动扫描函数,放在定时中断函数里
424{
425    static unsigned char Su8KeyLock1;
426    static unsigned int  Su16KeyCnt1;
427    static unsigned char Su8KeyLock2;
428    static unsigned int  Su16KeyCnt2;
429    static unsigned char Su8KeyLock3;
430    static unsigned int  Su16KeyCnt3;
431
432
433    if(0 != KEY_INPUT1)
434    {
435        Su8KeyLock1 = 0;
436        Su16KeyCnt1 = 0;
437    }
438    else if(0 == Su8KeyLock1)
439    {
440        Su16KeyCnt1++;
441
442        if(Su16KeyCnt1 >= KEY_FILTER_TIME)
443        {
444            Su8KeyLock1 = 1;
445            vGu8KeySec = 1;
446        }
447    }
448
449    if(0 != KEY_INPUT2)
450    {
451        Su8KeyLock2 = 0;
452        Su16KeyCnt2 = 0;
453    }
454    else if(0 == Su8KeyLock2)
455    {
456        Su16KeyCnt2++;
457
458        if(Su16KeyCnt2 >= KEY_FILTER_TIME)
459        {
460            Su8KeyLock2 = 1;
461            vGu8KeySec = 2;
462        }
463    }
464
465    if(0 != KEY_INPUT3)
466    {
467        Su8KeyLock3 = 0;
468        Su16KeyCnt3 = 0;
469    }
470    else if(0 == Su8KeyLock3)
471    {
472        Su16KeyCnt3++;
473
474        if(Su16KeyCnt3 >= KEY_FILTER_TIME)
475        {
476            Su8KeyLock3 = 1;
477            vGu8KeySec = 3;
478        }
479    }
480
481}
482
483void DisplayScan(void)    //数码管底层的驱动扫描函数,放在定时中断函数里
484{
485    static unsigned char Su8GetCode;
486    static unsigned char Su8ScanStep = 1;
487
488    if(0 == vGu16ScanTimerCnt)
489    {
490
491
492        P0 = 0x00;
493        P1_0 = 1;
494        P1_1 = 1;
495        P1_2 = 1;
496        P1_3 = 1;
497
498        switch(Su8ScanStep)
499        {
500            case 1:
501                Su8GetCode = Cu8DigTable[vGu8Display_Righ_1];
502
503                if(1 == vGu8Display_Righ_Dot_1)
504                {
505                    Su8GetCode = Su8GetCode | 0x80;
506                }
507
508                P0 = Su8GetCode;
509                P1_0 = 0;
510                P1_1 = 1;
511                P1_2 = 1;
512                P1_3 = 1;
513                break;
514
515            case 2:
516                Su8GetCode = Cu8DigTable[vGu8Display_Righ_2];
517
518                if(1 == vGu8Display_Righ_Dot_2)
519                {
520                    Su8GetCode = Su8GetCode | 0x80;
521                }
522
523                P0 = Su8GetCode;
524                P1_0 = 1;
525                P1_1 = 0;
526                P1_2 = 1;
527                P1_3 = 1;
528                break;
529
530            case 3:
531                Su8GetCode = Cu8DigTable[vGu8Display_Righ_3];
532
533                if(1 == vGu8Display_Righ_Dot_3)
534                {
535                    Su8GetCode = Su8GetCode | 0x80;
536                }
537
538                P0 = Su8GetCode;
539                P1_0 = 1;
540                P1_1 = 1;
541                P1_2 = 0;
542                P1_3 = 1;
543                break;
544
545            case 4:
546                Su8GetCode = Cu8DigTable[vGu8Display_Righ_4];
547
548                if(1 == vGu8Display_Righ_Dot_4)
549                {
550                    Su8GetCode = Su8GetCode | 0x80;
551                }
552
553                P0 = Su8GetCode;
554                P1_0 = 1;
555                P1_1 = 1;
556                P1_2 = 1;
557                P1_3 = 0;
558                break;
559
560        }
561
562        Su8ScanStep++;
563
564        if(Su8ScanStep > 4)
565        {
566            Su8ScanStep = 1;
567        }
568
569        vGu8ScanTimerFlag = 0;
570        vGu16ScanTimerCnt = SCAN_TIME;
571        vGu8ScanTimerFlag = 1;
572    }
573}
574
575void VoiceScan(void) //蜂鸣器的驱动函数
576{
577
578    static unsigned char Su8Lock = 0;
579
580    if(1 == vGu8BeepTimerFlag && vGu16BeepTimerCnt > 0)
581    {
582        if(0 == Su8Lock)
583        {
584            Su8Lock = 1;
585            BeepOpen();
586        }
587        else
588        {
589
590            vGu16BeepTimerCnt--;
591
592            if(0 == vGu16BeepTimerCnt)
593            {
594                Su8Lock = 0;
595                BeepClose();
596            }
597
598        }
599    }
600}
601
602void BeepOpen(void)
603{
604    P3_4 = 0;
605}
606
607void BeepClose(void)
608{
609    P3_4 = 1;
610}
611
612void T0_time() interrupt 1
613{
614    VoiceScan();    //蜂鸣器的驱动函数
615    KeyScan();      //按键底层的驱动扫描函数
616    DisplayScan();  //数码管底层的驱动扫描函数
617
618    if(1 == vGu8ScanTimerFlag && vGu16ScanTimerCnt > 0)
619    {
620        vGu16ScanTimerCnt--;
621    }
622
623    if(1 == vGu8RunTimerFlag && vGu16RunTimerCnt > 0) //用于控制跑马灯跑动速度的定时器
624    {
625        vGu16RunTimerCnt--;
626    }
627
628    TH0 = 0xfd; //此参数可根据具体的时间来修改,尽量确保每定时中断一次接近1ms
629    TL0 = 0x40; //此参数可根据具体的时间来修改,尽量确保每定时中断一次接近1ms
630}
631
632void SystemInitial(void)
633{
634    P0 = 0x00;
635    P1_0 = 1;
636    P1_1 = 1;
637    P1_2 = 1;
638    P1_3 = 1;
639
640    TMOD = 0x01;
641    TH0 = 0xfd; //此参数可根据具体的时间来修改,尽量确保每定时中断一次接近1ms
642    TL0 = 0x40; //此参数可根据具体的时间来修改,尽量确保每定时中断一次接近1ms
643    EA = 1;
644    ET0 = 1;
645    TR0 = 1;
646
647//上电初始化一些关键的数据
648
649    Gu8Wd = 1; //窗口1。开机默认处于正常工作的窗口
650    Gu8WdUpdate = 1; //整屏更新变量
651//跑马灯处于初始化的状态
652    P1_4 = 0; //第1个灯亮
653    P1_5 = 1; //第2个灯灭
654    P1_6 = 1; //第3个灯灭
655    P3_3 = 1; //第4个灯灭
656
657//根据当前的速度档位Gu8RunSpeed,来初始化速度时间参数Gu16RunSpeedTimeDate
658    if(1 == Gu8RunSpeed)
659    {
660        Gu16RunSpeedTimeDate = RUN_TIME_SLOW; //赋值“慢”档的时间参数
661    }
662    else if(2 == Gu8RunSpeed)
663    {
664        Gu16RunSpeedTimeDate = RUN_TIME_MIDDLE; //赋值“中”档的时间参数
665    }
666    else
667    {
668        Gu16RunSpeedTimeDate = RUN_TIME_FAST; //赋值“快”档的时间参数
669    }
670
671}
672
673void Delay(unsigned long u32DelayTime)
674{
675    for(; u32DelayTime > 0; u32DelayTime--);
676}
677
678 void PeripheralInitial(void)

原文发布于微信公众号 - 嵌入式开发圈(gh_d6ff851b4069)

原文发表时间:2019-05-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券