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

news2024/11/27 11:38:32

文章目录

  • 1.数码管动态刷新的原理
  • 2.动态刷新原理
  • 3.8位数码管同时点亮
    • 新建一个数组选择每个位需要显示的内容
    • 实战小练:简易10秒免单计数器
    • 将刷新动作写成函数
  • 课后练习:

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);

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

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

可以看到明显的闪烁。
如果只需要数码管从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;
		}

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

如果待显示数据无规律,则需要新建一个数组选择每个位需要显示的内容!
新建数组: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;
		}

实战小练:简易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

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

u8 Show_Tab[8] = {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[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、且按暂停后没有重新从0启动,刚开始的时候没有把数据清0,修改代码:

if( RUN_State == 0 )
					TimCount = 0;

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几,就可以了

在这里插入图片描述

编译烧录,显示: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;
                    }
				}

编译后运行,按下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;
	}
}

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

#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.初始状态显示00 - 00 - 00,分别作为时,分,秒;
2.每隔一秒钟,秒+1,一分钟,分+1,以此类推;
3.时间到达00 - 00 - 30的时候,蜂鸣响3秒钟表示闹钟。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/976554.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

追求数学之美

菲尔兹奖得主玛丽安米尔札哈尼说过:“只有在那些最有耐心的信徒面前,数学才会展现出它美丽的一面。”她的意思是,数学之美的绽放通常需要一定的时间。有时你需要费上一番功夫才能欣赏到建筑的美。数学的美也是这样,只要你拥有足够…

FHE 嵌合 MHE

参考文献: [NW96] Nisan N, Wigderson A. Lower bounds on arithmetic circuits via partial derivatives[J]. Computational complexity, 1996, 6: 217-234. Cites “M. Ben-Or, Private communication”.[Gen09] Gentry C. A fully homomorphic encryption schem…

基于32位单片机的感应灯解决方案

感应灯是一种常见照明灯,提起感应灯,相信大家并不陌生, 它在一些公共场所、卫生间或者走廊等场所,使用的较为广泛,同时它使用起来也较为方便省电。“人来灯亮,人走灯灭”的特性,使他们在部分场景…

利用Python和pandas分析瑞幸和茅台联名咖啡的市场策略

金融数据分析在投资决策和市场制定策略中发挥了至关重要的作用,而品牌价值分析是市场营销中的一个环节,它可以帮助企业了解其品牌在市场中的地位和价值,刚好最近瑞幸和茅台联名咖啡是近期备受关注的合作咖啡项目,其联名咖啡产品在…

安防监控/视频存储/视频汇聚平台EasyCVR如何接入智能分析网关V4?

TSINGSEE青犀AI边缘计算网关硬件 —— 智能分析网关目前有5个版本:V1、V2、V3、V4、V5,每个版本都能实现对监控视频的智能识别和分析,支持抓拍、记录、告警等,每个版本在算法模型及性能配置上略有不同。硬件可实现的AI检测包括&am…

c++中的对齐问题

c中的对齐问题 需要对齐的原因 尽管内存是以字节为单位,但是大部分处理器并不是按字节块来存取内存的.它一般会以双字节,四字节,8字节,16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度. 现在考虑4字节存取粒度的处理器取in…

java八股文面试[JVM]——引用计数、可达性分析

要想进行垃圾回收,得先知道什么样的对象是垃圾。 引用计数法 对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾,如果一个对象没有任何指针对其引用,它就是垃圾。 引用计数法在对象头处维护一…

论坛系统公共组件部分

1.在Java⽬录下创建包,在Resources⽬录下创建⽂件夹,结构如下 ├─java # java⽂件区 │ └─com │ └─example │ └─demo │ ├─common # 公共类 │ ├─config # 配置…

DBeaver新建Elasticsearch连接报错Error downloading driver libraries解决方案

1.软件版本背景 DBeaver Ultimate 22.1.0 elasticsearch 7.10 可能因DBeaver的版本不同,导致页面略有差异,请自行脑补! 2.新建数据库(Elasticsearch)连接 点击新建数据库连接按钮 选择Elasticsearch 填写相关配置…

javaScript:节点操作

目录 前言 常用的节点操作 innerHTML 的两个弊端(补充) createElement(标签名)使用dom方法创建一个元素 父元素.appendChild(子元素) 添加到父元素 注意 指定插入 父元素.insertBefore(要添加的元素,父元素中的指定子元素) 注意&…

Android Studio 汉化

一、汉化: 查看版本号,查看Android Studio版本,根据版本下载对应的汉化包。例如我的是223。 下载汉化包: 中文语言包下载地址 找到对应的版本 回到Android Studio 1、进入设置 2、从磁盘安装插件 3、选择下载好的包点击OK 4、…

kibana设置ILM

kibana设置ILM 1. 背景 kibana version: v7.9.3 2. 设置ILM 2.1 创建索引生命周期策略 2.1.1 热阶段 首先需要先创建索引生命周期策略,在索引模板中可以引用创建好的索引生命周期策略。 策略名称: 引用该策略是需要用,例如设置为&#…

【LeetCode75】第四十七题 迷宫中离入口最近的出口

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目给我们一个数组形式的地图,让我们找出离入口最近的出口,出口就是地图的边界。 那么这道题可以使用DFS也可以…

Vue+elementUI 导出word打印

import JSZipUtils from "jszip-utils"; import JSZip from "pizzip"; import Docxtemplater from "docxtemplater"; npm安装以上依赖 首先维护个word模板 导出方法 //导出wordskipOutWord(row) {var printData rowconst data JSON.parse(JS…

作品集(陆续上传中)

智能家居---不断完善中 家居-CSDN直播 家居 语音刷抖音 --- 基于串口和adb 基于守护进程的语音刷抖音-CSDN直播 基于守护进程的语音刷抖音 海天一色项目 --- 船舶靠港零碳排加热器 FTP云盘 --- 多进程和socket FTP云盘-CSDN直播 FTP云盘

JS 删除数组中的第一项和最后一项

JS 删除数组中的第一项和最后一项 需求分析 需求 JS 删除数组中的第一项和最后一项 分析 删除数组第一个元素 array.shift() /* 1. shift() 方法用于把数组的第一个元素从其中删除。 2. 返回值: 被删除的元素(即数组原来的第一个元素的值)。…

Unity——LitJSON的安装

一、LitJSON介绍 特点 LitJSON是一个轻量级的C# JSON库,用于在Unity游戏开发中进行JSON数据的序列化和反序列化操作。它提供了简单而高效的接口,帮助开发者处理JSON数据。 以下是LitJSON库的一些主要特点和功能: 1. 高性能:Lit…

死锁是什么?死锁的字节码指令了解?

用幽默浅显的言语来说死锁 半生:我已经拿到了机考的第一名,就差笔试第一名了 小一:我已经拿到了笔试的第一名,就差机考第一名了 面试官:我很看好你俩,继续"干", 同时拿到2个的第一名才能拿到offe…

华为云云服务器评测|基于云服务器的minio部署手册

华为云云服务器评测|基于云服务器的minio部署手册 【软件安装版本】【集群安装(是)(否)】 版本 创建人 修改人 创建时间 备注 1.0 jz jz 2023.9.2 minio华为云耀服务器 一. 部署规划与架构 1. 规…

降低LLM的幻觉风险:实用策略与技术

一、前言 近年来,大语言模型的快速发展为构建更智能和更人性化的AI系统提供了很多可能性。像GPT-3.5、GPT-4、Bard、Claude 2和LLaMa 2等大语言模型 (LLM) 在个人助理或聊天机器人应用领域展示了强大的潜力,可以生成流畅而令人惊叹的响应来回答用户的问…