打酱油的工程师 发表于 2023-9-5 16:32:57

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

本帖最后由 打酱油的工程师 于 2023-9-5 16:51 编辑

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




https://pica.zhimg.com/80/v2-8a49cd09823f3ba45c76a33ec835e49d_720w.jpg?source=d16d100b

https://picx.zhimg.com/80/v2-dd0ee8042f955d8649e64f814dc7d6e7_720w.jpg?source=d16d100b



https://picx.zhimg.com/80/v2-501d9da917c0511cba8583ffafa8d06f_720w.jpg?source=d16d100b


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

2.动态刷新原理
具体的控制的流程如图所示,N表示有几个数码管!


https://picx.zhimg.com/80/v2-89aa91f425993e844f92a71c96e58370_720w.jpg?source=d16d100b

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

3.8位数码管同时点亮
1.在上一课的基础上,新增一个位码选择的数组 以上一节的工程5.seg为模板,建立6.seg-active: 屏蔽原来的静态显示代码,增加4位数码管的显示代码://第1位的数码管显示0
                P7 = COM_Tab;
                P6 = SEG_Tab;      //这个数码管输出段码
                delay_ms(1);

                //第2位的数码管显示1
                P7 = COM_Tab;
                P6 = SEG_Tab;      //这个数码管输出段码
                delay_ms(1);

                //第3位的数码管显示2
                P7 = COM_Tab;
                P6 = SEG_Tab;      //这个数码管输出段码
                delay_ms(1);

                //第4位的数码管显示3
                P7 = COM_Tab;
                P6 = SEG_Tab;      //这个数码管输出段码
                delay_ms(1);

编译,下载,主频24MHZ,每次下载前发送自定义命令,数码管显示0123。 改为延迟为200ms,在文件头部宏定义最大时间延迟:#define SEG_DELAY 200        //延时ms
//while主循环中使用宏定义,可实现批量修改延迟时间
delay_ms(SEG_DELAY);
可以看到明显的闪烁。 如果只需要数码管从1 开始显示到8,观察代码中的段码和位码参数变量,值相同,可以使用num变量。num最大值为7,只有8位数码管。 需要加个判断来限定:P7 = COM_Tab;
                P6 = SEG_Tab;        //这个数码管输出段码,从1 开始显示到8
                delay_ms(SEG_DELAY);

                num++;

                if(num>7)
                {
                        num = 0;
                }

新建一个数组选择每个位需要显示的内容
如果待显示数据无规律,则需要新建一个数组选择每个位需要显示的内容! 新建数组:u8 Show_Tab = {1,5,0,3,5,7,3,3}; 修改显示函数的相关内容:P7 = COM_Tab;                //位码选择
                P6 = SEG_Tab];   //需要显示的数组内容,如果 num =0 ->Show_Tab = 1->P6 =0xf9
                delay_ms(SEG_DELAY);

                num++;

                if(num>7)
                {
                        num = 0;
                }实战小练:简易10秒免单计数器




https://pica.zhimg.com/80/v2-c881065feff6a491d228b6de9f00a71f_720w.jpg?source=d16d100b
1.在前四位数码管上显示目标时间,即“ 10. 00 ”表示定时时间10秒钟 2.后四位显示当前的计时00.00,最小单位为10ms, 3.按下开始按钮后,每10ms最末尾的数字+1;知道按下结束按钮后停止计数。 首先,小数点怎么去点亮?默认数组中小数点不点亮,添加小数点位。 复制原有的段码,然后将复制部分减0x80:u8 SEG_Tab = {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 = 1;       //选择1
                Show_Tab = 10;    //选择“0.”
                Show_Tab = 0;    //选择0
                Show_Tab = 0;    //选择0
看效果,前4位是10.00,后面还是5733(之前的代码未修改),可以修改原显示代码,全都显示0.
u8 Show_Tab = {0,0,0,0,0,0,0,0};

新建计时变量,大小选择为u32,u32 TimCount = 0;   //计数单位为ms 每加1,表示过去了1ms 4-7位的显示代码为:if(RUN_state == 1)
                {
                        TimCount++; //每执行完1次,加1
                        Show_Tab = TimCount/10000%10;    //取万位,
                        Show_Tab = TimCount/1000%10; //取千位,
                        Show_Tab = TimCount/100%10;//取百位,
                        Show_Tab = TimCount/10%10; //取10位,除以10即舍去最低位,103%10 = 3,1030/10%10=3
                }

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

2、百位数上的一个小数点没有显示,改为:Show_Tab = TimCount/1000%10+10; //取千位并显示小数点 重新编译,下载。显示10.000000,没有显示00.00,修改:在Show_Tab的对应位置原数据+10:u8 Show_Tab = {0,0,0,0,0,10,0,0};//数码管均重置为0,10代表第10位(0x40),带小数点。显示0.00。
                                                                          //即要想显示数字+小数点,只要在数字前面加1,变成10几,就可以了





https://picx.zhimg.com/80/v2-12944c02d342e76ba898bd7b3297092d_720w.jpg?source=d16d100b

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

                  num++;

                  if(num>7)
                  {
                        num = 0;
                  }
                                }

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

将刷新动作写成函数
重复的刷新工作可以用一个函数去代替 先声明:void SEG_Fre(void); //专门用于数码管刷新 再实现:void SEG_Fre(void) //专门用于数码管刷新
{
        //---------------------------数码管刷新---------------------------------
        u8 num = 0;
        P7 = COM_Tab;                //位码选择
        P6 = SEG_Tab];   //需要显示的数组内容,如果 num =0 ->Show_Tab = 1->P6 =0xf9
        delay_ms(SEG_DELAY);

        num++;

        if(num>7)
        {
                num = 0;
        }
}
代码中使用,完整代码为:#include "COMM/stc.h"                //调用头文件
#include "COMM/usb.h"

#define KEY1 P32                //定义一个按键 引脚选择P32
#define KEY2 P33                //定义一个按键 引脚选择P33

#define BEEP P54                //定义一个按键 引脚选择P54

#define SEG_Delay1        //延时多少ms

#define MAIN_Fosc 24000000UL        //定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

u8 SEG_Tab = { 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 = { 0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe };        //0-7的位码数组
u8 Show_Tab = {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= 1;                //选择 1
                Show_Tab= 10;                //选择 0.
                Show_Tab= 0;                //选择 0
                Show_Tab= 0;                //选择 0




                if( RUN_State==1 )
                {
                        TimCount++;
                        Show_Tab = TimCount/10000%10;
                        Show_Tab = TimCount/1000%10+10;
                        Show_Tab = TimCount/100%10;
                  Show_Tab = 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;                        //位码的选择
        P6 = SEG_Tab];//需要显示的数字的内码 赋给 P6   NUM =0 -> Show_Tab] = 1 -> p6 = oxF9
        delay_ms(SEG_Delay);

        num++;
        if( num >7 )
                num = 0;
}
课后练习:
一、做一个简易时钟,功能如下

1.初始状态显示00 - 00 - 00,分别作为时,分,秒;

2.每隔一秒钟,秒+1,一分钟,分+1,以此类推;

3.时间到达00 - 00 - 30的时候,蜂鸣响3秒钟表示闹钟。




页: [1]
查看完整版本: 学习笔记|小数点|STC32G单片机视频开发教程(冲哥)|第十集:数码管动态显示