B001-Atmega16-定时器1-(ques=1)

Atmega16-定时器1的使用 step by step。
之前完成了定时器2的各项功能的测试后,这里就很容易做了。


编译环境:AVR Studio 4.19 +avr-toolchain-installer-3.4.1.1195-win32.win32.x86
芯片型号:ATmega16
芯片主频:8MHz


测试说明:

1、 OC1AOC1B引脚输出比较匹配的波形
2、 PA2TOV1中断时取反
3、 PA3OCF1A中断时取反
4、 PA5OCF1B中断时取反
5、 PA6ICF1中断时取反


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

小结:

1、最好使用 CTC模式来做定时功能。

      因为这样就只需要设置OCR1A,不需要每次TOV1中断都要重新设置TCNT1的计数初值。
2、CTC模式下、OC1AOC1B的频率由OCR1AICR1决定,OCR1AOCR1B都用来控制OC1AOC1B的相位。
      CTC模式下的脉冲频率最大可达4MHz
3、快速/高频PWM用于:功率调节、整流、ADC
      当OCR1A/OCR1B超过TOP值时,依然有PWM波形输出:TCNT1=(OCR1A或OCR1B)&TOP时发生比较匹配
      可以得到相当精确的PWM频率和占空比,如38KHz1/3占空比的红外载波
      可以用OC1A引脚输出类似CTC模式的方波
4、相位修正对称用于:电机控制   
      修改TOP值可能导致上升斜坡下降斜坡长度不一致,导致一个周期的波形不对称
      结果就是占空比超出预期或低于预期。
      如果这有影响,就应该使用相位与频率修正PWM来做TOP值/频率可变的PWM

5、相频修正PWM,其作用与意义有待理解。

6、对于ICF1中断,还有异常,见question-001


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

第一步: 普通模式

说明:

1、使用定时器1的作为定时器使用,每次溢出后PA2的电平取反,由此可得知溢出时间。

测试代码:

Drv_Timer.h

typedef enum 
{
    INT_MODE_TOV = 0,
    INT_MODE_OCF = 1,
    INT_MODE_ICF = 2,
    INT_MODE_OCF1A = 3,
    INT_MODE_OCF1B = 4
} TIMER_INT_MODE;

typedef enum 
{
    T1_COM_MODE_NONE       = 0,
    T1_COM_MODE_TOGGLE     = 1,
    T1_COM_MODE_CLEAR      = 2,
    T1_COM_MODE_SET        = 3,

    T1_WGM_NOMAL           = 0,
    T1_WGM_8_PHASE_PWM     = 1,
    T1_WGM_9_PHASE_PWM     = 2,
    T1_WGM_10_PHASE_PWM    = 3,
    T1_WGM_CTC             = 4,
    T1_WGM_8_FAST_PWM      = 5,
    T1_WGM_9_FAST_PWM      = 6,
    T1_WGM_10_FAST_PWM     = 7,
    T1_WGM_PHASE_FRQ_PWM_ICR1  = 8,
    T1_WGM_PHASE_FRQ_PWM_OCR1A = 9,
    T1_WGM_PHASE_PWM_ICR1    = 10,
    T1_WGM_PHASE_PWM_OCR1A   = 11,
    T1_WGM_CTC_ICR1          = 12,
    T1_WGM_SERVED            = 13,
    T1_WGM_FAST_PWM_ICR1     = 14,
    T1_WGM_FAST_PWM_OCR1A    = 15,

    T1_CLK_SOURCE_NONE     = 0,
    T1_CLK_SOURCE_CLK_1    = 1,
    T1_CLK_SOURCE_CLK_8    = 2,
    T1_CLK_SOURCE_CLK_64   = 3,
    T1_CLK_SOURCE_CLK_256  = 4,
    T1_CLK_SOURCE_CLK_1024 = 5,
    T1_CLK_SOURCE_T1_FALL  = 6,
    T1_CLK_SOURCE_T1_RAISE = 7
} TIMER1_MODE;

typedef enum 
{
    T1_ICP_FALL_EDGE       = 0,
    T1_ICP_RAISE_EDGE      = 1
} TIMER1_ICP;
Drv_Timer.c
// ==========================================================================================================
// 定时器1初始化
// 
// 参数:OCM1A_mode      通道A比较匹配/PWM输出模式选择
//       OCM1B_mode      通道B比较匹配/PWM输出模式选择
//       com_mode        工作模式/波形产生模式选择
//       clk_source      时钟源和预分频选择
// 
// PWM模式下、写TCCR1A时需要清除FOC1A/B
// 写TCCR1B时需要清除bit5
// 
// ==========================================================================================================
void Drv_Timer1_init(const uint8_t com_mode, const uint8_t OCM1A_mode, const uint8_t OCM1B_mode, const uint8_t clk_source)
{
    TCCR1A = ((OCM1A_mode & 0x03) << 6) |   // 通道A比较匹配/PWM输出模式选择
             ((OCM1B_mode & 0x03) << 4) |   // 通道B比较匹配/PWM输出模式选择
             ((com_mode   & 0x03) << 0);    // 工作模式/波形产生模式选择(WGM[11:10])

    TCCR1B = (((com_mode & 0x0C) >> 2) << 3)   |    // 工作模式/波形产生模式选择(WGM[13:12])
             ( (clk_source & 0x07)     << 0);       // 时钟源和预分频选择
}

// ==========================================================================================================
// TIMER1 中断使能
// 
// 参数:mode   = INT_MODE_TOV 或 INT_MODE_ICF 或 INT_MODE_OCF1A  或 INT_MODE_OCF1B
//       enable = ENABLE 或 DISABLE
// 
// 可以单独使能/禁止一种模式的中断
// 
// ==========================================================================================================
void Drv_Timer1_INT_Enable(const uint8_t mode, const uint8_t enable)
{
    if(INT_MODE_TOV == mode)
    {
        if(DISABLE == enable)
        {
            TIMSK &= ~(1 << TOIE1);
        }
        else
        {
            TIMSK |=  (1 << TOIE1);
        }
        TIFR |= (1 << TOV1);
        return ;
    }
    if(INT_MODE_OCF1A == mode)
    {
        if(DISABLE == enable)
        {
            TIMSK &= ~(1 << OCIE1A);
        }
        else
        {
            TIMSK |=  (1 << OCIE1A);
        }
        TIFR |= (1 << OCF1A);
        return ;
    }
    if(INT_MODE_OCF1B == mode)
    {
        if(DISABLE == enable)
        {
            TIMSK &= ~(1 << OCIE1B);
        }
        else
        {
            TIMSK |=  (1 << OCIE1B);
        }
        TIFR |= (1 << OCF1B);
        return ;
    }
    if(INT_MODE_ICF == mode)
    {
        if(DISABLE == enable)
        {
            TIMSK &= ~(1 << TICIE1);
        }
        else
        {
            TIMSK |=  (1 << TICIE1);
        }
        TIFR |= (1 << ICF1);
    }
}

// ==========================================================================================================
// TIMER1 溢出中断服务程序
// 
// ==========================================================================================================
ISR(TIMER1_OVF_vect)
{
    PORTA ^= (1 << PA2);
}
main.c
// ==========================================================================================================
// 主函数
// ==========================================================================================================
#include 
#include 
#include "watch_dog.h"
#include "Drv_Timer.h"
#include "_noinit.h"
#include "system.h"
#include "sys_timer.h"
#include "config.h"

// ==========================================================================================================
//  伪中断BADISR_vect
// 
// ==========================================================================================================
ISR(BADISR_vect)
{
    
}

// ==========================================================================================================
// main函数
// ==========================================================================================================
int main(void)
{
    // ---------
    // 关全局中断
    cli();

    // 系统初始化
    sys_init();

    // PA[5:2]初始化为输出0
    DDRA   =   (1 << DDA2) | (1 << DDA3) | (1 << DDA5) | (1 << DDA6);
    PORTA &= ~((1 << PA2 ) | (1 << PA3 ) | (1 << PA5 ) | (1 << PA6 ));

    // 定时器1 初始化:普通模式、COM1A不启用、COM1B不启用、8预分频
    Drv_Timer1_init(T1_WGM_NOMAL, T1_COM_MODE_NONE, T1_COM_MODE_NONE, T1_CLK_SOURCE_CLK_8);
    // 使能TOV1中断
    Drv_Timer1_INT_Enable(INT_MODE_TOV, ENABLE);

    // 开全局中断
    sei();

    // ---------
    while(1)
    {
    }
    return 0;
}

你可能感兴趣的:(Atmega16-定时器1,CTC,PWM,相位修正PWM,相位频率修正PWM)