【蓝桥杯-单片机】基于定时器的倒计时程序设计

基于定时器的倒计时程序

题目如下所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实现过程中遇到的一些问题

01 如何改变Seg_Buf数组的值数码管总是一致地显示0 1 2 3 4 5

首先这个问题不是在main.c中关于数码管显示部分的逻辑错误,就是发生在数码管的底层错误。
检查了逻辑部分,没有发现问题
转而查找底层上面的错误。
底层的Seg.c是这样写的:

#include <Seg.h>unsigned char code Seg_Dula[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f ,0x00};
unsigned char code Seg_Wela[] = {0xfe ,0xfd ,0xfb,0xf7,0xef,0xdf};void Seg_Disp(unsigned char wela,dala)
{//消影P0 = 0x00;P2_6 = 1;P2_6 = 0;P0 = Seg_Wela[wela];P2_7 = 1;P2_7 = 0;P0 = Seg_Dula[wela];//问题出现在这里!P2_6 = 1;P2_6 = 0;
}

果然被我发现了,段选数组的索引写错了,写成了wela,这样无论如何,数码管的每一位都会按照传入的wela来显示(wela在main函数中即Seg_Pos,这个变量在0-5范围内循环)

	if(++Seg_Pos == 6) Seg_Pos = 0;Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);

02 按下设置按键KEY4设置好倒计时参数后,该参数应该在什么时机传输给Time_Count倒计时变量用于倒计时呢?

(1)设置完就对Time_Count赋值

//按键处理函数Key_Proc()
void Key_Proc()
{if(Key_Slow_Down)return;Key_Slow_Down = 1;//按键减速程序//这三行要背下来Key_Val = Key_Read();//读取按下的键码值Key_Down = Key_Val &(Key_Val ^ Key_Old);//捕获下降沿Key_Old = Key_Val;//辅助扫描switch(Key_Down){//框架先搭好,内容先不写case 1:if(Seg_Mode == 0) System_Flag = 1;break;case 3:Seg_Mode ^= 1;break;case 4:if(Seg_Mode == 1){if(++Set_Dat_Index == 3) Set_Dat_Index = 0;Time_Count = Set_Dat[Set_Dat_Index];//设置完就对Time_Count赋值!!!!!!}break;case 2:if(Seg_Mode == 0) Time_Count = Set_Dat[Set_Dat_Index];break;}
}

如果这样的话,会导致切换回显示模式后已经倒计时了一段时间了,不是从设置的值开始倒计时的。想要切换回显示模式从设置的值开始倒计时,需要在切换回显示模式后,再对Time_Count赋值。

(2)在切换成显示模式后对Time_Count赋值

//按键处理函数Key_Proc()
void Key_Proc()
{if(Key_Slow_Down)return;Key_Slow_Down = 1;//按键减速程序//这三行要背下来Key_Val = Key_Read();//读取按下的键码值Key_Down = Key_Val &(Key_Val ^ Key_Old);//捕获下降沿Key_Old = Key_Val;//辅助扫描switch(Key_Down){//框架先搭好,内容先不写case 1:if(Seg_Mode == 0) System_Flag = 1;break;case 3:Seg_Mode ^= 1;if(Seg_Mode == 0)Time_Count = Set_Dat[Set_Dat_Index]  ;//切换到显示界面再对Time_Count赋值!!!!!!break;case 4:if(Seg_Mode == 1){if(++Set_Dat_Index == 3) Set_Dat_Index = 0;//Time_Count = Set_Dat[Set_Dat_Index];}break;case 2:if(Seg_Mode == 0) Time_Count = Set_Dat[Set_Dat_Index];break;}
}

03 倒计时到0之后为什么数码管又变成55再倒计时呢?

这是因为Time_Count–,没有对其作任何限制的情况下,Time_Count减为0之后会再从255开始减递减(Time_Count是一个unsigned char类型的变量,该变量8bit,变量可以表示的范围为0-255)。而我们只让数码管显示到十位数,因此我们看到的就是数码管从55开始倒计时。

对中断服务函数代码作如下修改:

void Timer0Server() interrupt 1
{//定时器的初值一定要记得从上面复制过来TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值if(++Key_Slow_Down == 10) Key_Slow_Down = 0;if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;if(++Seg_Pos == 6) Seg_Pos = 0;Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//模板以外的东西if(System_Flag == 1)//倒计时开始{if(++Timer_1000ms == 1000){Timer_1000ms = 0;Time_Count--;//相当于1s中减少一次(倒计时一次)if(Time_Count==255) Time_Count=0;//修改代码!!!!!!!!!!!!!!!!!!}}
}

修改代码之后数码管会停在00的位置。

在这里插入图片描述

至此,所有代码如下所示(不包含设置参数以1s为周期闪烁):

//头文件声明
#include <REGX52.H>
#include <Key.h>
#include <Seg.h>//动态数码管会用到数码管的底层?//变量声明
unsigned char Key_Slow_Down;//按键减速专用变量 10ms
unsigned char Key_Val,Key_Down,Key_Old;//按键扫描专用变量unsigned int Seg_Slow_Down;//数码管减速专用变量 500mschar:0-255.char不够用//动态数码管
unsigned char Seg_Pos;//数码管扫描变量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组unsigned char Seg_Mode;//数码管显示页面 0-显示 1-设置,默认为0
unsigned int Timer_1000ms;//1000ms标志位
unsigned char Time_Count = 30;//倒计时变量//按键
bit System_Flag;//0-暂停 1-开始倒计时unsigned char Set_Dat[3] = {15,30,60};//设置参数储存数组
unsigned char Set_Dat_Index = 1;//LED点亮标志位
bit Timer0Flag;//0-倒计时没有到0;1-倒计时到0//按键处理函数Key_Proc()
void Key_Proc()
{if(Key_Slow_Down)return;Key_Slow_Down = 1;//按键减速程序//这三行要背下来Key_Val = Key_Read();//读取按下的键码值Key_Down = Key_Val &(Key_Val ^ Key_Old);//捕获下降沿Key_Old = Key_Val;//辅助扫描switch(Key_Down){//框架先搭好,内容先不写case 1:if(Seg_Mode == 0) System_Flag = 1;break;case 3:Seg_Mode ^= 1;//if(Seg_Mode == 0)//Time_Count = Set_Dat[Set_Dat_Index];break;case 4:if(Seg_Mode == 1){if(++Set_Dat_Index == 3) Set_Dat_Index = 0;Time_Count = Set_Dat[Set_Dat_Index];}break;case 2:if(Seg_Mode == 0) Time_Count = Set_Dat[Set_Dat_Index];break;}
}//信息显示函数Seg_Proc()
void Seg_Proc()
{if(Seg_Slow_Down)return;Seg_Slow_Down = 1;//数码管减速程序//现在没有要显示的信息,这里先空着。(模板以外的东西)Seg_Buf[0] = Seg_Mode + 1;if(Seg_Mode == 0)//显示模式{Seg_Buf[4] = Time_Count/10%10;//可以写成Time_Count/10嘛Seg_Buf[5] = Time_Count%10;}else//处于设置模式{Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;}}/* 其他显示函数 */
//Led_Proc()
void Led_Proc()
{if(Time_Count == 0){P1 = 0x00;//LED全亮P2_3 = 0;//蜂鸣器使能}else{P1 = 0xff;//LED全灭P2_3 = 1;//蜂鸣器关闭}
}//Timer0Init()定时器0的中断初始化函数
void Timer0Init(void)		//1毫秒@12.000MHz
{//AUXR &= 0x7F;		//定时器时钟12T模式TMOD &= 0xF0;		//设置定时器模式TMOD |= 0x01;		//设置定时器模式TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值TF0 = 0;		//清除TF0标志TR0 = 1;		//定时器0开始计时//复制过来之后不要忘记加上两句话ET0 = 1;EA = 1;
}//Server定时器0的中断服务函数
//a++是先进行取值,后进行自增。++a是先进行自增,后进行取值
void Timer0Server() interrupt 1
{//定时器的初值一定要记得从上面复制过来TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值if(++Key_Slow_Down == 10) Key_Slow_Down = 0;if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;if(++Seg_Pos == 6) Seg_Pos = 0;Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//模板以外的东西if(System_Flag == 1)//倒计时开始{if(++Timer_1000ms == 1000){Timer_1000ms = 0;Time_Count--;//相当于1s中减少一次(倒计时一次)if(Time_Count==255) Time_Count=0;}}
}
//主函数
void main()
{Timer0Init();//上电时立即调用定时器初始化函数while(1){//三大处理单元:按键、数码管、LEDKey_Proc();Seg_Proc();Led_Proc();}
}

04 如何实现设置参数以1s为周期闪烁?

(1)在变量声明区新增两个变量:
注:以1s为周期闪烁,即500ms亮,500ms灭。

unsigned int Timer_500ms;//500ms标志位
bit Seg_Flag;//数码管标志位,即控制数码管的亮灭

(2)在中断服务函数中

	if(++Timer_500ms == 500){Timer_500ms = 0;Seg_Flag ^= 1;//因为默认值为0,只需要对其取反即可,不需要赋值,可以用^=1来对一个变量取反}

(3)在数码管显示函数中

//信息显示函数Seg_Proc()
void Seg_Proc()
{if(Seg_Slow_Down)return;Seg_Slow_Down = 1;//数码管减速程序//现在没有要显示的信息,这里先空着。(模板以外的东西)Seg_Buf[0] = Seg_Mode + 1;if(Seg_Mode == 0)//显示模式{Seg_Buf[4] = Time_Count/10%10;//可以写成Time_Count/10嘛Seg_Buf[5] = Time_Count%10;}else//处于设置模式{
//		Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;
//		Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;
//修改如下:if(Seg_Flag == 1){Seg_Buf[4] = 10;Seg_Buf[5] = 10;}else{Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;}}
}

05 最终版代码

//头文件声明
#include <REGX52.H>
#include <Key.h>
#include <Seg.h>//动态数码管会用到数码管的底层?//变量声明
unsigned char Key_Slow_Down;//按键减速专用变量 10ms
unsigned char Key_Val,Key_Down,Key_Old;//按键扫描专用变量unsigned int Seg_Slow_Down;//数码管减速专用变量 500mschar:0-255.char不够用//动态数码管
unsigned char Seg_Pos;//数码管扫描变量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组unsigned char Seg_Mode;//数码管显示页面 0-显示 1-设置,默认为0
unsigned int Timer_1000ms;//1000ms标志位
unsigned char Time_Count = 30;//倒计时变量//按键
bit System_Flag;//0-暂停 1-开始倒计时unsigned char Set_Dat[3] = {15,30,60};//设置参数储存数组
unsigned char Set_Dat_Index = 1;//设置参数闪烁
unsigned int Timer_500ms;//500ms标志位
bit Seg_Flag;//数码管标志位//LED点亮标志位
bit Timer0Flag;//0-倒计时没有到0;1-倒计时到0//按键处理函数Key_Proc()
void Key_Proc()
{if(Key_Slow_Down)return;Key_Slow_Down = 1;//按键减速程序//这三行要背下来Key_Val = Key_Read();//读取按下的键码值Key_Down = Key_Val &(Key_Val ^ Key_Old);//捕获下降沿Key_Old = Key_Val;//辅助扫描switch(Key_Down){//框架先搭好,内容先不写case 1:if(Seg_Mode == 0) System_Flag = 1;break;case 3:Seg_Mode ^= 1;//if(Seg_Mode == 0)//Time_Count = Set_Dat[Set_Dat_Index];break;case 4:if(Seg_Mode == 1){if(++Set_Dat_Index == 3) Set_Dat_Index = 0;Time_Count = Set_Dat[Set_Dat_Index];}break;case 2:if(Seg_Mode == 0) Time_Count = Set_Dat[Set_Dat_Index];break;}
}//信息显示函数Seg_Proc()
void Seg_Proc()
{if(Seg_Slow_Down)return;Seg_Slow_Down = 1;//数码管减速程序//现在没有要显示的信息,这里先空着。(模板以外的东西)Seg_Buf[0] = Seg_Mode + 1;if(Seg_Mode == 0)//显示模式{Seg_Buf[4] = Time_Count/10%10;//可以写成Time_Count/10嘛Seg_Buf[5] = Time_Count%10;}else//处于设置模式{
//		Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;
//		Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;if(Seg_Flag == 1){Seg_Buf[4] = 10;Seg_Buf[5] = 10;}else{Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;}}
}/* 其他显示函数 */
//Led_Proc()
void Led_Proc()
{if(Time_Count == 0){P1 = 0x00;//LED全亮P2_3 = 0;//蜂鸣器使能}else{P1 = 0xff;//LED全灭P2_3 = 1;//蜂鸣器关闭}
}//Timer0Init()定时器0的中断初始化函数
void Timer0Init(void)		//1毫秒@12.000MHz
{//AUXR &= 0x7F;		//定时器时钟12T模式TMOD &= 0xF0;		//设置定时器模式TMOD |= 0x01;		//设置定时器模式TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值TF0 = 0;		//清除TF0标志TR0 = 1;		//定时器0开始计时//复制过来之后不要忘记加上两句话ET0 = 1;EA = 1;
}//Server定时器0的中断服务函数
//a++是先进行取值,后进行自增。++a是先进行自增,后进行取值
void Timer0Server() interrupt 1
{//定时器的初值一定要记得从上面复制过来TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值if(++Key_Slow_Down == 10) Key_Slow_Down = 0;if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;if(++Seg_Pos == 6) Seg_Pos = 0;Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//模板以外的东西if(System_Flag == 1)//倒计时开始{if(++Timer_1000ms == 1000){Timer_1000ms = 0;Time_Count--;//相当于1s中减少一次(倒计时一次)if(Time_Count==255) Time_Count=0;}}if(++Timer_500ms == 500){Timer_500ms = 0;Seg_Flag ^= 1;//因为默认值为0,只需要对其取反即可,不需要赋值,可以用^=1来对一个变量取反}
}
//主函数
void main()
{Timer0Init();//上电时立即调用定时器初始化函数while(1){//三大处理单元:按键、数码管、LEDKey_Proc();Seg_Proc();Led_Proc();}
}

参考视频:https://www.bilibili.com/video/BV1TR4y1k7iz?p=6&vd_source=5af7b905774c79f1754cd4ab83975115

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++庖丁解牛】二叉搜索树(Binary Search Tree,BST)

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1. 二叉搜索树概念2. 二叉…

python框架的一加剧场管理系统的设计与实现flask-django-nodejs-php

本文讲述了一加剧场管理系统。结合电子管理系统的特点&#xff0c;分析了一加剧场管理系统的背景&#xff0c;给出了一加剧场管理系统实现的设计方案。 本论文主要完成不同用户的权限划分&#xff0c;不同用户具有不同权限的操作功能&#xff0c;在用户模块&#xff0c;主要有用…

letcode::根据二叉树创建字符串

根据二叉树创建字符串 题目描述&#xff1a; 给你二叉树的根节点 root &#xff0c;请你采用前序遍历的方式&#xff0c;将二叉树转化为一个由括号和整数组成的字符串&#xff0c;返回构造出的字符串。 空节点使用一对空括号对 “()” 表示&#xff0c;转化后需要省略所有不影…

一文读懂SDRAM内存模组与基本概念

本文可以了解什么&#xff1f; DDR-DDR4内存模块的差异以及对比&#xff1b;逻辑BANK的概念与定义&#xff1b;芯片的位宽的解释。 下图是DDR3的PHY IP Core的定义规范。 DDR-DDR4的物理结构差异 首先&#xff0c;我们来对比一下DDR, DDR2, DDR3 SDRAM, and DDR4 SDRAM物理…

cyclictest 交叉编译报错---rt_numa.h:18:10: fatal error: numa.h: 没有那个文件或目录

cyclictest 主要是用于测试系统延时&#xff0c;进而判断系统的实时性 使用版本 rt-tests-2.6.tar.gz numactl v2.0.16 问题 编译时&#xff0c;需要先编译 numactl &#xff0c;不然会有以下报错&#xff1a; arm-linux-gnueabihf-gcc -D VERSION2.6 -c src/cyclictest/c…

FPGA——DDR3的IP核

FPGA——DDR3的ip核 IP核配置基于MIG核代码基于AXI接口的DDR3 IP核配置 1 2 3 4 5 6 基于MIG核代码 控制MIG核的信号进行读写 module MIG_APP_Drive(input i_ui_clk ,input i_ui_rst ,input init_calib_…

数字孪生底层技术框架

数字孪生是一种将现实世界中的物理实体、过程或系统数字化并映射到计算机模型中的方法。它在数学建模与仿真方面具有重要作用&#xff0c;为了实现数字孪生&#xff0c;以下是一些底层技术框架和方法&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业…

[OpenCV学习笔记]获取鼠标处图像的坐标和像素值

目录 1、介绍2、效果展示3、代码实现4、源码展示 1、介绍 实现获取鼠标点击处的图像的坐标和像素值&#xff0c;灰度图显示其灰度值&#xff0c;RGB图显示rgb的值。 OpenCV获取灰度值及彩色像素值的方法&#xff1a; //灰度图像&#xff1a; image.at<uchar>(j, i) //j…

牛客NC111 最大数【中等 贪心、排序 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/fc897457408f4bbe9d3f87588f497729 思路 贪心解法对于 numsnums 中的任意两个值 aa 和 bb&#xff0c;我们无法直接从常规角度上确定其大小/先后关系。但我们可以根据「结果」来决定 aa 和 bb 的排序关系&#…

链表oj测试题(上)

链表的申明&#xff1a; struct ListNode {int val;struct ListNode* next; }; 1.题1 删除指定元素 例如&#xff1a;链表1 2 6 3 4 5 6&#xff0c;然后选择删除元素6&#xff0c;返回的链表为1 2 3 4 5 。 代码演示&#xff1a; typedef struct ListNode ListNode;List…

【C++航海王:追寻罗杰的编程之路】stack

目录 1 -> stack的介绍和使用 1.1 -> stack的介绍 1.2 -> stack的使用 1.3 -> stack的模拟实现 1 -> stack的介绍和使用 1.1 -> stack的介绍 stack的文档介绍 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c…

yolov6实现遥感影像目标识别|以DIOR数据集为例

1 目标检测是计算机视觉领域中的一项重要任务&#xff0c;它的目标是在图像或视频中检测出物体的位置和类别。YOLO&#xff08;You Only Look Once&#xff09;是一系列经典的目标检测算法&#xff0c;最初由Joseph Redmon等人于2016年提出。YOLO算法具有快速、简单、端到端的特…

Java集合Collection之LinkedList

LinkeList LinkedList&#xff08;双向链表&#xff09;是一种常见的线性数据结构&#xff0c;但是并不会按线性的顺序存储数据。它由一系列节点组成&#xff0c;每个节点包含数据部分和一个指向下一个节点的引用。相比于数组&#xff0c;链表具有动态大小、插入和删除效率高的…

【计算机视觉】Gaussian Splatting源码解读补充(二)

第一部分 本文是对学习笔记之——3D Gaussian Splatting源码解读的补充&#xff0c;并订正了一些错误。 目录 三、相机相关scene/cameras.py&#xff1a;class Camera 四、前向传播&#xff08;渲染&#xff09;&#xff1a;submodules/diff-gaussian-rasterization/cuda_rast…

ES进程除了kill之外,有什么优雅关闭的方式吗?

问题 Linux环境中&#xff0c;Elasticsearch 8的进程除了kill之外&#xff0c;有什么优雅关闭的方式吗&#xff1f; 具体实施方式 在Linux环境中&#xff0c;Elasticsearch&#xff08;ES&#xff09;进程可以通过多种方式实现优雅关闭&#xff0c;这种方式允许它完成必要的…

【Python音视频技术】玩AI视频创作引发写Python音视频技术系列文章1---视频添加字幕

最近对视频创作感兴趣&#xff0c; 详情见之前写的几篇文章。 【AI应用】模仿爆款视频二次创作短视频操作步骤 【人工智能】AI数字人视频演示 【人工智能】AI视频二次创作演示 作为程序员出身的我&#xff0c;看到一些功能, 我都有猎奇的习惯&#xff0c; 想着自己用什么技…

【技术栈】Spring Cache 简化 Redis 缓存使用

​ SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习技术栈 个性签名&#xff1a;保留赤子之心也许是种幸运吧 ​ 本文封面由 凯楠&#x1f4f8; 友情提供 目录 本栏传送门 1. Spring Cache 介绍 2. Spring Cache 常用注解 注&#xff1a;手机端浏览本文章…

Spark与flink计算引擎工作原理

Spark是大批量分布式计算引擎框架&#xff0c;scale语言开发的&#xff0c;核心技术是弹性分布式数据集&#xff08;RDD&#xff09;可以快速在内存中对数据集进行多次迭代&#xff0c;支持复杂的数据挖掘算法及图形计算算法&#xff0c;spark与Hadoop区别主要是spark多个作业之…

基于python+vue的stone音乐播放器的设计与实现flask-django-php-nodejs

随着我国经济的高速发展与人们生活水平的日益提高&#xff0c;人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下&#xff0c;人们更趋向于足不出户解决生活上的问题&#xff0c;stone音乐播放器展现了其蓬勃生命力和广阔的前景。与此同时&#xff0c;为解决用…

Yocto学习笔记1-下载与首次编译

Yocto学习笔记1-下载与首次编译 1、基础环境介绍2、注意点3、安装依赖3.1 yocto常规系统构建所需依赖库&#xff08;较全&#xff09;3.2 龙芯适配时的最小依赖库&#xff08;最小&#xff09; 4、下载4.1 通过git克隆4.2 查看所有远程分支4.3 签出一个长期支持的稳定版本4.4 查…