专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

AVR单片机学习(六)中断与定时器

作者:zww 1988   来源:本站原创   点击数:  更新时间:2014年04月18日   【字体:
中断的概念
  • M16的外部中断
  • 定时器的概念
  • M16的定时器
  • 中断方式使用定时器
  • 中断概念

    一、在程序运行期间,发生非预期的紧急事件

    1、通常是为了避免查询方式的程序设计(它低效因为一直查询,死循环一直不停查询)

    2、用的最多的是外部中断与定时器中断(主要产生一些精确地延时,省去了CPU延时CPU延时就不能干其他事情了所以可以提高CPU效率)

    3、外部中断:按键程序

    4、定时器中断:定时与循环扫描应用场合

    二、中断服务程序

    1、中断发生时,主程序暂停,跳转到中断服务程序,称为“相应中断”

    2、执行完毕后返回主程序继续运行

     
    一、M16具有3个外部中断

    1、M16具有3个外部中断

    2、INT0、INT1:

       1):支持4种触发模式,与CPU时钟是同步触发

    3、INT2

       1)支持2种触发模式、与CPU时钟是异步触发

    二、中断相关库函数的头文件

    1、 avr/interrupt.h

    三、中断服务程序

    SIGNAL(SIG_INTERRUPT0)

    {

       //此处添加中断服务代码

    四、中断有关的寄存器

    1、MCUCR

    2、MCUCSR

    3、GICR

    //ATmega16 技术文档



    由:The External interrupt are triggered by the INT0 ,INT1 and INT2 pins.说明外部中断是通过这3个脚进行触发。看下图


    INT0/INT1/INT2 分别对应单片机的16、17、3脚不过在开发过程中INT2不常用。

    observe that ,if enabled the interrupts will trigger even if the INT0..2pins are configured as outputs.可得即使中断引脚配置成输出,只要使能了中断,电平发生了变化就会触发。

    the feature provides a way of generating a software interrupt.这个特征可提供一个可发生软中断的方式。但对与初学者可以不用理解呵呵。

    上图不明显但是可以看出高四位 是灰色的是用于其他用途。  ISC11  ISC10 是配置中断1的触发方式。

    ISC01   ISC00 这两位是配置中端0的触发方式。

    外部中断有个三个INT1 INT0   INT2

    看看中断1的控制寄存器 MCUCR   control  register

    ISC11  ISC10  这两位组合4中方式申请中断  0 0 低电平发生中断申请  也就是只要INT1引脚上有低电平时候就申请中断。一般不采用因为稳定性和可靠性太差。(估计是低电平不停申请)

      1 的时候任意的逻辑电平变化INT1 发生一个中断申请。(就是说上升,下降都产生)

      0 一个falling edge  下降沿  发生一个中断申请

      1 一个rising edge 上升沿  发生一个中断申请

    我们用的比较多的是后两种方式

    MCUCR 这个寄存器有8位就是配置INT0和INT1的触发方式。

    中端0的和1是一样所以不再解释了哦,如下图。

    下一个寄存器是MCUCSR 

     这个是控制和状态寄存器(MCU CONTROL AND STATUS REGISTER MCUCSR) 它的第6位用来配置中端2 INT2的触发方式如下图



    看datasheet的解释如下图

     



     


    这个异步外部中断2 是外部中断2脚激活 SREG 1-bit and 相应的中断屏蔽位GICR 设置。加入ISC2写 0,一个falling edge (下降沿) 开INT2  激活中断, IF ISC2 是写 1,是一个 rising edge (上升沿) 开INT2 激活中断, INT2的边沿触发方式(registered 注册)是异步的。跟外部中断2有关系的



     

    第三个寄存器是通用外部中断控制寄存器


    这个寄存器的高三位用来使能外部中断请求 INT1  INT0 INT2 只有这三位相应位置1  比如使用INT0 必须把INT0 这个位写1,表示这中断打开了。参看下面2图的说明

     

     

     

    第四个寄存器是中断标志寄存器对于初学者一般用不到



    当外部中断发生的时候相应的外部中断寄存器就会置1,被单片机内部置1,我们可以将他读出来,但是一般不用去读这个标志位,自动就会进入中断服务程序。所以ATmega16 的三个外部中断主要就样子。而我们用的比较多的就是中断0  和中断1.所以我们学习也就只是学习中断0和中断1.还有就是中断库函数的头文件 avr/interrupt.h  用include 包含进去。然后如果使用中断必须写一个中断服务程序中断服务程序一般是 SIGNAL(SIG_INTERRUPT0){}

    这是中断0的,这个在哪查询到的呢?在AVR 单片机GCC程序设计这本电子书,在第四章 功能模块编程示例 4.1首先就是中断服务程序看下图。

    你看signame  中断类型,SIG_INTERRUPT0   就是外部中断 INT0的。  我们一般用第一个就可以,SIGNAL(signame)他们两个区别不是很大,所以我们用第一个就可以。看下图示例



    在新版的AVR GCC 中avr/signal.h 以后就不用包含了,已经没有了。所以只包含avr/interrupt.h就可以了。

    跟中断有关的寄存器刚才说过了有(MCUCR/MCUCSR/GICR    其中还有一般用不到的是GIFR 中断标志寄存器)。

    外部中断的使用步骤

    一、第一步:包含头文件

      1、#include

    二、第二步:设置中断触发方式、

      1、任意逻辑电平变化:MCUCR |= (1<<ISC10);

      2、下降沿触发:MCUCR |= (1<<ISC10)|(1<<ISC11);

      3、上升沿触发:MCUCR |= (1<<ISC11);

    三、第3步:使能响应相应外部中断

      1、GICR |= (1<<INT0);

    四、第4步:使能全局中断

      1、sei();

    五、第五步:编写中断服务程序

    SIGNAL(SIG_INTERRUPT0){}

    根据以上步骤我们编写一个外部中断0的程序

    第一步打开AVR Studio    点击New Project


    选AVR GCC 起个名字lesson6 点击NEXT



    点击 JTAG ICE 单击Finish


    首先对所有的AVR 的程序都必须包含的一个头文件#include





    INT0 (PD2)接在 K1上,它在常态下属于低电平因为有一个10K的下拉电阻。按下接通电源。

    而对于INT1(PD3) 是在 K2上它在常态下属于高电平 。按下到地了低电平。



    第二个按钮是编译后全速运行。

    #include

    #include

     

    int main(void){

             DDRA |= (1<<3);

             DDRB = 0XFF;

             MCUCR |= (1<<ISC11) | (1<<ISC00) | (1<<ISC00);//设置中断触发方式

             GICR |= (1<< INT0) |(1<<INT1);//使能中断0 和1

             sei();//开启全局中断

             while(1);

    }

    SIGNAL(SIG_INTERRUPT0){

             PORTB = 0;//关闭所有LED

             PORTB |= (1<<0);//LED0 发光

             PORTA |= (1<<3);//蜂鸣器响

    }

    SIGNAL(SIG_INTERRUPT1){

             PORTB =0;//关闭所有LED

             PORTB |=(1<<1);//LED1发光

             PORTA &= ~(1<<3);//蜂鸣器关闭

    }

    以上是外部中断就将这么多下面讲定时器、一般单片机分为8位和16位定时器两种,ATmega 16 有2个 TC0 TC2 8位及一个16位的TC1 。2种功能定时、计数、实际就是一个计数的功能讲值保存在计数寄存器里面。

     

    ---------------------------------------------------------------------------

    定时器的概念  

    ATmega 16具有3个定时器 0 1 2 。

    一、8位定时/计数器的模型

         1、1个8位长度计数寄存器、可以对其进行读写

    2、1个时钟输入端口,计数寄存器对时钟输入端口的时钟脉冲个数进行加1计数,即每来一个时钟脉冲,寄存器的数值自加1

    理解:计数功能保存在计数寄存器里面。

    二、如何实现精确定时?

             1、给计数寄存器定初值n0

             2、给时钟输入端口输入一个频率精确的方波方波周期为t0

             3、计数器计数到256时定时器溢出,时间间隔为:其实就是255到下一个就溢出又都成0了

                                                           T=(256-n0)*t0

                            no 是设定的初值

             4、定时器溢出时可以产生中断  当然这个中断也需要编写一个中断服务程序

    当然定时器的最简单的应用就是溢出方式的应用。ATmega16 具有3个定时器 0 、1 、2定时器0是属于功能最简单的定时器。

    三、M16的定时器0(定时器0是一个功能最简单的定时器)

             1、8位定时器

            2、高级功能具有PWM功能 输出比较功能还有输入捕获功能对一些输入事件进行计时。 四、定时器0相关寄存器

             1、T/C 控制寄存器------TCCR0

             2、设置时钟源频率

     

    技术文档:

     

    Timer/Counter0 is a general purpose, single compare unit, 8-bit Tim

    main features are:

    ?? Single Compare Unit Counter  单通道计数

    ?? Clear Timer on Compare Match (Auto Reload) 比较匹配发生时清除定时器(自动加载)

    ?? Glitch-free, Phase Correct Pu lse Width Modulator (PWM) 无干扰脉冲,相位正确的PWM

    ?? Frequency Generator 频率发生器

    ?? External Event Counter 外部事件计数

    ?? 10-bit Clock Prescaler 10位的时钟分频器(值得注意可以把单片机分频得到时间长点的定时)

    ?? Overflow and Compare Match Interrupt Sources (TOV0 and OCF0)  溢出合比较匹配中断源(定时器的2个中断源)我们只讲溢出中断 TOV0 .

    8Timer/Counter0  with PWM Timer/Counter0 是一个(一般用途)通用单通道 8位定时器、比较器模块。这个模块的主要特征是:

    1、单通道比较计数器

    2、清除比较匹配发生(自动加载)就是比较匹配发生时清除定时器(自动加载)这个初学者不用关心

    3、释放干扰脉冲,相位改正脉冲宽度调制器(PWM)就是无干扰脉冲相位正确的PWM

    4、频率发生器

    5、外部事件计数器

    610位时钟预分频器(比如单片机晶振16MHZ可以进行一些预分频然后提供时钟给定时器)

    7、溢出和比较匹配中断源(TOVO and OCFO)就是2个中断源一个是溢出中断  和一个比较匹配中断  而比较匹配中断一般应用于PWM 应用时使用。这里只说下TOV0 就是溢出中断。

    比较匹配中断一般应用于PWM 应用时使用。这里只说下TOV0 就是溢出中断。 

    和定时器0 有关的寄存器我们看8位定时/计数器寄存器的说明。

    首先它有一个控制寄存器 TCCR0

    Timer/Counter Control

    Register – TCCR0

     

     

    它的从第7位到第3位都是跟PWM有关的,这里我们先不去讲解 0 1 2 3位是非常重要的,看下图,可以通过选择这3位可以对CPU时钟进行预分频然后提供给定时器0使用。

    其实经过分频这个定时的时间长度跨度就非常大了。比晶振频率慢了当然时间长了

    2个寄存器叫TCNT0 如下图、这个T/C寄存器 TCNT0 这就是计数寄存器,这个寄存器的数值呢,每来一个定时器的时钟脉冲数值就自动增  256就溢出

     

    第三个寄存器叫做输出比较寄存器 如下图  OCR0 这个也是跟PWM功能有关的。






    第四个叫做TIMSK  中断屏蔽寄存器如下图它的第1位和第0位可以用来使能输出比较匹配中断和溢出中断我们只关心   TOIE0  溢出定时器溢出中断。

     

    第五个寄存器是  中断标志寄存器 TIFR  它的第1位第0位是输出比较匹配标志  和溢出标志我们使用中断不用关心,如果查询模式的话,我们需要不停查询TOV0来判断一下TC0有没有达到溢出

    列举一下TC0相关相关寄存器

    定时器0相关寄存器

     

    T/C 控制寄存器 ----TCCR0

    设置时钟频率

     

    T/C寄存器  TCNT0

    计数寄存器

     

    T/C 中断屏蔽寄存器 ----TIMSK

    需要使用溢出中断时

     

    T/C 中断标志寄存器 ---TIFR

    查询是否溢出

    下面演示下定时器0溢出方式 用查询模式使用步骤

    第一步:设置TC寄存器初值

    TCNT0 =55

    第二步:开启时钟,同时TC0启动

    TCCR0 |= (1<<CS01);

    第三步:查询TIFR 寄存器的TOV0位

    while(!(TIFR & (1<<TOV0)));


    当然要先设置时钟频率TCNR0 对时钟预分频如 要100us 首先选一个合适的分频比例 8 分频就是2MHZ

    2MHZ 就是0.5 微妙 ,所以定100微妙时长的话,计数200次所以先赋初值 TCNT0 =55   55+200 =255 溢出了就是时长100微妙。

    以下代码查询方式使用定时器0 的代码


    当然还有中断模式,中断模式使用稍微复杂一点

    第一步:包含中断函数头文件

    #include

    第二步:设置TC寄存器初值

    TCNT0 =55;

    第三步:使能TC0溢出中断

    TIMSK |= (1<<TOIE0);

    第四步:编写TCO溢出中断服务程序

    SIGNAL(SIG_SIG_OVERFLOW0)

    {//此添加中断服务程序代码}

    第五步:开启时钟,同时TC0启动

    TCCR0 |= (1<<CS01);

    第六步:使能全局中断

    sei();

     

    看代码用中断实现定时器0



     

     

    关闭窗口

    相关文章