Atmega16-定时器2的使用 step by step。
编译环境:AVR Studio 4.19 +avr-toolchain-installer-3.4.1.1195-win32.win32.x86
芯片型号:ATmega16
芯片主频:8MHz
测试说明:
1、OC2引脚输出比较匹配的波形
2、PA0在TOV2中断时取反
3、PA1在OCF2中断时取反
-------------------------------------------------------------------------------------------------------------------------------------
第零步: 阅读手册
-------------------------------------------------------------------------------------------------------------------------------------
第一步: 普通模式
1、这一步使用普通模式输出脉冲,顺便测量一下自己设置的溢出时间是否OK。
测试代码:
Drv_Timer.h
// 定时器中断模式
typedef enum
{
INT_MODE_TOV = 0,
INT_MODE_OCF = 1,
INT_MODE_ICF = 2
} TIMER_INT_MODE;
// 定时器2
typedef enum
{
T2_WGM_NOMAL = 0, // 普通模式
T2_WGM_PHASE_PWM = 1,
T2_WGM_CTC = 2,
T2_WGM_FAST_PWM = 3,
T2_COM_MODE_NONE = 0,
T2_COM_MODE_TOGGLE = 1,
T2_COM_MODE_CLEAR = 2,
T2_COM_MODE_SET = 3,
T2_CLK_SOURCE_NONE = 0,
T2_CLK_SOURCE_CLK_1 = 1,
T2_CLK_SOURCE_CLK_8 = 2,
T2_CLK_SOURCE_CLK_32 = 3,
T2_CLK_SOURCE_CLK_64 = 4,
T2_CLK_SOURCE_CLK_128 = 5,
T2_CLK_SOURCE_CLK_256 = 6,
T2_CLK_SOURCE_CLK_1024 = 7
} TIMER2_MODE;
Drv_Timer.c
// ==========================================================================================================
// 定时器0/1/2 驱动模块
// ==========================================================================================================
#include "Drv_Timer.h"
#include <avr/interrupt.h>
// ==========================================================================================================
// TIMER2 初始化
//
// 参数:wave_mode 工作模式/波形产生模式选择
// OC_mode 比较匹配/PWM输出模式选择
// clk_source 时钟源和预分频选择
//
// 写TCCR2时需要清除bit7=FOC2
//
// 定时器溢出周期 T = ((1.0 / 8000000) * 1000000) * clk_source * 256 ( @ 8MHz )
// ==========================================================================================================
void Drv_Timer2_init(const uint8_t wave_mode, const uint8_t com_mode, const uint8_t clk_source)
{
uint8_t wgm20,wgm21;
wgm20 = wave_mode & 0x01;
wgm21 = (wave_mode & 0x02) >> 1;
// 写TCCR2时需要将bit7=FOC2清0
TCCR2 = (wgm20 << 6)| // 工作模式/波形产生模式选择
(wgm21 << 3)|
((com_mode & 0x03) << 4)| // 比较匹配/PWM输出模式选择
((clk_source & 0x07) << 0); // 时钟源和预分频选择
}
// ==========================================================================================================
// TIMER2 中断使能
//
// 参数:mode = INT_MODE_TOV 或 INT_MODE_OCF 或 INT_MODE_ICF
// enable = ENABLE 或 DISABLE
//
// 可以单独使能/禁止一种模式的中断
//
// ==========================================================================================================
void Drv_Timer2_INT_Enable(const uint8_t mode, const uint8_t enable)
{
if(INT_MODE_TOV == mode)
{
if(DISABLE == enable)
{
TIMSK &= ~(1 << TOIE2);
}
else
{
TIMSK |= (1 << TOIE2);
}
TIFR |= (1 << TOV2);
}
if(INT_MODE_OCF == mode)
{
if(DISABLE == enable)
{
TIMSK &= ~(1 << OCIE2);
}
else
{
TIMSK |= (1 << OCIE2);
}
TIFR |= (1 << OCF2);
}
}
// ==========================================================================================================
// TIMER2 溢出中断服务程序
// ==========================================================================================================
ISR(TIMER2_OVF_vect)
{
PORTA ^= (1 << PA0);
}
main.c
// ==========================================================================================================
// 主函数
// ==========================================================================================================
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Drv_Timer.h"
#include "config.h"
// ==========================================================================================================
// main函数
// ==========================================================================================================
int main(void)
{
// 关全局中断
cli();
// PA0初始化为:输出0
DDRA |= (IO_OUTPUT << DDA0);
PORTA &= ~(1 << PA0);
// 定时器2初始化、工作在普通模式、OC2引脚不连接CTC、预分频=1024、使能溢出中断
Drv_Timer2_init(T2_WGM_NOMAL, T2_COM_MODE_NONE, T2_CLK_SOURCE_CLK_1024);
Drv_Timer2_INT_Enable(INT_MODE_TOV, ENABLE);
// 开全局中断
sei();
while(1)
{
}
return 0;
}
// ==========================================================================================================
// 伪中断BADISR_vect
//
// ==========================================================================================================
ISR(BADISR_vect)
{
DDRA |= (IO_OUTPUT << DDA1);
PORTA ^= (1 << PA1);
}
测试结果:
1、示波器查看 PA0引脚输出的脉冲的宽度为 32.2ms而计算出的溢出周期为 T = ((1.0 / 8000000) * 1000000) * 1024* 256 = 32.768ms
考虑示波器的误差,可以认为这两个结果一致。
-------------------------------------------------------------------------------------------------------------------------------------
第二步: CTC模式
0、比较匹配如何产生:
而比较匹配的周期就是 OCR2的数值决定的。也就是说,如果我们设置的 OCR2的值小于 255,那么 TCNT2就不能计数到最大值,也就不会发生计数溢出,没有 TOV2中断。
CTC模式下,当 TCNT2计数到