单片机学习笔记---按键控制LED流水灯模式定时器时钟

目录

代码讲解

初始化函数

1.定时器部分的配置步骤

第一步,对TMOD的赋值

第二步,给TF0赋值

第三步,给TR0赋值开启定时器

第四步,给TL0和TH0赋初值

2.中断系统部分的配置步骤

第一步,给ET0赋值

第二步,给EA赋值

第三步,给PT0赋值

中断函数

定时器计算器生成代码工具

按键控制流水灯代码演示

时钟代码演示


看这一节之前一定要先依次看完这前三节:

单片机学习笔记---中断系统(含外部中断)-CSDN博客

单片机学习笔记---定时器/计数器(简述版!)-CSDN博客

单片机学习笔记---定时器和中断系统如何连起来工作-CSDN博客

代码讲解

这一节开始代码演示。

本节代码主要演示的是这个工作路线:

新创建一个工程,写上框架:

一,初始化函数

现在来写一个配置定时器和中断系统的函数

1.定时器部分的配置步骤

第一步,对TMOD的赋值

首先是对TMOD的赋值,TMOD的寄存器,我们前面已经说了,它是用来确定我们定时器的工作方式,像里面包含了T0和T1这两个定时器的工作方式,那你使用的是T0或者是T1,那就对这个TMOD的高4位或者是低4位进行赋值。

我们给TMOD赋值0x01,高四位它是0,说明我们现在使用的是低4位,它低四位是用于定时器0的管控,定时机1是高四位来控制的。

我们先不管定时器1,先看定时器0,所以高四位赋值0,低四位赋值1,也就是T1=0,T0=1的意思

那定时器0低4位是0001,对应的寄存器的值是0001

最后八位赋值成0000 0001

以上GATE设置为0,说明定时器的启动是通过TR0来控制的;

然后这个C/T设置为0,说明它的工作与T模式,也就是定时器模式;

然后,M1和M0=01,01的话是工作方式1,也就是16位定时计数器。

于是写TMOD=0x01

所以,我们通过这种设置可以知道我们定时器它处于定时器0,并且是16位,方式1,而且GATE是0可以直接通过TCON中的TR0来进行启动。

                

这样我们就完成了工作流程图中的这一部分的配置:

第二步,给TF0赋值

根据流程图,我们现在需要给TF0赋值:

先补充一个概念知识:

不可位寻址VS可位寻址:

不可位寻址的寄存器只能整体赋值;

可位寻址的寄存器可以对它其中的每一位单独赋值。

由于TCON是可位寻址的,所以我们可以单独赋值。

上图中TF1和TR1是定时器1的,我们不管。

我们可以单独看定时器0中的TF0和TR0。

TF0是定时器T0溢出中断标志,我们给它赋值0,因为一旦等于1之后,它就产生中断。我们先给TF0清零是为了防止还没有配置好就产生中断。这一步没有的话也不会产生特别大的影响。

第三步,给TR0赋值开启定时器

根据流程图,我们要配置TR0

由于GATE位等于0了,所以开启定时器主要取决于TR0,所以就写TR0=1;如果不知道为什么TR0=1的话请看上一节解释。

第四步,给TL0和TH0赋初值

之前第一步的时候我们只是选择了方式1,即选择16个位的寄存器存放初值,现在我们要来给这16个位的寄存器赋初值。

我们怎么让它每隔1毫秒产生中断呢?怎么定时呢?

我们前几节提到过,这个计数器的计数范围是0~65535,每隔一微秒(前面定时器那节已经说过12Mhz的晶振机器周期是1微秒),计数加1,总共定时时间是65535微秒,那我们怎样让它计1秒呢?

每隔1毫秒,让它产生中断每一次中断之后,我们再来计数,中断1000次的时候,就是1s。

时间换算:

       1s【秒】 = 1000ms【毫秒】
  1ms【毫秒】 = 1000μs【微秒】
   1μs【微秒】 = 1000ns【纳秒】
  1ns 【纳秒】= 1000ps【皮秒】

首先我们先给它定一毫秒产生中断。

如果一开始给它赋值64535,那64535离计数器溢出差值1000(微秒),所以计时时间为1ms。

那么我们想要64535这个初值给T0定时器,首先将64535换算成二进制给到T0的高八位TH0和低八位TL0(TH0和TL0都是八个位的寄存器,只能存放256

所以我们可以这样赋值:

为什么这样写就可以把64535的高八位和低八位取出来呢?

因为64535在寄存器当中的数据是十六位的,

我们可以类比一下十进制,十进制的取值范围是0~99,正好100个数,比如说123这个数,我们想要取出它的最高位和它的余数,那么我们就可以123/100=1,123%100=23。

同理,八个位的寄存器的存放数值是256,想要取出64535十六进制的高八位和低八位和就可以写成64535/256=高八位,64535%256=低八位。

现在整个定时器部分就配置好了。

2.中断系统部分的配置步骤

第一步,给ET0赋值

ET0=1就打开开关

第二步,给EA赋值

把总中断打开EA=1

第三步,给PT0赋值

PT0默认等于0,但我们要写上

以上这样就配置完了,

这个子函数也就完成了,我们来调用一下。

到这里这个定时器就可以工作了,那定时器溢出之后,也就是闹钟响了之后,我们要干嘛呢?

二,中断函数

我们还要写一个子函数,让闹钟响了之后,要跳转到这个子函数来,执行中断任务。

为什么要写一个中断函数呢?

也就是定时器初始化之后,

过了一个毫秒while(1){},中断一过来,程序就会从while(1){}跳转到中断函数里面来,等中断函数执行完之后,程序再回到while(1)里面去。

其实我们是根据这个程序流程图的逻辑来写程序的:

主程序在执行的过程中来了一个中断,主程序就跳转到中断函数,等执行完中断再跳转会主函数中。

这个中断函数的形式是这样的:

前面定时器那一节讲过这个子函数的书写规则了,不懂的话可以去看看。

这里我们需要记住对应的中断号,芯片手册上也列出了中断号:

现在我们把这整个程序下载到单片机里面来验证一下。

现在看还是什么现象都没有的

怎么证明它的确是在执行这个函数了呢?

可以在中断函数里点亮一个灯看看

可以发现,到目前为止我们的主程序中还没有调用这个函数的。

如果中断真的过来了,那P2_0=0;这句代码肯定执行,它一执行,开发板上的这个灯就会点亮,所以我们先这样验证主程序是不是过来了,稍后再验证时间。

我们看到D1的确亮了。

这个中断函数根本没有执行,只是跟了一个尾巴(interrupt 1)定时器过来之后,它就点亮了,就说明程序真的跳转到这个地方来执行了。

定时器计算器生成代码工具

这里我们的代码还没有结束,先介绍一个非常好的方法可以省去我们的敲代码的时间!

在STC上找到定时器计算器。

可以看到这里有已经写的框架,我们只需要选择参数即可

根据我们选择的工作模式和开发板的资源设置正确的参数:

为什么选择定时器时钟是12T呢?

这里就是我们前面几节说的这里,我们这节主要选择的工作流程是12T。

怎么让它拨到6T呢?

只要在这里打勾就是6T模式,没有打勾就是12T模式,但是我们一般是用12T模式。

最后把设置好的代码复制下来

改造一下:

因为89系列没有AUXR这个寄存器,所以删掉这一行

然后这两句代码是因为TMOD=0x01这种写法只适合用TMOD的高四位或者低四位时。

当高四位和低四位同时应用的时候,因为TMOD是不可位寻址,最好是优化成:

TMOD&=0xF0;//表示把TMOD的低四位清零,高四位保持不变,TMOD&1111 0000

TMOD|=0x01;//表示把TMOD最低位置1,其他位保持不变

然后这两句写的和我们自己写的这两句不一样

我们自己写是这样:

其实我们写成的这样会有一微秒的差别。

可以验证一下它生成的这种写法是不是跟我们写的结果一样,

用计算机算一下

取整是252,转换成16进制就是FC

说明我们的写的和它生成的结果是一样的

再验证一下低四位:

余23

23换成16进制是17

说明我们配置的低四位比它生成的低四位少了1微秒

所以我们可以把自己写的这句代码改成+1这样:

可以直接用它生成的形式也可以!

然后他还缺少这三句,我们把自己写的加上

最后我们把代码优化成这样(分模块化来写),每一行代码几乎都有注释了,这里就不再赘述:

main.c文件:

Timer0.c文件:

Timer0.h文件:

下载后的效果:

D1在以1秒为间隔在闪烁

说明我们的定时器程序已经没有错误了。

按键控制流水灯代码演示

接下来开始演示按键控制流水灯的程序:

同样分文件来写,创建Key.c和Key.h文件

然后把之前矩阵键盘那一节写好的Delay.c和Delay.h文件复制到本节的程序文件中

然后再添加进来

然后main.c文件改成:

Timer0.h文件没变:

Timer0.c文件也没变:

Key.h文件

Key.c文件

运行后的效果:

LED正在以500ms位间隔向右移动,随便按下一个独立按键后,移动方向变为向左移动。

时钟代码演示

最后开始演示时钟的程序:

新创建一个工程

写上框架

然后把LCD1602调试工具那一节的Delay.c,Delay.h,LCD1602.c,LCD1602.h文件复制到刚刚新创建的工程文件里面来,然后点击添加。

添加进来

同样操作,再把本节前面按键控制流水灯的Timer.c和Timer.h文件添加进来

编译后无错误,但是有9个警告

嫌警告碍眼可以点击这里忽略警告

再次编译,无错误,无警告

然后怎么调用这些函数的话都在之前相关章节讲过了,不懂的伙伴去翻我的单片机专栏里的文章看看。这里就不再赘述。

添加进来的文件不用修改什么,直接看本节主程序main.c调用写好的代码,每一行代码基本都有注释。这里就不再赘述。

看看效果:

观察23:59:59再计一秒后开始进位,全部变成00:00:00

然后从1开始计:

以上就是本节全部的代码演示。

本节全部的源码都放在评论区了,自取!

有问题的欢迎评论区留言或者私信。

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

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

相关文章

Linux系统安全①iptables防火墙

目录 一.iptables防火墙概述 1.netfilter与iptables (1)netfilter (2)iptables 2.iptables防火墙默认规则表、链结构 二.iptables四表五链 1.四表 2.五链 3.总结 三.iptables的配置 1.安装 2.配置方法 (1…

PySpark(四)PySpark SQL、Catalyst优化器、Spark SQL的执行流程

目录 PySpark SQL 基础 SparkSession对象 DataFrame入门 DataFrame构建 DataFrame代码风格 DSL SQL SparkSQL Shuffle 分区数目 DataFrame数据写出 Spark UDF Catalyst优化器 Spark SQL的执行流程 PySpark SQL 基础 PySpark SQL与Hive的异同 Hive和Spark 均是:“分…

c语言动态数组的实现

动态数组是在程序运行时动态分配内存空间的数组,可以根据需要随时改变大小。在C语言中,动态数组通常通过指针和malloc函数来实现。 使用malloc函数动态分配内存空间: int *arr; int size 10; arr (int*)malloc(size * sizeof(int));使用r…

扩展鸿蒙textinput组件

扩展鸿蒙textinput组件,支持快速扩展展性,标题文本等,文本内容双向绑定、文本组件快速复用。 组件代码 /*** 单选文本*/ Component export default struct DiygwInput{//绑定的值Link value:string;//未选中图标State labelImg: Resource …

sql非查询知识点(增删改-crud没有r)

1.建库 create database database_name 2.使用该数据库 use database_name 3.建表 3.1普通建表 create table if not exists actor(actor_id smallint(5) not null primary key comment "主键id",first_name varchar(45) not null comment "名字",last…

挂耳式耳机什么牌子的好?年度最值得入手的挂耳式耳机推荐

近年来耳机市场发展迅猛,蓝牙耳机品类日益增多。而挂耳式耳机尤其火爆,得益于其出色的佩戴体验,赢得了众多消费者的青睐。市场上挂耳式耳机的品牌种类繁多,让许多消费者在选择时感到困惑,挂耳机耳机什么牌子的好&#…

详细了解ref和reactive.

这几天看到好多文章标题都是类似于: 不用 ref 的 xx 个理由不用 reactive 的 xx 个理由历数 ref 的 xx 宗罪 我就很不解,到底是什么原因导致有这两批人: 抵触 ref 的人抵触 reactive 的人 看了这些文章,我可以总结出他们的想法…

工作与生活平衡:在生活中寻找和谐

工作和生活是我们生活中不断交织的两个重要方面。对许多人来说,找到两者之间的完美平衡已经成为一个持久的挑战。然而,与其专注于平衡,更重要的是要认识到工作和生活并不是可以相互平衡的两个分离实体,而是一个相互影响的循环。正…

python的进程,线程、协程

python进程的实现 #coding:utf-8 from multiprocessing import Process import timedef run(name):print(%s is running % name)time.sleep(3)print(%s finished his run % name)if __name__ __main__:p Process(targetrun, args(XWenXiang,)) # 创建一个进程对象p.start()…

提高效率:如何利用易点易动设备管理系统优化设备移动巡检流程

在现代企业中,设备的移动巡检是一个重要的任务,涉及到设备的维护、保养和安全等方面。然而,传统的手动巡检方式存在着效率低、准确性不高等问题。为了解决这些问题,引入易点易动设备管理系统成为了一个值得考虑的选择。本文将介绍…

若依整合mybatis-plus

文章目录 1.注释掉原本的MybatisConfig2. 将mybatis的配置文件改为mybatis-plus文件 ##前言 出先下列异常: 请求地址’/prod-api/user’,发生未知异常. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ruoyi.web.mapper.Us…

如何在Linux上部署1Panel运维管理面板并实现无公网ip远程访问

文章目录 前言1. Linux 安装1Panel2. 安装cpolar内网穿透3. 配置1Panel公网访问地址4. 公网远程访问1Panel管理界面5. 固定1Panel公网地址 前言 1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。高效管理,通过 Web 端轻松管理 Linux 服务器,包括主机监控、…