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

基于定时器的倒计时程序

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

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

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.mzph.cn/news/756865.shtml

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

相关文章

【重温设计模式】状态模式及其Java示例

状态模式的基本概念 在编程世界的大海中&#xff0c;各种设计模式就如同灯塔&#xff0c;为我们的代码编写指明方向。其中&#xff0c;状态模式是一种行为设计模式&#xff0c;它让你能在一个对象的内部状态改变时改变其行为&#xff0c;使得对象看起来就像改变了其类一样。这…

Git小乌龟安装及使用教程

一、Win7安装git 软件下载地址&#xff1a;git for windows 安装过程直接默认下一步&#xff0c;直到安装结束。 安装结束后重启一下。 安装完成后&#xff0c;在文件夹空白处右键出现以下几个标识&#xff0c;说明安装成功。 二、安装tortoise git&#xff08;乌龟git&…

分布式砖题

雪花算法 变动位数&#xff0c;性能佳&#xff0c;灵活调整bit位划分&#xff0c;灵活 zk 临时节点和watch机制实现注册中心 &#xff0c;数据都在内存&#xff0c;nio 多线程模型&#xff1b; cp注重一致性&#xff0c;集群数据不一致时集群不可用 数据一致性模型 cap 强…

图解CodeWhisperer的安装使用

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 &#x1f4d8; CodeWhisperer简介 &#…

力扣202. 快乐数

思路&#xff1a;用一个set记录是否重复出现过某值&#xff0c;是 则是无限循环&#xff0c;不可能还有1的情况&#xff0c;直接返回false; 否则一直处理生产新的数&#xff0c;直到为1&#xff1b; class Solution {public boolean isHappy(int n) {//set记录是否重复出现过某…

内存条@电脑支持的最大内存@升级内存硬件

文章目录 电脑支持的最大内存规格cpu官网查看支持的规格命令行查看脚本化 DDR内存LPDDR内存内存升级扩展&#x1f47a;插槽检查板载内存SPD内存厂商其他 内存参数&#x1f47a;性能指标使用软件查看更多内存相关的软件工具 电脑支持的最大内存规格 确认电脑最大支持内存大小和频…

自动化部署利器:Jenkins+Gitlab助力Springboot项目快速上线,实现持续集成与持续交付!

Jenkins 能干什么 来自官网 官网 Jenkins怎么用【Linux版】 下载 war包 本机为Java8 选择Jenkins版本为2.289.1 注意&#xff1a; 如果是Java8 尽量和我的Jenkins版本保持一致哈&#xff01;后面可能会遇到各种坑。 把下载好的war放到Linux服务器的某一个目录下 启动war …

python沧州市人民医院患者就诊信息管理系统flask-django-nodejs-php

因此&#xff0c;本论文旨在探讨人民医院患者就诊信息管理系统的建设与实施&#xff0c;分析其在医疗服务中的作用和意义&#xff0c;进一步探讨如何优化医院信息系统和提高医疗服务质量。通过对人民医院患者就诊信息管理系统的研究&#xff0c;可以为医院信息化建设提供借鉴和…

面试笔记——Redis(双写一致、持久化)

双写一致 双写一致性&#xff1a; 当修改了数据库中的数据&#xff0c;也要更新缓存的数据&#xff0c;使缓存和数据库中的数据保持一致。 相关问题&#xff1a;使用Redis作为缓存&#xff0c;mysql的数据如何与Redis进行同步&#xff1f;——双写一致性问题 回答时&#xff0…

Vue 计算属性和监视属性

Vue 计算属性和监视属性 computed computed 计算属性 规则&#xff1a; 用已有的属性计算不存在的属性默认调用一次get()只有值不发生改变的时候才可以使用简写&#xff08;函数&#xff09;&#xff1b;值发生改变 使用对象式写法&#xff0c;才可以配置set()方法底层原理使…

[项目设计]基于websocket实现网络对战五子棋

项目介绍 该项目旨在实现一个网页端的在线五子棋&#xff0c;将实现登陆、好友、房间、对战、观战、聊天等功能 完成该项目需要了解C、数据库MySQL、基础前端HTML/CSS/JS/Ajax、网络协议WebSocket 项目源码&#xff1a;azhe1/online_gobang - 码云 - 开源中国 (gitee.com) …

R语言实现多要素偏相关分析

偏相关分析是指当两个变量同时与第三个变量相关时&#xff0c;将第三个变量的影响剔除&#xff0c;只分析另外两个变量之间相关程度的过程&#xff0c;判定指标是相关系数的R值。 在GIS中&#xff0c;偏相关分析也十分常见&#xff0c;我们经常需要分析某一个指数与相关环境参…

网络基础知识-DNS与DHCP+网络规划与设计故障诊断+嵌入式系统设计师备考笔记

0、前言 本专栏为个人备考软考嵌入式系统设计师的复习笔记&#xff0c;未经本人许可&#xff0c;请勿转载&#xff0c;如发现本笔记内容的错误还望各位不吝赐教&#xff08;笔记内容可能有误怕产生错误引导&#xff09;。 本章的主要内容见下图&#xff1a; 本章知识和计算机…

MNN createSession 之创建流水线后端(四)

系列文章目录 MNN createFromBuffer&#xff08;一&#xff09; MNN createRuntime&#xff08;二&#xff09; MNN createSession 之 Schedule&#xff08;三&#xff09; MNN createSession 之创建流水线后端&#xff08;四&#xff09; MNN Session::resize 之流水线编码&am…

B站python爬虫课程笔记(Q16-)

下面是学习的网址&#xff1a; ​​​​​​【Python爬虫】 16、捕捉异常try&except语句的一些问题 1&#xff09;一些常见的异常类型 IndexError索引错误ZeroDivisionError除零错误FileNotFindError找不到文件错误TypeError类型错误KeyError键错误ValueError值错误Ind…

微信小程序 canvas层级过高覆盖原生组件

一、背景 微信小程序中使用signature第三方插件完成签名效果&#xff0c;但真机调试时发现canvas层级过高遮挡了按钮 二、具体问题 问题原因&#xff1a;签名后点击按钮无法生效 问题代码&#xff1a; <template><view class"sign_page" v-cloak>&l…

51单片机学习笔记7 串转并操作方法

51单片机学习笔记7 串转并操作方法 一、串转并操作简介二、74HC595介绍1. **功能**&#xff1a;2. **引脚**&#xff1a;3. **工作原理**&#xff1a;4. 开发板原理图&#xff08;1&#xff09;8*8 LED点阵&#xff1a;&#xff08;2&#xff09;74HC595 串转并&#xff1a; 三…

蓝桥杯刷题|03普及-真题

[蓝桥杯 2017 省 B] k 倍区间 题目描述 给定一个长度为 N 的数列&#xff0c;​,,⋯&#xff0c;如果其中一段连续的子序列 ​,,⋯ (i≤j) 之和是 K 的倍数&#xff0c;我们就称这个区间 [i,j] 是 K 倍区间。 你能求出数列中总共有多少个 K 倍区间吗&#xff1f; 输入格式 …

Spark 3.5.0 特性速览

介绍 Spark 3系列已经发布了第六版3.5.0&#xff0c;目前最新3.5.1。 使用最广泛的大数据可扩展计算引擎。数以千计的公司&#xff0c;包括 80% 的财富 500 强企业&#xff0c;都在使用 Apache Spark。来自业界和学术界的 2000 多名开源项目贡献者。 Apache Spark 3.5.0 是…

抖音视频爬虫提取工具界面|视频批量下载软件

抖音视频爬虫界面解析 一&#xff1a;概述 抖音视频爬虫是一款功能强大的工具&#xff0c;主要提供关键词批量提取视频和单独视频提取的功能&#xff0c;并支持提取后的视频下载操作。 二&#xff1a;功能解析 2.1&#xff1a;关键词批量提取视频的解析 用户可以通过输入关键…