51单片机的定时器有两个,分别是定时器0和定时器1。
定时器0:定时器0是一个8位定时器,它可以用作定时器或计数器。在定时器模式下,它可以生成中断,定时范围为0255。在计数器模式下,它可以计数外部脉冲,计数器范围为065535。
定时器1:定时器1是一个16位定时器,也可以用作定时器或计数器。在定时器模式下,它可以生成中断,定时范围为065535。在计数器模式下,它可以计数外部脉冲,计数器范围为065535。
在使用定时器时,需要先进行定时器的初始化设置。具体步骤如下:
1.选择定时器工作模式(定时器或计数器)。
2.设置计数值或定时器的初值。
3.打开定时器中断(如果需要中断)。
4.打开定时器开关。
// 定时器0初始化函数
void timer0_init()
{
TMOD &= 0xF0; // 设置为定时器模式,使用模式1
TH0 = 0xB1; // 设置定时器初值为0xB1
TL0 = 0xE0; // 设置定时器初值为0xE0
ET0 = 1; // 打开定时器中断
TR0 = 1; // 打开定时器开关
}
代码将定时器0设置为10ms中断一次
#include
void timer0_init()
{
TMOD &= 0xF0; // 设置为定时器模式,使用模式1
TH0 = 0x3C; // 设置定时器初值为0x3C
TL0 = 0xAF; // 设置定时器初值为0xAF
ET0 = 1; // 打开定时器中断
TR0 = 1; // 打开定时器开关
}
void timer0_isr() interrupt 1
{
TH0 = 0x3C; // 重新设置定时器初值
TL0 = 0xAF;
// 处理中断事件
}
void main()
{
timer0_init(); // 初始化定时器0
EA = 1; // 打开总中断开关
while(1);
}
使用定时器0来产生一个1秒钟的中断
51单片机定时器有以下四种模式:
模式0(13位定时器):模式0是一个13位定时器,可以用作定时器或计数器。在定时器模式下,它可以生成中断,定时范围为08191。在计数器模式下,它可以计数外部脉冲,计数器范围为08191。这种模式的特点是定时器/计数器的溢出标志位TF0只有在定时器/计数器计满13位时才会置位。
模式1(16位定时器):模式1是一个16位定时器,也可以用作定时器或计数器。在定时器模式下,它可以生成中断,定时范围为065535。在计数器模式下,它可以计数外部脉冲,计数器范围为065535。这种模式的特点是定时器/计数器的溢出标志位TF1只有在定时器/计数器计满16位时才会置位。
模式2(8位自动重载定时器):模式2是一个8位自动重载定时器,只能用作定时器。在定时器模式下,它可以生成中断,定时范围为0~255。这种模式的特点是定时器的溢出标志位TF0会在定时器计满8位时置位,并且自动将定时器初值装载到计数器中。
模式3(16位自动重载定时器):模式3是一个16位自动重载定时器,只能用作定时器。在定时器模式下,它可以生成中断,定时范围为0~65535。这种模式的特点是定时器的溢出标志位TF1会在定时器计满16位时置位,并且自动将定时器初值装载到计数器中。
自动重载定时器是一种定时器模式,其特点是在定时器溢出后自动重新加载初值,从而实现循环定时的功能。自动重载定时器的好处在于可以避免手动重新设置定时器初值的繁琐操作,并且可以保证定时器的稳定性和精度。
在自动重载定时器模式下,当定时器计满计数器的位数(如8位或16位)后,会自动将定时器的初值重新装载到计数器中,从而实现循环定时的功能。在定时器工作期间,我们只需要通过设置定时器初值和选择定时器模式来控制定时器的行为,而不需要手动干预定时器计数器的值。
定时器在工作时需要设置一个初始值,用来指定定时器的计数范围和定时时长。在定时器开始工作时,定时器从这个初始值开始计数,直到计数值达到设定的上限,定时器就会触发中断或产生其他相关的操作。
通过设置定时器的初始值,可以灵活地控制定时器的定时时长,使定时器可以适应不同的应用场景和需求。例如,在一个需要定期进行数据采集的应用中,我们可以根据采集周期来设置定时器的初始值,以便精确地控制采集时间。
定时器模式0是51单片机定时器的一种工作模式,也被称为13位定时器模式。在这种模式下,定时器的计数器宽度为13位,可以实现的计时范围为0~8191个机器周期。定时器模式0的工作原理如下:
首先,将定时器的计数器初始化为0,并设置一个定时器初值TH0和TL0。这两个值分别表示计数器计数达到65536时,将自动重新加载的高8位和低5位初值。
定时器开始计数,每个机器周期计数器加1,直到计数器达到上限65536,然后自动重新加载TH0和TL0的值,重新开始计数。这个过程一直重复,直到定时器停止工作。
如果设置了定时器中断使能,当定时器计数器溢出时,会触发定时器中断,并执行中断处理函数。
定时器模式0适用于定时器需要很高精度、计时时间比较短的场景,由于计数器宽度只有13位,因此能够计时的时间最长只有8191个机器周期,约为1.08ms。同时,在定时器模式0中,计时器的高8位初值是不可改变的,因此不适合需要更灵活的计时范围的应用场景。
定时器模式1是51单片机定时器的一种工作模式,也被称为16位定时器模式。在这种模式下,定时器的计数器宽度为16位,可以实现的计时范围为0~65535个机器周期。定时器模式1的工作原理如下:
首先,将定时器的计数器初始化为0,并设置一个定时器初值TH1和TL1。这两个值分别表示计数器计数达到65536时,将自动重新加载的高8位和低8位初值。
定时器开始计数,每个机器周期计数器加1,直到计数器达到上限65536,然后自动重新加载TH1和TL1的值,重新开始计数。这个过程一直重复,直到定时器停止工作。
如果设置了定时器中断使能,当定时器计数器溢出时,会触发定时器中断,并执行中断处理函数。
定时器模式1适用于需要较长计时时间的应用场景,由于计数器宽度为16位,可以实现最长65535个机器周期的计时范围,约为8.19ms。同时,在定时器模式1中,可以通过设置TH1和TL1的值来灵活地控制计时范围,从而适应不同的应用场景需求。因此,定时器模式1比定时器模式0更灵活、更适用于一些长时间计时的应用场景。
定时器模式2是51单片机定时器的一种工作模式,也被称为8位自动重载定时器模式。在这种模式下,定时器的计数器宽度为8位,可以实现的计时范围为0~255个机器周期。定时器模式2的工作原理如下:
首先,将定时器的计数器初始化为TH2,并设置一个定时器初值RCAP2H和RCAP2L。这两个值分别表示计数器计数达到上限255时,将自动重新加载的高8位和低8位初值。
定时器开始计数,每个机器周期计数器加1,直到计数器达到上限255,然后自动重新加载RCAP2H和RCAP2L的值,重新开始计数。这个过程一直重复,直到定时器停止工作。
如果设置了定时器中断使能,当定时器计数器溢出时,会触发定时器中断,并执行中断处理函数。
定时器模式2适用于需要精度相对较低,但计时时间较短的应用场景。由于计数器宽度只有8位,能够计时的时间最长只有255个机器周期,约为32.76us。同时,在定时器模式2中,通过设置RCAP2H和RCAP2L的值,可以灵活控制计时范围。相比于定时器模式0和定时器模式1,定时器模式2的计时范围更短,但是更适合于需要高频计时的应用场景。
定时器模式3是51单片机定时器的一种工作模式,也被称为16位定时器模式。在这种模式下,定时器的计数器宽度为16位,可以实现的计时范围为0~65535个机器周期。定时器模式3的工作原理如下:
首先,将定时器的计数器初始化为0,并设置一个定时器初值TH0和TL0。这两个值分别表示计数器计数达到65536时,将自动重新加载的高8位和低8位初值。
定时器开始计数,每个机器周期计数器加1,直到计数器达到上限65536,然后自动重新加载TH0和TL0的值,重新开始计数。这个过程一直重复,直到定时器停止工作。
如果设置了定时器中断使能,当定时器计数器溢出时,会触发定时器中断,并执行中断处理函数。
定时器模式3与定时器模式1的区别在于,定时器模式3使用的是定时器0,而模式1使用的是定时器1。另外,在定时器模式3中,使用的是不同的寄存器TH0和TL0来存储计数器初值和重新加载值。定时器模式3适用于需要较长计时时间的应用场景,由于计数器宽度为16位,可以实现最长65535个机器周期的计时范围,约为8.19ms。同时,在定时器模式3中,可以通过设置TH0和TL0的值来灵活地控制计时范围,从而适应不同的应用场景需求。
定时器模式0:8位自动重载定时器模式。使用定时器0,计数器宽度为8位,计时范围为0~255个机器周期。在该模式下,定时器的初值被写入TH0寄存器中,当计数器计数达到255时,自动重新加载初值,循环计数。适用于计时较短的应用场景。
定时器模式1:16位自动重载定时器模式。使用定时器1,计数器宽度为16位,计时范围为0~65535个机器周期。在该模式下,定时器的初值被写入TH1和TL1寄存器中,当计数器计数达到65535时,自动重新加载初值,循环计数。适用于计时较长的应用场景。
定时器模式2:8位PWM输出模式。使用定时器0,计数器宽度为8位,计时范围为0~255个机器周期。在该模式下,可以通过设置TH0和TL0的值来控制PWM输出的频率和占空比。适用于需要生成PWM信号的应用场景。
定时器模式3:16位自动重载定时器模式。使用定时器0,计数器宽度为16位,计时范围为0~65535个机器周期。在该模式下,定时器的初值被写入TH0和TL0寄存器中,当计数器计数达到65535时,自动重新加载初值,循环计数。与定时器模式1相似,但使用的是定时器0,适用于计时较长的应用场景。
不是必须要搭配中断函数使用定时器,但是在实际应用中,常常使用定时器与中断函数相结合的方式,以实现定时器功能的更加精确和高效。
使用中断函数可以让处理器在定时器计时完成后及时响应,执行相应的处理操作。同时,在中断服务程序中可以进行其他操作,如数据处理、状态切换等,提高系统的效率和灵活性。
当然,如果不需要对定时器计时完成后进行及时响应的处理,也可以不使用中断函数,而是采用查询的方式读取定时器计数器的值来实现相应的功能。但这种方式可能会占用过多的CPU时间,并且不能及时响应计时完成事件,导致计时不够精确。
编写中断函数时,需要注意以下几点:
中断函数必须是短小精悍的,不能执行过长的代码。因为中断函数是在中断发生时被调用,如果执行时间过长,会影响主程序的运行。
中断函数中不能使用被中断的寄存器。在中断发生时,CPU会自动将相应的寄存器压入堆栈保存,当中断服务程序执行完成后,CPU会自动将寄存器弹出恢复原值。如果在中断服务程序中修改了被中断的寄存器,可能会导致程序出错。
中断函数中要尽量避免使用浮点运算和复杂的数据结构,因为这些操作需要较长的执行时间,可能会导致中断响应时间变慢。
中断函数中要注意对共享变量的保护,避免出现多个任务同时访问同一共享资源的情况,导致数据出错或死锁。
中断函数中要注意对其他中断的响应。如果系统中存在多个中断源,需要根据实际情况设置中断优先级,避免低优先级的中断被高优先级的中断所屏蔽。