×
单片机 > 单片机程序设计 > 详情

任务12:中断与定时器

发布时间:2022-03-14 发布时间:
|

本系列教程以AVR单片机为对象,介绍单片机的快速开发方法。


参考教材:《单片机技术及应用项目教程》 栾秋平 电子工业出版社 2019.6 第1版


本文介绍中断与定时器。

一、认知单片机中的“中断”

(1)中断的基本概念


在计算机执行程序的过程中,当出现某种情况时,由服务对象向CPU发出请求当前程序中断的信号,要求CPU暂时停止当前程序的执行,而转去执行相应的处理程序,待处理程序执行完毕后,再返回继续执行原来被中断的程序,这样的过程称为中断过程。引起中断的原因或触发中断请求的来源称为中断源。为实现中断而设置的各种硬件和软件称为中断系统。


(2)采用中断技术的优点


a、实行分时操作,提高了CPU的利用率。当服务对象向CPU发出中断请求时,才使CPU转向为该对象服务,否则不影响CPU的正常工作。这样,利用中断可以使CPU同时为多个对象服务,从而大大提高了整个单片机系统的工作效率。


b、实现实时处理,及时处理实时信息。在工业现场控制中,常常要求单片机系统对信号进行实时处理。利用中断技术,各服务对象可以根据需要随时向CPU发出中断请求,CPU及时检测并处理各对象的控制要求,已实现实时控制。


c、对难以预料的情况或故障进行及时处理。在单片机系统工作过程中,有时会出现一些难以预料的情况或故障,如电源掉电、运算溢出、传输错误等,此时可以利用中断进行相应的处理而不必停机。


(3)中断的处理流程

二、定时器

(1)定时器


定时器启动后,开始定时,定时时间到,则置相应的中断标志位,然后向CPU申请中断。定时器的定时功能是以计数的方式来工作的,此时是对单片机内部的脉冲进行加1计数,此脉冲的周期是机器周期分频后得到的,其公式如下:


定时时间 = (溢出值 – 计数初值)× 内部脉冲


定时器可以用来实现很多功能,例如我们可以产生时间;可以在检测系统中,对被检测点进行定时取样;可以在读按键状态时,产生一个消抖时间等等。


(2)计数器


计数器启动后,对外部输入脉冲进行加1计数,计数器加满溢出时,将中断标志位置位,然后向CPU申请中断,其公式如下:


计数脉冲个数 = 溢出值 – 计数初值


计时器在很多应用场合都发挥着作用;例如在工业生产线上,对零件和产品进行计数;在大桥和高速公路上对车流量进行统计等等。


三、程序实现

//加入包含文件

#include "../include.h"

//定义系统常量

//定义全局变量

uint8 u8g_DisplayString[8];

uint8 u8g_DisplayPoint[8];

//主程序

int main(void)

{

//定义局部变量

uint8 i;

//目标板初始化,该函数会自动初始化相应的外设文件

TARGET_Init();

//初始化全局变量

for (i = 0; i < 8; i++)

{

u8g_DisplayString[i] = 0x00;

u8g_DisplayPoint[i] = 0x00;

}

//在上电时,执行的相应操作

//后台主循环

while(1)

{

/*

**********************************

在这里完成自己的项目逻辑

**********************************

*/

for (i = 0; i < 8; i++)

{

u8g_DisplayString[i] = i;

}

TARGET_Delayms(500, 1);

for (i = 0; i < 8; i++)

{

u8g_DisplayString[i] = 8 + i;

}

TARGET_Delayms(500, 1);

/*

**********************************

喂狗语句,大部分工程项目都不应去除

**********************************

*/

#if INTERNAL_PERIPHERAL_WDT_MODE != 0

TARGET_WatchDogReset();

#endif

}

return 0; //永不执行

}

//串口0接收中断服务处理函数,接收到的数据存储在 UDR0 寄存器中

#if INTERNAL_PERIPHERAL_UART0_MODE != 0

ISR(USART__RX_vect)

{

uint8 u8_UartData;

u8_UartData = UDR0;

#if PROTOCOL_MINIUART_UART0_MODE !=0

miniUART_UartInterrupt(&miniUART_UART0, u8_UartData);

#endif

}

#endif

//定时器0溢出中断服务处理函数

#if INTERNAL_PERIPHERAL_TIMER0_MODE != 0

ISR(TIMER0_OVF_vect)

{

#if INTERNAL_PERIPHERAL_TIMER0_MODE == 1

//在此完成逻辑内容

static uint8 u8_Number;

u8_Number++;

if (u8_Number > 7)

{

u8_Number = 0;

}

NIXIETUBE_SelectLED(u8_Number);

NIXIETUBE_DrawLED(u8g_DisplayString[u8_Number], u8g_DisplayPoint[u8_Number]);

#if PROTOCOL_MINIUART_UART0_MODE !=0

miniUART_TimerInterrupt(&miniUART_UART0);

#endif

#if PROTOCOL_MINIUART_CH432T_UART0_MODE !=0

miniUART_TimerInterrupt(&miniUART_CH432T_UART0);

#endif

#if PROTOCOL_MINIUART_CH432T_UART1_MODE !=0

miniUART_TimerInterrupt(&miniUART_CH432T_UART1);

#endif

//为了提高运行速度,将此语句写在中断服务处理函数里,用户在使用时,可不理会下列语句

TCNT0 = TIMER0_TCNT0;

#elif INTERNAL_PERIPHERAL_TIMER0_MODE == 2

#endif

}

#endif

//定时器1溢出中断服务处理函数

#if INTERNAL_PERIPHERAL_TIMER1_MODE != 0

ISR(TIMER1_OVF_vect)

{

//在此完成逻辑内容

//为了提高运行速度,将此语句写在中断服务处理函数里,用户在使用时,可不理会下列语句

TCNT1H = TIMER1_TCNT1H;

TCNT1L = TIMER1_TCNT1L;

}

#endif

//外部中断0中断服务处理函数

#if INTERNAL_PERIPHERAL_INT0_MODE != 0

ISR(INT0_vect)

{

//如果使用了CH432T,则调用相应的中断处理函数

#if EXTERNAL_MODULE_CH432T_MODE != 0

CH432T_INT();

#endif

}

#endif

//外部中断1中断服务处理函数

#if INTERNAL_PERIPHERAL_INT1_MODE != 0

ISR(INT1_vect)

{

//如果使用了CH432T,则调用相应的中断处理函数

#if EXTERNAL_MODULE_CH432T_MODE != 0

CH432T_INT();

#endif

}

#endif

//CH432T扩展串口0,接收调用函数

#if EXTERNAL_MODULE_CH432T_MODE != 0

void CH432T_Uart0(uint8 u8_UartData)

{

#if PROTOCOL_MINIUART_CH432T_UART0_MODE != 0

miniUART_UartInterrupt(&miniUART_CH432T_UART0, u8_UartData);

#endif

}

#endif

//CH432T扩展串口1,接收调用函数

#if EXTERNAL_MODULE_CH432T_MODE != 0

void CH432T_Uart1(uint8 u8_UartData)

{

#if PROTOCOL_MINIUART_CH432T_UART1_MODE != 0

miniUART_UartInterrupt(&miniUART_CH432T_UART1, u8_UartData);

#endif

}

#endif


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多