• 学习笔记|小数点控制原理|数码管动态显示|段码跟位码|STC32G单片机视频开发教程(冲哥)|第十集:数码管动态显示


    1.数码管动态刷新的原理

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    上述图片引用自:51单片机初学2-数码管动态扫描
    用一排端口来控制段码,需要显示哪几个就点亮哪几个段,和看电影一样,一个一个的打开,关闭,一个个的画面,组成动画。
    在这里插入图片描述

    2.动态刷新原理

    具体的控制的流程如图所示,N表示有几个数码管!
    在这里插入图片描述

    其中需要注意每个延时不能太短,我们这边程序就以1ms为准,且需要保证总共一个循环结束的时间不能大于20ms,因为人眼的视觉不容易分辨出50HZ以上的动态刷新。
    给他延时一定时间以后再切到第二位,再打开位码,顺次循环,8个管同时点亮。

    3.8位数码管同时点亮

    1.在上一课的基础上,新增一个位码选择的数组
    以上一节的工程5.seg为模板,建立6.seg-active:
    屏蔽原来的静态显示代码,增加4位数码管的显示代码:

    		//第1位的数码管显示0
    		P7 = COM_Tab[0];
    		P6 = SEG_Tab[0];	//这个数码管输出段码
    		delay_ms(1);
    
    		//第2位的数码管显示1
    		P7 = COM_Tab[1];
    		P6 = SEG_Tab[1];	//这个数码管输出段码
    		delay_ms(1);
    
    		//第3位的数码管显示2
    		P7 = COM_Tab[2];
    		P6 = SEG_Tab[2];	//这个数码管输出段码
    		delay_ms(1);
    
    		//第4位的数码管显示3
    		P7 = COM_Tab[3];
    		P6 = SEG_Tab[3];	//这个数码管输出段码
    		delay_ms(1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    编译,下载,主频24MHZ,每次下载前发送自定义命令,数码管显示0123。
    改为延迟为200ms,在文件头部宏定义最大时间延迟:

    #define SEG_DELAY 200	//延时ms
    //while主循环中使用宏定义,可实现批量修改延迟时间
    delay_ms(SEG_DELAY);
    
    • 1
    • 2
    • 3

    可以看到明显的闪烁。
    如果只需要数码管从1 开始显示到8,观察代码中的段码和位码参数变量,值相同,可以使用num变量。num最大值为7,只有8位数码管。
    需要加个判断来限定:

    		P7 = COM_Tab[num];
    		P6 = SEG_Tab[num+1];	//这个数码管输出段码,从1 开始显示到8
    		delay_ms(SEG_DELAY);
    
    		num++;
    
    		if(num>7)
    		{
    			num = 0;
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    新建一个数组选择每个位需要显示的内容

    如果待显示数据无规律,则需要新建一个数组选择每个位需要显示的内容!
    新建数组:u8 Show_Tab[8] = {1,5,0,3,5,7,3,3};
    修改显示函数的相关内容:

    		P7 = COM_Tab[num];		//位码选择
    		P6 = SEG_Tab[Show_Tab[num]];   //需要显示的数组内容,如果 num =0 ->Show_Tab[num] = 1->P6 =0xf9
    		delay_ms(SEG_DELAY);
    
    		num++;
    
    		if(num>7)
    		{
    			num = 0;
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    实战小练:简易10秒免单计数器

    在这里插入图片描述

    1.在前四位数码管上显示目标时间,即“ 10. 00 ”表示定时时间10秒钟
    2.后四位显示当前的计时00.00,最小单位为10ms,
    3.按下开始按钮后,每10ms最末尾的数字+1;知道按下结束按钮后停止计数。
    首先,小数点怎么去点亮?默认数组中小数点不点亮,添加小数点位。
    复制原有的段码,然后将复制部分减0x80:

    u8 SEG_Tab[20] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //0-9段码选择,添加0-9带小数点的段码
    
    //定义基础显示代码
    		Show_Tab[0] = 1;	 //选择1
    		Show_Tab[1] = 10;    //选择“0.”
    		Show_Tab[2] = 0;    //选择0
    		Show_Tab[3] = 0;    //选择0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    看效果,前4位是10.00,后面还是5733(之前的代码未修改),可以修改原显示代码,全都显示0.

    u8 Show_Tab[8] = {0,0,0,0,0,0,0,0};
    
    • 1

    新建计时变量,大小选择为u32,u32 TimCount = 0; //计数单位为ms 每加1,表示过去了1ms
    4-7位的显示代码为:

    		if(RUN_state == 1)
    		{
    			TimCount++; //每执行完1次,加1
    			Show_Tab[4] = TimCount/10000%10;    //取万位,
    			Show_Tab[5] = TimCount/1000%10; //取千位,
    			Show_Tab[6] = TimCount/100%10;  //取百位,
    			Show_Tab[7] = TimCount/10%10; //取10位,除以10即舍去最低位,103%10 = 3,1030/10%10=3
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    编译烧录,数据在跳动,但显示还是不正常:
    1、且按暂停后没有重新从0启动,刚开始的时候没有把数据清0,修改代码:

    if( RUN_State == 0 )
    					TimCount = 0;
    
    • 1
    • 2

    2、百位数上的一个小数点没有显示,改为:Show_Tab[5] = TimCount/1000%10+10; //取千位并显示小数点
    重新编译,下载。显示10.000000,没有显示00.00,修改:在Show_Tab[8]的对应位置原数据+10:

    u8 Show_Tab[8] = {0,0,0,0,0,10,0,0};  //数码管均重置为0,10代表第10位(0x40),带小数点。显示0.00。
    									  //即要想显示数字+小数点,只要在数字前面加1,变成10几,就可以了
    
    • 1
    • 2

    在这里插入图片描述

    编译烧录,显示:10.0000.00,效果正常,按key1从0开始计数,数字跳动,再按一下,停止,重新按键,又从0开始计数。
    而按下key1的情况下,只显示1位,需要调整代码:
    看一下key1按下执行到哪里?“while(KEY1 == 0);”,等待按键松开,所以显示在这里不动了。
    所以解决问题的关键在于:等待按键松开的过程中,还要保持这个数码管不断的显示。
    则需要把数码管的显示代码挪过来,在等待过程中再显示一遍,循环的时候数据还要自加:

    				while(KEY1 == 0)   //增加重复显示代码,防止等待KEY1按下的过程中只显示1位0
    				{
                        P7 = COM_Tab[num];		//位码选择
                        P6 = SEG_Tab[Show_Tab[num]];   //需要显示的数组内容,如果 num =0 ->Show_Tab[num] = 1->P6 =0xf9
                        delay_ms(SEG_DELAY);
    
                        num++;
    
                        if(num>7)
                        {
                            num = 0;
                        }
    				}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    编译后运行,按下key1时,参数也一直在动。

    将刷新动作写成函数

    重复的刷新工作可以用一个函数去代替
    先声明:void SEG_Fre(void); //专门用于数码管刷新
    再实现:

    void SEG_Fre(void) //专门用于数码管刷新
    {
    	//---------------------------数码管刷新---------------------------------
    	u8 num = 0;
    	P7 = COM_Tab[num];		//位码选择
    	P6 = SEG_Tab[Show_Tab[num]];   //需要显示的数组内容,如果 num =0 ->Show_Tab[num] = 1->P6 =0xf9
    	delay_ms(SEG_DELAY);
    
    	num++;
    
    	if(num>7)
    	{
    		num = 0;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    代码中使用,完整代码为:

    #include "COMM/stc.h"		//调用头文件
    #include "COMM/usb.h"
    
    #define KEY1 P32		//定义一个按键 引脚选择P32
    #define KEY2 P33		//定义一个按键 引脚选择P33
    
    #define BEEP P54		//定义一个按键 引脚选择P54
    
    #define SEG_Delay  1	//延时多少ms
    
    #define MAIN_Fosc 24000000UL	//定义主时钟
    
    char *USER_DEVICEDESC = NULL;
    char *USER_PRODUCTDESC = NULL;
    char *USER_STCISPCMD = "@STCISP#";
    
    u8 SEG_Tab[20] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};	//0-9段码,0-9带小数点
    u8 COM_Tab[8] = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };	//0-7的位码数组
    u8 Show_Tab[8] = {3,0,0,0,0,10,0,0};
    
    u32 TimCount = 0;		//计数单位1ms
    bit RUN_State = 0;		//开始运行/结束运行
    u8 num = 0;
    
    void sys_init();	//函数声明
    void delay_ms(u16 ms);	//unsigned int
    
    void SEG_Fre( void ); //专门用于数码管刷新
    
    void main()					//程序开始运行的入口
    {
    
    	sys_init();				//USB功能+IO口初始化
    	usb_init();				//usb库初始化
    	EA = 1;					//CPU开放中断,打开总中断。
    
    	while(1)		//死循环
    	{
    		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
    			continue;
    		if( bUsbOutReady )
    		{
    			usb_OUT_done();
    
    		}
    
    //------------------------------------------------数码管刷新-------------------------------------------------
    		Show_Tab[0]  = 1;		//选择 1
    		Show_Tab[1]  = 10;		//选择 0.
    		Show_Tab[2]  = 0;		//选择 0
    		Show_Tab[3]  = 0;		//选择 0
    
    
    
    
    		if( RUN_State==1 )
    		{
    			TimCount++;
    			Show_Tab[4] = TimCount/10000%10;
    			Show_Tab[5] = TimCount/1000%10+10;
    			Show_Tab[6] = TimCount/100%10;
    		    Show_Tab[7] = TimCount/10%10;		//取10位
    		}
    
    		SEG_Fre();
    
    		if( KEY1 ==0 )
    		{
    			delay_ms(10);
    			if( KEY1 ==0 )
    			{
    				BEEP = 0;
    				delay_ms(10);
    				BEEP = 1;
    				while( KEY1 ==0 )
    				{
    					SEG_Fre();
    				}
    				if( RUN_State==0 )
    					TimCount = 0;
    
    				RUN_State = !RUN_State;
    			}
    		}
    
    	}
    }
    /*
     11111110 0XFE
     11111101 0XFD
     11111011 0XFB
     11110111 0XF7
     11101111 0XEF
     11011111 0XDF
     10111111 0XBF
     01111111 0X7F
    */
    
    void sys_init()		//函数定义
    {
        WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
        EAXFR = 1; //扩展寄存器(XFR)访问使能
        CKCON = 0; //提高访问XRAM速度
    
    	P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
        P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
        P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
        P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
        P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
        P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
        P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
        P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    
        P3M0 = 0x00;
        P3M1 = 0x00;
    
        P3M0 &= ~0x03;
        P3M1 |= 0x03;
    
        //设置USB使用的时钟源
        IRC48MCR = 0x80;    //使能内部48M高速IRC
        while (!(IRC48MCR & 0x01));  //等待时钟稳定
    
        USBCLK = 0x00;	//使用CDC功能需要使用这两行,HID功能禁用这两行。
        USBCON = 0x90;
    }
    
    
    void delay_ms(u16 ms)	//unsigned int
    {
    	u16 i;
    	do
    	{
    		i = MAIN_Fosc/6000;
    		while(--i);
    	}while(--ms);
    }
    
    void SEG_Fre( void )
    {
    	//位码选择第一位,段码选择0
    	u8 num = 0; //也可以放在main函数前,作为全局变量
    	P7 = COM_Tab[num];			//位码的选择
    	P6 = SEG_Tab[Show_Tab[num]];//需要显示的数字的内码 赋给 P6   NUM =0 -> Show_Tab[num]] = 1 -> p6 = oxF9
    	delay_ms(SEG_Delay);
    
    	num++;
    	if( num >7 )
    		num = 0;
    }
    
    • 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

    课后练习:

    一、做一个简易时钟,功能如下
    1.初始状态显示00 - 00 - 00,分别作为时,分,秒;
    2.每隔一秒钟,秒+1,一分钟,分+1,以此类推;
    3.时间到达00 - 00 - 30的时候,蜂鸣响3秒钟表示闹钟。

  • 相关阅读:
    springboot之二:整合junit进行单元测试+整合redis(本机、远程)+整合mybatis
    Linux —— OpenCv编译安装
    机器学习(15)---代价函数、损失函数和目标函数详解
    ubuntu16编译linux源码内核
    Golang使用sqlx报错max_prepared_stmt_count超过16382
    网页制作基础大二dw作业HTML+CSS+JavaScript云南我的家乡旅游景点
    CentOS7的#!bash #!/bin/bash #!/bin/env bash #!/usr/bin/bash #!/usr/bin/env bash
    【SpringBoot框架篇】29.Jpa+vue实现单模型的低代码平台
    38、Java——汽车租赁系统(JDBC+MySQL+Apache DBUtils)
    Linux journal日志文件维护
  • 原文地址:https://blog.csdn.net/Medlar_CN/article/details/132694178