任务12:中断与定时器
本系列教程以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
任何问题,只需在此文章的评论处留言即可,我将尽力解答,不要试图采用其它的联系方式,我一概不理会。
原创性文章,转载请注明出处CSDN:http://blog.csdn.net/qingwufeiyang12346。