首页 > 其他分享 >05-定时器

05-定时器

时间:2023-12-15 21:44:23浏览次数:38  
标签:定时器 05 中断 T0 单片机 chKeyNum CPU

05-定时器

背景资料

51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成。前面介绍的独立按键、led灯都属于外设。

定时器的作用

  1. 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
  2. 替代长时间的Delay,提高CPU的运行效率和处理速度
  3. ...

STC89C52RC定时器资源

  • 定时器个数:3个(T0、T1、T2),T0T1与传统的51单片机兼容,T2是此型号单片机增加的资源
  • 注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0T1的操作方式是所有51单片机所共有的

定时器框图

定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号,每隔固定的一段时间,计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请,产生“响铃提醒”,使程序跳转到中断服务函数中执行

定时器工作模式

STC89C52T0T1均有四种工作模式:

  • 模式0 :13位定时器/计数器
  • 模式1 :16位定时器/计数器(常用)
  • 模式2 :8位自动重装模式
  • 模式3 :两个8位计数器

工作模式1框图:

每脉冲一次定时器/计数器加一,当16位定时器/计数器0溢出时,对TF0标志位进行置位,该标志位置位后,就会向中断系统申请中断,然后执行任务

  • SYSclk:系统时钟,即晶振周期,本开发板上的晶振为12MHz

  • T0 Pin:对应单片机外部引脚P3.4,接收外部脉冲

  • \[C/\overline{T} \]

    :当其为1时,计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟或每6个时钟得到一个计数脉冲,计数值加1;当其为0时,计数脉冲来自单片机外部引脚(T0P3.4T1P3.5),则为计数方式,每来一个脉冲加1

中断系统

中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。

当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源。微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求

CPU正在处理一个中断源请求的时候(执行相应的中断服务程序),发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统

  • 中断系统是为了使CPU具有对外界紧急事件的实时处理能力
  • 多级中断系统中,高优先级的中断可以打断低优先级的中断

中断程序流程

STC89C52RC中断资源

  • 中断源个数:8个(外部中断0/1/2/3,定时器0/1/2中断,串口中断)

  • 中断优先级个数:4个

  • 中断号:

  • 注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等

定时器和中断

定时器相关寄存器

单片机通过配置寄存器来控制内部电路的连接

  • 寄存器是连接软硬件的媒介
  • 在单片机中寄存器就是一段特殊的RAM存储器。一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线(此处是比喻),控制着电路的连接方式
  • 寄存器相当于一个复杂机器的“操作按钮”

一、按键控制led流水灯模式

定时器初始化可以使用STC-ISP的定时器计算器获得,不过记得再加上允许中断的设置和中断优先级的设置,如下

// 设置定时器0可允许中断
EA = 1;
ET0 = 1;
// 设置定时器0的中断优先级
PT0 = 0;

#include <REGX52.H>
#include <INTRINS.H>

unsigned char chLedDir = 1;    // 流水灯方向

void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;

    while(xms)
    {
        i = 2;
        j = 239;
        do
        {
            while (--j);
        } while (--i);
        xms--;
    }
}

/**
  * @brief  读取独立按键键码
  * @param  无
  * @retval chKeyNum 按下按键的键码值
  *         如果按键按下不放,程序会停留在此函数,松手返回按键键码。若没有按键按下,返回0
  */
unsigned char Key()
{
    unsigned char chKeyNum = 0;
    
    if(P3_1 == 0){Delay(20);while(P3_1 == 0);Delay(20);chKeyNum=1;}
    if(P3_0 == 0){Delay(20);while(P3_0 == 0);Delay(20);chKeyNum=2;}
    if(P3_2 == 0){Delay(20);while(P3_2 == 0);Delay(20);chKeyNum=3;}
    if(P3_3 == 0){Delay(20);while(P3_3 == 0);Delay(20);chKeyNum=4;}
    
    return chKeyNum;
}

/**
  * @brief	定时器0初始化 1毫秒@12.000MHz
  * @param  无
  * @retval 无
  *         
  */
void Timer0Init()
{
    // 设置 T0 定时器的工作模式为16位定时模式
    TMOD &= 0xF0;   // 把TMOD的低四位清零(T0定时器),高四位保持不变(T1定时器)
    TMOD |= 0x01;   // 把TMOD的最低位置1(T0定时器),其余高位保持不变
    
    // 设置 T0 定时器的计数单元初值
    // 每隔1us计算加1, 定时器最大值为65535
    // 64536离定时器溢出差值1000(65535 + 1才溢出),正好使计时时间为1ms
    // 中断之后需要在中断服务程序里将定时器计数单元初值
    // 重新配置为64535,这样就能做到 每隔1s中断一次的效果
    TL0 = 64536 % 256;  // TL0 = 0x18
    TH0 = 64536 / 256;  // TH0 = 0xFC
    
    // 设置定时器0可允许中断
    EA = 1;
    ET0 = 1;
    
    // 设置定时器0的中断优先级
    PT0 = 0;
    
    // 定时器0溢出中断标志清0
    TF0 = 0;
    
    // 定时器0开始定时
    TR0 = 1;
}

void main()
{   
    P2 = 0x7F;
    
    Timer0Init();
    while(1)
    {
        unsigned char chKeyNum = Key();
        if(chKeyNum)
        {
            if(chKeyNum == 1)
            {
                chLedDir = !chLedDir;
            }
        }
    }
}

void Timer0Routine() interrupt 1
{
    static unsigned int nT0Cnt = 0;
    nT0Cnt++;
    
    // 设置定时初值
    TL0 = 64536 % 256;
    TH0 = 64536 / 256;
    
    if(nT0Cnt >= 500)
    {
        nT0Cnt = 0;
        
        if(chLedDir == 0)
        {
            P2 = _crol_(P2, 1);   // 循环左移1位 
        }
        else
        {
            P2 = _cror_(P2, 1);   // 循环右移1位
        }
    }
}

二、定时器时钟

中断服务程序一般处理短时任务

#include <REGX52.H>
#include "LCD1602.H"
#include <INTRINS.H>

unsigned char chSec = 50, chMin = 59, chHour = 23;

/**
  * @brief	定时器0初始化 1毫秒@12.000MHz
  * @param  无
  * @retval 无
  *         
  */
void Timer0Init()
{
    // 设置 T0 定时器的工作模式为16位定时模式
    TMOD &= 0xF0;   // 把TMOD的低四位清零(T0定时器),高四位保持不变(T1定时器)
    TMOD |= 0x01;   // 把TMOD的最低位置1(T0定时器),其余高位保持不变
    
    // 设置 T0 定时器的计数单元初值
    // 每隔1us计算加1, 定时器最大值为65535
    // 64536离定时器溢出差值1000(65535 + 1才溢出),正好使计时时间为1ms
    // 中断之后需要在中断服务程序里将定时器计数单元初值
    // 重新配置为64535,这样就能做到 每隔1s中断一次的效果
    TL0 = 64536 % 256;  // TL0 = 0x18
    TH0 = 64536 / 256;  // TH0 = 0xFC
    
    // 设置定时器0可允许中断
    EA = 1;
    ET0 = 1;
    
    // 设置定时器0的中断优先级
    PT0 = 0;
    
    // 定时器0溢出中断标志清0
    TF0 = 0;
    
    // 定时器0开始定时
    TR0 = 1;
}

void main()
{   
    LCD_Init();
    Timer0Init();
    LCD_ShowString(1, 1, "Clock:");
    LCD_ShowString(2, 3, ":  :");
    while(1)
    {       
        // 中断服务程序一般处理短时任务
        // LCD1602显示会占用较多时间
        // 所以放在主函数显示
        LCD_ShowNum(2, 1, chHour, 2);
        LCD_ShowNum(2, 4, chMin, 2);
        LCD_ShowNum(2, 7, chSec, 2);
    }
}

void Timer0Routine() interrupt 1
{
    static unsigned int nT0Cnt = 0;
    nT0Cnt++;
    
    // 设置定时初值
    TL0 = 64536 % 256;
    TH0 = 64536 / 256;
    
    if(nT0Cnt >= 1000)
    {
        nT0Cnt = 0;
        
        chSec++;
        if(chSec >= 60)
        {
            chSec = 0;
            chMin++;
        }
        
        if(chMin >= 60)
        {
            chMin = 0;
            chHour++;
        }
        
        if(chHour >= 24)
        {
            chHour = 0;
        }
    }
}

标签:定时器,05,中断,T0,单片机,chKeyNum,CPU
From: https://www.cnblogs.com/yljblogs/p/17904224.html

相关文章

  • 解决方案 | pywintypes.com_error: (-2147221005, '无效的类字符串', None, None) --P
     1背景importpythoncomimportwin32com.clientimportmathwincad=win32com.client.Dispatch("AutoCAD.Application")#强制打开cad,该句发生报错信息doc=wincad.ActiveDocumentdoc.Utility.Prompt("Hello!Autocadfrompywin32com.\n")msp=doc.Mode......
  • 05-模块和包的概念
    模块和包模块是python的源文件,即.py文件。模块支持导入,一个模块可以导入其他系统提供或第三方模块,可以使用其中提供好的全局变量、函数等。若导入的模块名字过长,也可以使用as使用别名。import会导入一个模块中所有内容,如果只想使用部分内容,可使用from模块import部分这......
  • Day05 变量
    Day05变量定义:在程序执行过程中,其值有可能发生改变的量(数据)使用场景:当某个数据经常发生改变时,我们也可以用变量存储。当数据变化时,只要修改变量里面变化的值即可。变量的定义格式数据类型变量名=数据值;(数据值:存在空间里面的数值)(变量名:为空间起的名)(数据类型:为空间......
  • 05_bootloader开发
    05_bootloader开发需要准备:usb转串口线、SD卡、MINIUSB程序没有运行的时候是放在Nandflash(相当于硬盘)中的,这个地址为程序地址。运行起来的时候是放在DRAM(相当于内存)里的,这个地址为程序链接地址。1.ARM启动顺序1.1.第一个点亮LED的程序(GPIO)参考NoOS(裸机程序)\s......
  • 05 基础入门——资产架构&端口&应用&WAF&站库分离&负载均衡
    一、资产架构1、网站配置(1)目录型网站安全bbs.xiaodi8.com  dz论坛      #该域名下有一套网站程序,dz论坛bbs.xiaodi8.com/blog wp程序  #该域名的某个目录下也配置了一套网站程序总结:一个网站,两个程序,其中任何一个程序出现漏洞,都可以进入安全测试(同一服务器......
  • P2053 [SCOI2007] 修车
    题意有\(n\)个工人,\(m\)个工作。每个人给每个工作有\(t_{i,j}\)的花费。求每个工作的最小平均花费。Sol直接连边跑费用流不好搞。考虑将每种工人在不同时间做的工作暴力建点。枚举\(k\)表示第\(i\)个工人在倒数第\(k\)个做\(j\)工作。这样仍然不好考虑贡献,......
  • [Ynoi2005] qwq
    原问题比较类似\(\text{ZJOI2020}\)序列,可以划归为一个线性规划的形式,考虑将线性规划对偶,不难发现等价于求一个序列\(b\),使得对于任意\(1\leqslantl\leqslantr\leqslantn,r-l+1\leqslantm\)均满足\(\sum_{i=l}^{r}b_{i}\leqslant1\),最大化\(\sum_{i=1}^{n}a_{i}b_{i}......
  • springboot+vue小白升级之路04-实现登录注册功能和springboot+vue小白升级之路05-实现
    我们接着上一课的内容继续我还是尽量把全部代码都贴出来,方便大家学习。项目结构截图springboot后端pom.xml<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>......
  • Nginx——记录post请求回执405的一种解决方式
    前言:nginx做反向代理,一直报405,由于之前配置过,一直是没问题的,这次一直报405,搞了一下午,终于找到原因了是因为开启了多个ngixn导致的。解决办法:cmd杀掉nginx后台进程命令杀掉nginx后台nginx常用命令taskkill/f/t/imnginx.exenginx 常用命令startnginx#启动Ng......
  • P8805 [蓝桥杯 2022 国 B] 机房
    原题链接前情提要题目不难看懂,即求a->b过程中的所有点的延迟和。显然可以暴力遍历一遍完成,但是时间复杂度太高了。改进算法想象这个图是由点和线组成的,把其中一个点提起来,这样就变成了一个树(n叉树),任意两点(a,b)间的延迟和等于a->lca->b,其中lca为ab两点的最近公共祖先这样一来,只......