STC89C52定时器/中断快速上手示例讲解
Posted 帅气的黑桃J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STC89C52定时器/中断快速上手示例讲解相关的知识,希望对你有一定的参考价值。
Catalogue
本文旨在通过简单的示例快速上手定时器与外部中断。
什么是中断?
在你工作摸鱼的时候有电话来了,于是你停下手头正在摸的鱼,转头去接电话,等到电话打完了之后,回来继续摸刚才没摸玩的鱼,这就是中断。
电话来了就是中断的触发信号,接电话就是中断要执行的事情(函数),打完电话回来继续摸鱼就是中断函数执行完之后继续执行未执行完的主程序。
当然,具体的情况会复杂一些,比如摸鱼的时候既有电话又有邮件,你要先处理哪个?这就是优先级的问题,再次延伸下去,就是一些复杂的多中断问题了,这里不展开讨论,下面,我们将从一个简单的demo上手,按下按键后使得led灯取反,代码如下所示。
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
sbit k3 = P3 ^ 2; //定义按键 K3
sbit led = P2 ^ 0; //定义 P20 口是 led
void delay(u16 i)
while (i--);
void Int0Init()
//设置 INT0
IT0 = 1; //跳变沿出发方式(下降沿)
EX0 = 1; //打开 INT0 的中断允许。
EA = 1; //打开总中断
void main()
Int0Init(); // 设置外部中断 0
while (1);
void Int0() interrupt 0 //外部中断 0 的中断函数
delay(1000); //延时消抖
if (k3 == 0)
led = ~led;
什么是定时器/计数器?
51里面的定时器,是通过加一计数器实现的,比如i++一次就间隔1ms,那么i++一千次就是1000ms,也就是一秒,通过某些寄存器配置,你可以让定时器每1ms触发一次中断,从而定时执行你想要完成的任务。
下面,我们来实现一个led灯点亮1秒,熄灭1秒的功能,代码如下:
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
sbit led=P2^0; //定义P20口是led
/*******************************************************************************
* 函 数 名 : Timer0Init
* 函数功能 : 定时器0初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Timer0Init()
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
Timer0Init(); //定时器0初始化
while(1);
/*******************************************************************************
* 函 数 名 : void Timer0() interrupt 1
* 函数功能 : 定时器0中断函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Timer0() interrupt 1
static u16 i;
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
i++;
if(i==1000)
i=0;
led=~led;
进阶:定时器 + 按键中断
会用中断了,会用定时器了,让我们来做一些更复杂的功能:让四个LED灯轮询闪烁一秒,放置两个按键,一个用来开始暂停,一个用来复位重新开始。电路图如下所示:
思路不太难,就是一个定时器中断控制LED闪烁,两个按键中断控制,其中一个按键按下时,定时器会开启或暂停,从而使得LED暂停闪烁;另外一个按键按下时直接让IO口初始化就好了,代码如下所示:
/**
* @file main.c
* @author zeeland
* @brief 让四个LED灯轮询闪烁一秒,放置两个按键,一个用来开始暂停,一个用来复位重新开始。
* @version 0.1
* @date 2022-11-09
*
* @copyright Copyright (c) 2022
*
*/
#include "reg52.h"
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit btn1 = P3^2; // 控制暂停和开始
sbit btn2 = P3^3; // 控制复位
sbit led1 = P0^0;
sbit led2 = P0^1;
sbit led3 = P0^2;
sbit led4 = P0^3;
static u8 index;
static u16 counter;
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void Delay(u16 i)
while(i--);
/*******************************************************************************
* 函 数 名 : delayms
* 函数功能 : 延时函数,i=1时,大约延时1ms
*******************************************************************************/
void Delayms(u8 s) //延时函数
u8 i;
for(i=0;i<s;i++);
/*******************************************************************************
* 函 数 名 : Timer0Init
* 函数功能 : 定时器0初始化,优先级0
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Timer0Init()
TMOD |= 0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0 = 0XFC; //给定时器赋初值,定时1ms
TL0 = 0X18;
ET0 = 1;//打开定时器0中断允许
EA = 1;//打开总中断
TR0 = 1;//打开定时器
// 优先级设置
// PT1 = 0;
/*******************************************************************************
* 函 数 名 : Int0Init
* 函数功能 : 外部中断0,控制系统复位,最高优先级,优先级3
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Int0Init()
IT0 = 1;//跳变沿出发方式(下降沿)
EX0 = 1;//打开 INT0 的中断允许。
EA = 1;//打开总中断
PX0 = 1;//优先级设置
/*******************************************************************************
* 函 数 名 : Int1Init()
* 函数功能 : 设置外部中断1
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Int1Init()
IT1 = 1;//跳变沿出发方式(下降沿)
EX1 = 1;//打开INT1的中断允许。
EA = 1;//打开总中断
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
Timer0Init();
Int0Init();
Int1Init();
while(1);
void Timer0() interrupt 1
TH0 = 0XFC;
TL0 = 0X18;
counter ++;
if (counter == 1000)
P0 = ~(0x01 << index);
counter = 0;
if (++index == 4) index = 0;
// 开始暂停
void Int0() interrupt 0
// 暂停开始定时器1
TR0 = ~TR0;
// 复位
void Int1() interrupt 2
Delay(1000); //延时消抖
if (btn2 == 0)
P0 = 0xff;
index = 0;
最后运行的结果如下所示:
电路图的优化
第一版的电路图如下所示,可以看出还是有点丑的,于是想着优化一下。
在优化了proteus的网络标号,改造后的电路图如下所示,具体的优化过程可以参考Reference.
如果想要完整的proteus文件可以私聊本人。
Reference
以上是关于STC89C52定时器/中断快速上手示例讲解的主要内容,如果未能解决你的问题,请参考以下文章
8051单片机实战分析(以STC89C52RC为例) | 10 - 外部中断的使用