HAM单片机学习计划AVR篇之三:定时器和计数器的使用方法


写在前面:似乎是我太忙了,好几个月都没有好好的写个教程了。有的朋友知道我忙什么,有的不知道,不解释了,请大家谅解。
这次我们继续学习AVR的功能,实际上这次我这是写了这个教程,教程中使用的程序是我在几年前写好的,正好用在这里。考虑到一直以来,很多朋友对电子不熟悉,不太好做实验,所以这次开始我们使用Proteus7做仿真,在大多数的时候,大家不用做电路板也可以学习和实验单片机了。关于这个仿真软件,存在很多版权问题,不能提供下载,建议大家到百度或迅雷看看。
    好了,下面我们开始吧。
      Avr单片机atmega16具有2个8位定时器timer0和timer2,和1个16位定时器timer1。
   
      AVR的定时计数器有多种工作模式,有通用计数器、PWM、比较器等,这里,我们只使用基本的计数功能。
    说明一下,这个程序的作用是利用time2定时器生成PWM从而驱动舵机。
    部分资料见这里:http://ham.armcu.com/showtopic-36.aspx

      /*********************  程序代码  *************************/
#include <mega16.h>

int zkb;
int zq;         
int t1,t2;


// Timer 2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
// Reinitialize Timer 2 value
//每次触发为20微秒
TCNT2=0xEC;          //反转值,理论值为0xEC 但是实测值为0xEF  有点没搞懂  ??

  if((--zq)==0)
  {     
    PORTB^=0B00000001;    //PORTB.0 反转 
    if(PORTB.0==1){
      zq=t1;
    }else
    {
      zq=t2;
    }         
  }
}

// Declare your global variables here
void delay_1ms(void); //函数声明,本实验中会用到这两个函数
void delay_nms(unsigned int n); 


void main(void)
{           
int aa=20;   

/*初始化参数*/
zkb=1500;   
t1=zkb/20;       
t2=(20000-zkb)/20;
zq=t1;

/********************************************/

PORTB=0x00;
DDRB=0x00;
DDRB.0=1;      //置为输出

PORTB.0=1;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 1000.000 kHz
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x02;
TCNT2=0xEF;
OCR2=0x00;

// Timer(s)/Counter(s) Interrrupt(s) initialization
TIMSK=0x40;

// Global enable interrupts
#asm("sei")

while (1)
      {
        //下面是测试代码
        delay_nms(150);
        zkb+=aa;
        if(zkb==1000||zkb==2000){    //标准应该是1000至2000
          aa=-aa;         
          delay_nms(500);
        }
        t1=zkb/20;       
        t2=(20000-zkb)/20;
       
      }
}   

void delay_1ms(void)//1ms延时函数
{
  unsigned int i;
  for (i=0;i<150;i++)
  {
  }


void delay_nms(unsigned int n)//延时n毫秒
{
  unsigned int i;
  for (i=0;i<n;i++)//执行n次1毫秒延时
  delay_1ms();
}

      /********************************************************/
     
      这个程序很简单的,实现的是 利用定时器 产生线性变化的1至2毫秒的变化,步进为20微秒。
   
    下面我们来分解看一下这个程序吧。

    // Timer/Counter 2 initialization
      // Clock source: System Clock
      // Clock value: 1000.000 kHz
      // Mode: Normal top=FFh
      // OC2 output: Disconnected
      ASSR=0x00;
      TCCR2=0x02;
      TCNT2=0xEF;
      OCR2=0x00;

      这段程序是告诉单片机Timer2的初始值,和如何触发。由于参数太多,具体请看手册。
   
      ASSR=0x00;          //确定频率源为时钟频率
    TCCR2=0x02;        //确定分频大小
    TCNT2=0xEF;        //初始化值
    OCR2=0x00;          //输出比较寄存器

    原理:
    timer2是8为计数器,那么最大值是255,在给定时器赋初始值的情况下,每个TCNT2周期加1,当超出255时溢出,触发中断interrupt [TIM2_OVF] void timer2_ovf_isr(void)。
    在本例子中,每次触发中断的时间为20微秒,在中断程序中重新设置初始值TCNT2,以便重新循环。其它的工作模式基本都是基于这个原理的。

    由于定时计数器的参数太多,所以请参考手册。
     

      至于中断函数吗?最重要的是为TCNT2赋值。本例子中的其它程序都很简单了,程序中有注释,应该可以看懂的。

    重复一下,最终实现的高电平的时间在1-2毫秒间线性变化,步进值就是每次中断的时间,既20微秒。你看懂了吗?
   
      写在后面:
    随着学习的深入,大家可能发现,程序不像原来一样,每一个细节都讲解了,因为大家都开始熟悉了,没有必要都讲的。还有就是C语言的运用越来越复杂了,这就是我原来和大家强调的,要把C语言学好;还有就是一定要多阅读手册,这样才能熟悉每个参数和寄存器,这是很重要的。好了,就到这里吧。

    BG2ANV    2008.05.04 于 北国哈尔滨
   

附件: 可变脉宽输出试验-范例.rar (2008-5-4 19:51:43, 910.56 K)
该附件被下载次数 293


   
    仿真源代码:
   

附件: AVRMega16_time.rar (2008-5-4 19:55:57, 502.08 K)
该附件被下载次数 331



     

     



   





最后编辑xidongs 最后编辑于 2008-05-05 12:38:32
呼号:BG2ANV
姓名:丛喜东
地址:150081
  黑龙江哈尔滨市哈平路134号(黑龙江省木材采运研究所)
电话:0451-89629801
QQ: 9960862
Email:congxd@vip.sina.com

体谅 Considerate
忠诚 Loyal
进取 Progressive
友爱 Friendly
适度 Balanced
爱国 Patriotic