51单片机快速入门之定时 器
断开外部输入
晶振振荡 假设为 12MHz
12分频之后,为1MHz 当其从0-65536 时,需要65536μs 微秒 也就是65.536ms 毫秒
溢出(值>=65536 时)>中断>执行中断操作
假设需要1ms后产生溢出,则需要设置初始值为64536
此时定时器会从 64536 开始计数 (1000μs 微秒 = 1 ms 毫秒 )
51单片机快速入门之计数器
计算外部输入的脉冲信号
假设设置其为16位计数器,其最大计数值为 2^16=65536
溢出(值>=65536 时) >中断>执行中断操作
假设需要100个脉冲后产生溢出,则需要设置初始值为65436
此时计数器会从 65436 开始计数
结构原理
由 两个8位 计数器构成的 16位 计数器
由 TCON 寄存器 控制 开(1) / 关(0)
由 TMOD 寄存器 设置 工作方式 (定时还是计数)
TMOD寄存器
以下图片来源于stc89c52官方数据手册:
这个GATE用于IO口控制 定时器 使用(1) / 不使用(0) 如果需要IO口控制 需设置其为 1
C/T 设置是 定时器 断开引脚输入 还是 计数器 从引脚输入
M1 M0 为模式选择,有不同的搭配
0 0 时 为13位 模式 (由 两个8位 计数器构成的 16位 计数器) 一计数器低5位 | 二计数器全8位
当 低五位计数器溢出时,它会向高八位计数器提供一个进位信号,这个信号会使高八位计数器的值加1。此时,低五位计数器会自动复位为其最小值(通常为0)
"低 5 位"通常是指一个二进制数的最右边的 5 个比特位从右向左数
举例:16位二进制数1010 1100 0101 1001 低五位 就为 10011
0 1 时 为16位 两个8位全用
1 0 时 为8位自动重载 第一个计数器溢出之后,先转移当前值到 第二个计数器中,再复位为0
每次溢出时,第二个计数器的值就会增加(或减少,取决于计数方向)
1 1 时 停止计数(暂停)
这里要注意数据手册上标注 当M1 M0 都为 1 时 定时器 0 的工作方式
第一个计数器可以设置成 8位定时器/计数器 受 定时器 0 控制
但是 第二个计数器 只能是 8位定时器 受 定时器 1 控制
TCON寄存器
以下图片来源于stc89c52官方数据手册:
定时器1
TF1 溢出标志位 (溢出时其为 1 ,会向CPU 请求中断 ,CPU响应后0) 可手动设置
TR1 运行控制位 (控制开/关 ) 这里要注意TMOD中 GATE 的设置
定时器0
TF0 溢出标志位 (溢出时其为 1 ,会向CPU 请求中断 ,CPU响应后0) 可手动设置
TR0 运行控制位 (控制开/关 ) 这里要注意TMOD中 GATE 的设置
IE1 / IE0 分别为 外部中断1 / 外部中断0 请求标志位
有请求时为1 处理后 由硬件自动清0(默认为0)
IT1 / IT0 分别为外部中断1 / 外部中断 0 触发方式控制位 为0 是低电平触发
程序设计时:在中断服务例程(ISR)的开始部分直接控制IO拉高(低电平触发时)
假设设置为 低电平 触发
低电平时 IE0或IE1 会被置位,即设置为1表示有一个中断请求待处理。
中断请求来时,以下步骤会发生:
- 中断请求使IE0或IE1置位(设置为1)。
- CPU响应中断请求,暂停当前的任务,并跳转到中断服务例程(ISR)。
- 在ISR中,你处理中断请求,完成相应的任务。
- 在ISR结束之前,你需要手动或自动 清零IE0或IE1,以表示中断请求已经被处理完毕。
定时器 程序设计
例子:产生1kHz方波信号 时钟频率12MHz
分析:
信号周期T=1/f T=1/1000 =1ms
高低电平设计为0.5ms(500μs)
定时初始值计算公式:2^16-定时值=2^16-500=65036
第一计数器 A 存储 初值 高八位,第二计数器 B 存储 初值 低八位
在计算机科学中,一个字节由8位二进制数字组成。这8位数字可以分为高四位和低四位,也可以称为高四位和低四位。
- 高八位:指的是这个字节中最左边的8位,也就是最高位的那一部分。
- 低八位:指的是这个字节中最右边的8位,也就是最低位的那一部分。
65036(10进制)转换成16进制为 0xFE0C A存储FE B存储0C
因 65036 数过大,计算比较费劲 所以要适当 缩小
65036/256=取商得到 254
计数器值常需除以256,因计算机处理数据以字节为单位,每字节8位,可表256个值(0-255)。此操作适用于字节操作、防止溢出、图像处理中表示颜色深度、遵循数据格式及简化数学计算。
在计算机科学和电子工程中,计数器的值经常需要 除以256,这通常是因为以下几个原因:
- 字节操作:
计算机中的数据通常以字节(byte)为单位处理,而一个字节等于8位(bit)。由于256等于2的8次方(2^8),它刚好是一个字节可以表示的最大整数值(从0到255)。因此,当处理字节或进行位操作时,256是一个关键的参考点。
- 溢出和模运算:
计数器在增加过程中可能会超过其最大表示范围,导致溢出。如果一个计数器是用一个字节表示的,那么当它的值超过255时,就会从0开始循环。这种现象可以用模运算(即取余数)来描述,而模数通常是256。
- 颜色深度:
在图形和图像处理中,每个像素的颜色可能由若干个字节表示,比如RGB色彩模型中,每个颜色分量(红、绿、蓝)通常用一个字节表示,因此有256种可能的强度级别。
- 协议和数据格式:
某些通信协议或数据格式可能规定了特定的字段长度或计数范围,这时候使用256作为基数可以帮助确保兼容性和标准化。
- 数学和算法:
在一些数学算法和数据结构中,256因其与二进制系统的紧密关系,常常被用作基数或除数,以简化计算和逻辑操作。
总的来说,除以256的操作反映了计算机系统中对字节边界和模运算的常见需求。
65036%256=取余数 12
在计算机科学和数学中,取余数(模运算)是一种非常常见的操作。当我们对一个数进行除法运算时,余数是除不尽的部分。取余数的操作可以帮助我们解决以下几类问题:
溢出处理:在某些系统中,例如基于字节的操作,我们需要确保数值不会超过某个范围(如0到255)。通过取余数,我们可以使数值"循环"回这个范围内,避免溢出。
周期性事件:如果我们想要跟踪每隔一定数量的事件发生的情况(比如每256个事件),取余数可以帮助我们确定是否到达了这个周期的某个特定点。
密码学:在密码学中,模运算是基础操作之一,用于创建和解密密码系统。
数据校验和压缩:在数据传输和存储中,模运算可以用于生成和验证校验和,以检测错误。在某些压缩算法中,它也被用来减少数据的大小。
数学算法:许多数学算法和公式中会用到模运算,因为它可以简化计算,特别是在处理大数时。
对于65036除以256的情况,取余数的操作可以告诉我们65036在256的倍数之间的"剩余"部分是多少。
定时器 程序代码
设置工作模式 :第一计数器 A 存储 初值 高八位,第二计数器 B 存储 初值 低八位
TMOD=0X01;
//0x01 是一个十六进制数,它代表的二进制数是 0000 0001
A=65036/256;//存储高八位
B=65036%256;//存储低八位
EA=1;//打开总中断
ET0=1;//允许定时器0中断
TR0=1;//打开定时器0
定时器 中断函数代码
void T0(void) interrupt 1 using 1
{
A=65036/256;//存储高八位 复位
B=65036%256;//存储低八位 复位
这里放入中断后需要做的操作
}
代码解释:
void T0(void)
:这是一个函数声明,表明函数T0
不接受任何参数,并且不返回任何值。interrupt 1
:这是关键字和参数,用于指定这个函数是一个中断服务例程,其中1
表示中断号。不同的中断号对应不同的中断源.using 1
:这是另一个关键字和参数,用于指定该中断服务例程使用的工作寄存器组。在一些微控制器中,允许程序员在中断服务例程中使用不同的工作寄存器组,以避免与主程序中的寄存器冲突。这里的1
表示使用第1个工作寄存器组。
中断号解释: interrupt
- 外部中断0 (INT0) 中断号0
- 定时器/计数器0 (T0) 中断号1
- 外部中断1 (INT1) 中断号2
- 定时器/计数器1 (T1) 中断号3
- 串行口中断 (串行I/O) 中断号4
寄存器组解释: using 参考链接https://blog.csdn.net/cssdl/article/details/41674095?sharetype=blogdetail&sharerId=41674095&sharerefer=PC&sharesource=qq_43422073&sharefrom=from_link
R0-R7在数据存储器里的实际地址是由特殊功能寄存器PSW里的RS1、RS0位决定的。
using 0时
设置 RS1=0,RS0 =0,用第0组寄存器,R0--R7的在数据存储区里的实际地址是00H-07H。R0(00H)....R7(07H)
using 1时
设置 RS1=0,RS0 =1,用第1组寄存器,R0--R7的在数据存储区里的实际地址是00H-07H。R0(08H)....R7(0FH)
using 2时
设置 RS1=1,RS0 =0,用第2组寄存器,R0--R7的在数据存储区里的实际地址是08H-0FH。R0(10H)....R7(17H)
using 3时
设置 RS1=1,RS0 =1,用第3组寄存器,R0--R7的在数据存储区里的实际地址是00H-07H。R0(18H)....R7(1FH)
计数器为什么要复位 :
在单片机编程中,特别是涉及到定时器/计数器的中断服务例程时,经常会看到这样的情况:在中断服务例程的开始部分,会将一些寄存器的值重新赋值给计数器。
- 防止溢出:
定时器/计数器在达到最大值后会溢出并从零开始计数。如果不重新赋值,计数器可能会继续从溢出点开始计数,导致不正确的结果。通过在中断服务例程中重新赋值,可以确保计数器从预期的值开始计数。
- 实现精确的定时:
在一些应用中,需要实现非常精确的定时。通过在中断服务例程中重新赋值计数器,可以调整定时器的计数值,从而实现更精确的定时。
- 初始化计数器:
在中断服务例程中,可能需要对计数器进行初始化,以便从一个已知的状态开始。这在处理复杂的定时任务或多任务环境中尤为常见。
- 实现周期性任务:
如果中断服务例程需要周期性地执行某些任务,可以通过重新赋值计数器来实现这一点。例如,如果中断服务例程每1毫秒执行一次,可以在中断服务例程的开始部分将计数器设置为一个适当的值,以确保下次中断发生在1毫秒后。
- 处理中断嵌套:
在多中断环境下,可能会出现中断嵌套的情况。在这种情况下,需要确保每次中断服务例程执行时,计数器的值是正确的。通过在中断服务例程中重新赋值计数器,可以确保这一点。
中断相关资料
EX0:EX0=1,允许外部中断0中断;EX0=0,禁止中断
ET0:ET0=1,允许T0中断;ET0=0,禁止中断
EX1:EX1=1,允许外部中断1中断;EX1=0,禁止中断
ET1:ET1=1,允许T1中断;ET1=0,禁止中断
ES:ES=1,允许串行口中断;ES=0,禁止中断
EA:EA=1,CPU开放中断;EA=0,CPU禁止所有的中断请求
TMOD=0X01;
//0x01 是一个十六进制数,它代表的二进制数是 0000 0001
这里操作的是 定时器0 按位带入以下图片中 可以知道定时器0 的 M1=0 M0=1
M1=0 M0=1 时 为16位 两个8位全用
计数器程序代码
例子: 50kHz方波 信号 时钟频率12MHz
TMOD=0X20;
//0X20 是二进制 0010000 控制的是定时器1
//结合上图M1=1 M0=0为8位自动重载 第一个计数器A1溢出之后,先转移当前值到 第二个计数器B1中,再复位为0
A1=246;//设置初始值 溢出相关
B1=246;//设置初始值
//246-256 需要10μs
EA=1;//打开总中断
ET1=1;//打开定时器1中断
TR1=1;//启动定时器1
void T1(void) interrupt 3 using 1
{
//因为是8位重载所以不用初始化计数器
//这里放入需要做的操作
}