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

发布者:VelvetDreamer最新更新时间:2022-02-14 来源: eefocus关键字:Atmega16  定时器1  波形 手机看文章 扫描二维码
随时随地手机看文章

Atmega16-定时器1的使用 step by step。

之前完成了定时器2的各项功能的测试后,这里就很容易做了。


编译环境:AVR Studio 4.19 +avr-toolchain-installer-3.4.1.1195-win32.win32.x86

芯片型号:ATmega16

芯片主频:8MHz


测试说明:

1、 OC1A和 OC1B引脚输出比较匹配的波形

2、 PA2在 TOV1中断时取反

3、 PA3在 OCF1A中断时取反

4、 PA5在 OCF1B中断时取反

5、 PA6在 ICF1中断时取反

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


小结:

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

      因为这样就只需要设置OCR1A,不需要每次TOV1中断都要重新设置TCNT1的计数初值。

2、CTC模式下、OC1A和OC1B的频率由OCR1A或ICR1决定,OCR1A和OCR1B都用来控制OC1A和OC1B的相位。

      CTC模式下的脉冲频率最大可达4MHz。

3、快速/高频PWM用于:功率调节、整流、ADC

      当OCR1A/OCR1B超过TOP值时,依然有PWM波形输出:TCNT1=(OCR1A或OCR1B)&TOP时发生比较匹配

      可以得到相当精确的PWM频率和占空比,如38KHz、1/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;

}

测试结果:

1、 PA2引脚电平每个 66ms翻转一次。

      定时器1溢出周期为 T = ((1.0/8000000)*1000000) * 8 * 65536 / 1000 = 65.536 ms。

      两者基本一致。

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

第二步: CTC模式

1、使用OCR1A作为TOP值:WGM[13:10] = 0100

说明:

TCNT1加计数到TCNT1 = OCR1A时,比较匹配A发生、OC1A引脚电平翻转,同时TCNT1会被清0。


TCNT1加计数到TCNT1 = OCR1B时,比较匹配B发生、 OC1B引脚电平翻转。


但是,如果OCR1A < OCR1B,那么因为在TCNT1 = OCR1A时、TCNT1会被清0,不会继续增加到更大的OCR1B,


所以OCF1B永远不会发生、OC1B引脚将永远不会翻转。


测试代码:

Drv_Timer.c中增加1个初值设置函数和2个中断服务函数:


// ==========================================================================================================

//      设置TCNT1、OCR1A、OCR1B的值

// 

// (1). 在比较匹配下、OCR1A、OCR1B需要在TCNT1被设置之后设置

//      相应的,ICP1也需要在TCNT1被设置之后设置

// 

// ==========================================================================================================

[1] [2] [3] [4]
关键字:Atmega16  定时器1  波形 引用地址:B001-Atmega16-定时器1-(ques=1)

上一篇:B001-Atmega16-看门狗WDT-(ques=1)
下一篇:B001-Atmega16-定时器2-(ques=4)

推荐帖子

分享芯片的Powerpad功能介绍
芯片的powerpad,功能上是用来给芯片散热的,大部分的芯片都带Powerpad。但是有几个问题要注意:Powerpad必须接GND,并且是充分与PCB上的GND焊接,并且通过扩展PCBGND面积来加强散热,例如四层板,打孔连接,利用中间层的GND来散热。Powepad处,一般和模拟GND连接。电源芯片也一般会将功率GND和模拟GND分开,再powerpad处短接。Powerpad上也有电流的,这主要关系功率回路,layout设计上都是要功率回路尽量小。以下是TPS54160
qwqwqw2088 模拟与混合信号
室内定位汇总贴
Qorvo技术视频之面向汽车应用的UWB:工程入门知识 安信可UWB室内定位模组NodeMCU-BU01 Qorvo专家谈UWB 全球UWB设备出货量将达到3.17亿 专家带你谈UWB 什么是UWB技术 UWB室内定位主要针对商场及地下车库怎么就没有被利用起来 一文简述UWB 什么使UWB成为与众不同 UWB技术的潜在用途 UWB实现安全测距和精度技术介绍及其工作原理 uwb有哪几种定位方式 U
btty038 RF/无线
msp430的指纹代码
各位大神,最近想玩一下指纹模块,有没有与之相关的代码,私发给我,一起学习一下,谢谢了。msp430的指纹代码不同指纹模块的操作方法不同,你有什么模块就去看该模块的使用手册。这和你用的模块有有关,相反跟msp430关系不大,你应该找模块提供商要代码,他们会有例程代码的。我买了一个指纹模块,没有历程代码,只有使用手册
mxh1 模拟与混合信号
有带PS/2接口的M3没有?
请问大家有带PS/2接口的M3没有?有带PS/2接口的M3没有?应该没有,没有见过MCU上面用这种接口也没有用啊PS2并非是专门规格的硬件,所以不会有。需要的话,用普通IO实现即可。谢谢!明白了。
ZHANGXUEJIE 微控制器 MCU
液晶显示器出现垂直亮线
我的宏基17寸的液晶显示器用了大约2年左右。半月前出现问题,显示器开不了了,拿到维修处说是驱动板坏了,花了我150刚修好,但是前天电脑右端大概三分之一处出现一道垂直亮线,但是把刷新率调到60就没有了,请问这是什么原因,会不会是上次维修没有修好的遗留问题,还是什么原因呢??最后在60的刷新率也会有亮线,有时候会消失一会再出来。液晶显示器出现垂直亮线1、液晶虽然与CRT工作原理不同,但刷新率还是60最好,因为不是扫描方式,所以不会像CRT那样闪烁2、这种状况一般是液晶板快要光荣下岗了。支持搂
eestudent 嵌入式系统
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved