Atmega16-定时器2-(ques=2)
2016-06-02 10:22
399 查看
Atmega16-定时器2的使用 step by step。
-------------------------------------------------------------------------------------------------------------------------------------
待解决问题数量 = 2
-------------------------------------------------------------------------------------------------------------------------------------
而计算出的溢出周期为 T = ((1.0 / 8000000) * 1000000) * 1024* 256 = 32.768ms
考虑示波器的误差,可以认为这两个结果一致。
-------------------------------------------------------------------------------------------------------------------------------------
也就是说,如果我们设置的OCR2的值小于255,那么TCNT2就不能计数到最大值,也就不会发生计数溢出,没有TOV2中断。
CTC模式下,当TCNT2计数到TCNT2= OCR2时,就发生比较匹配,此时TCNT2会自动清0。
main.c:
2、在8MHz[b]/1预分频[/b]下,TCNT2=OCR2=0,每个定时器时钟周期里都有一次比较匹配发生,此时的比较周期最小,将产生最大的频率。
比较匹配周期 T = ((1.0 / 8000000) * 1000000) * 1* 1 = 0.125us,即每隔0.125us、OC2引脚翻转一次,方波周期是(0.125 * 2) us
对应的频率为 F = 1 / (0.125 * 2) * 1000000 = 4000000 = 4MHz
示波器测试如下:
CH1为OC2引脚输出的波形、结果为4.07MHz,和计算结果基本一致。
CH2为PA0的输出,TCNT2只计数到0,TCNT2没有溢出,没有产生溢出中断,所以PA0引脚就没有方波输出
3、增大OCR2,方波频率降低。
OCR2=255时对应最低频率为 F = 31.25KHz
此时TCNT2可以计数到255并溢出,将产生溢出中断,所以PA0引脚有方波输出,频率也是 F = 31.25KHz
4、使用最大的1024预分频,方波频率最低。
OCR2=255时对应最低频率为 F = 30.5Hz
此时TCNT2可以计数到255并溢出,将产生溢出中断,所以PA0引脚有方波输出,频率也是 F = 30.5Hz
-------------------------------------------------------------------------------------------------------------------------------------
2、OC2引脚一直为低电平,在每次比较匹配时都被清0拉低,而PA1引脚在每次比较匹配时都翻转一次
示波器测试如下:
在8MHz/1024预分频下,TCNT2=0,OCR2=128的配置下、OCR比较匹配的周期为T = ((1.0 / 8000000) * 1000000) * 1024 * 128 = 16384 = 16.384ms
PA1引脚在每次比较匹配时都翻转一次、输出的方波的周期是OCR比较匹配周期的2倍、即32.768ms,对应的频率为30.5Hz
示波器测量结果为16.2ms、和30.7Hz,和计算结果基本一致。
而TCNT2没有溢出,没有发生溢出中断,所以PA0引脚没有波形输出。
3、如果设置成比较匹配发生时OC2引脚置1,结果仅仅是OC2引脚一直拉高,PA1引脚的输出依然是30.5Hz的方波,PA0引脚无波形。
4、OCR2=255时,TCNT2才可以溢出,才会发生溢出中断,PA0引脚才会有波形输出。
-------------------------------------------------------------------------------------------------------------------------------------
Drv_Timer2.c中修改比较匹配中断、让OC2清0和置1两种配置交替出现,而main.c不变:
测试结果(方波):
1、OC2引脚出现方波,周期和PA1引脚一致,都是比较匹配周期的2倍,即32.768ms。
示波器测试如下:
使用变量来控制占空比,就可以得到了PWM波形:
测试代码([b]PWM波):[/b]
测试结果([b]PWM波):[/b]
1、占空比为64 / 256 = 25%。
示波器测试如下:
高电平宽度为8ms,脉冲周期为30.89ms,占空比为25.9%,和计算结果基本一致。
2、中断周期为32.768ms,每次进入中断都需要CPU来重新配置,如果中断频率很高,CPU的任务就会很繁重。
使用第三步和第四步的两种PWM模式,就可以让CPU避开这些工作。
而CTC模式一般就用来产生方波。
示波器输出如下:
在中断中不调用Drv_Timer2_init()来修改TCCR2,PA1得到的PWM波形就OK,只是CPU的任务会较重。
-------------------------------------------------------------------------------------------------------------------------------------
要强制匹配有输出,就得设置OC2引脚为比较匹配模式中的一种,如比较匹配时取反。
但是只要设置了OC2引脚,比较匹配立即生效,好像和FOC2是否设置无关。
-------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------
待解决问题数量 = 2
-------------------------------------------------------------------------------------------------------------------------------------
第零步: 阅读手册
-------------------------------------------------------------------------------------------------------------------------------------第一步: 普通模式
1、这一步使用普通模式输出脉冲,顺便测量一下自己设置的溢出时间是否OK。测试代码:
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初始化、使能溢出中断 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 // .用于捕获未定义中断函数的中断 // 没有包含interrupt.h的文件中的ISR()都被视为未定义的ISR(),这种ISR()可以被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模式
比较匹配如何产生:
而比较匹配的周期就是OCR2的数值决定的。也就是说,如果我们设置的OCR2的值小于255,那么TCNT2就不能计数到最大值,也就不会发生计数溢出,没有TOV2中断。
CTC模式下,当TCNT2计数到TCNT2= OCR2时,就发生比较匹配,此时TCNT2会自动清0。
1、比较匹配发生时OC2取反,用于产生方波
测试代码:
Drv_Timer2.c在第一步的基础上增加了2个函数(仍然使用PA0观察T2计数溢出的周期):// ========================================================================================================== // 设置TCNT2和OCR2的值 // // (1). 在比较匹配下、OCR2需要在TCNT2被设置之后设置 // ========================================================================================================== void Drv_Timer2_set_TCNT2_OCR2(const uint8_t tcnt2, const uint8_t ocr2) { TCNT2 = tcnt2; OCR2 = ocr2; } // ========================================================================================================== // 强制触发一次比较匹配 // // (1). FOC2写1后、立即进行比较操作 // ========================================================================================================== void Drv_Timer2_FOC2_enable(const uint8_t enable) { if(DISABLE == enable) { TCCR2 |= (1 << FOC2); } else { TCCR2 &= ~(1 << FOC2); } }
main.c:
// ========================================================================================================== // main函数 // ========================================================================================================== int main(void) { // ------------------------------------------------------------------------------------------------------ // 关全局中断 cli(); // PA0初始化为:输出0,置于T2溢出中断、用于测试T2的溢出时间 DDRA |= (IO_OUTPUT << DDA0); PORTA &= ~(1 << PA0); // 定时器2初始化:TCNT2=0、OCR2=0、CTC模式、1分频(@ 8MHz)、使能溢出中断发生比较匹配时OC2取反 Drv_Timer2_set_TCNT2_OCR2(0, 0); Drv_Timer2_init(T2_WGM_CTC, T2_COM_MODE_TOGGLE, T2_CLK_SOURCE_CLK_1); Drv_Timer2_INT_Enable(INT_MODE_TOV, ENABLE); //(OC2的比较状态的配置需要在设置数据方向寄存器之前完成) // PD7/OC2初始化为:输出0 DDRD |= (IO_OUTPUT << DDD7); PORTD &= ~(1 << PD7); // 开全局中断 sei(); // ------------------------------------------------------------------------------------------------------ while(1) { } return 0; }
测试结果:
1、这个代码产生了方波,同时TCNT2没有溢出,所以没有产生溢出中断,PA0引脚就没有方波输出。2、在8MHz[b]/1预分频[/b]下,TCNT2=OCR2=0,每个定时器时钟周期里都有一次比较匹配发生,此时的比较周期最小,将产生最大的频率。
比较匹配周期 T = ((1.0 / 8000000) * 1000000) * 1* 1 = 0.125us,即每隔0.125us、OC2引脚翻转一次,方波周期是(0.125 * 2) us
对应的频率为 F = 1 / (0.125 * 2) * 1000000 = 4000000 = 4MHz
示波器测试如下:
CH1为OC2引脚输出的波形、结果为4.07MHz,和计算结果基本一致。
CH2为PA0的输出,TCNT2只计数到0,TCNT2没有溢出,没有产生溢出中断,所以PA0引脚就没有方波输出
3、增大OCR2,方波频率降低。
OCR2=255时对应最低频率为 F = 31.25KHz
此时TCNT2可以计数到255并溢出,将产生溢出中断,所以PA0引脚有方波输出,频率也是 F = 31.25KHz
4、使用最大的1024预分频,方波频率最低。
OCR2=255时对应最低频率为 F = 30.5Hz
此时TCNT2可以计数到255并溢出,将产生溢出中断,所以PA0引脚有方波输出,频率也是 F = 30.5Hz
-------------------------------------------------------------------------------------------------------------------------------------
2、比较匹配时OC2清0
测试代码:
Drv_Timer2.c中增加比较匹配中断,在其中对PA1引脚取反,其他部分不变:// ========================================================================================================== // TIMER2 比较匹配中断服务程序 // ========================================================================================================== ISR(TIMER2_COMP_vect) { PORTA ^= (1 << PA1); }在main.c中修改工作CTC模式为:发生比较匹配时OC2清0,并设置PA1引脚初始化为:输出0,用于测试比较匹配周期:
// ========================================================================================================== // main函数 // ========================================================================================================== int main(void) { // ------------------------------------------------------------------------------------------------------ // 关全局中断 cli(); // PA0初始化为:输出0,置于T2溢出中断函数里面、用于测试T2的溢出时间 DDRA |= (IO_OUTPUT << DDA0); PORTA &= ~(1 << PA0); // PA1初始化为:输出0,置于T2比较匹配中断函数里面、用于测试T2的比较匹配周期 DDRA |= (IO_OUTPUT << DDA1); PORTA &= ~(1 << PA1); // 定时器2初始化:TCNT2=0、OCR2=128、CTC模式、32分频(溢出时间=1ms @ 8MHz)、发生比较匹配时OC2清0 Drv_Timer2_set_TCNT2_OCR2(0, 128); Drv_Timer2_init(T2_WGM_CTC, T2_COM_MODE_CLEAR, T2_CLK_SOURCE_CLK_1024); // 使能溢出中断,使能比较匹配中断 Drv_Timer2_INT_Enable(INT_MODE_TOV, ENABLE); Drv_Timer2_INT_Enable(INT_MODE_OCF, ENABLE); //(OC2的比较状态的配置需要在设置数据方向寄存器之前完成) // PD7/OC2初始化为:输出0 DDRD |= (IO_OUTPUT << DDD7); PORTD &= ~(1 << PD7); // 开全局中断 sei(); // ------------------------------------------------------------------------------------------------------ while(1) { } return 0; }
测试结果:
1、CH1为OC2引脚输出,CH2为PA1引脚输出2、OC2引脚一直为低电平,在每次比较匹配时都被清0拉低,而PA1引脚在每次比较匹配时都翻转一次
示波器测试如下:
在8MHz/1024预分频下,TCNT2=0,OCR2=128的配置下、OCR比较匹配的周期为T = ((1.0 / 8000000) * 1000000) * 1024 * 128 = 16384 = 16.384ms
PA1引脚在每次比较匹配时都翻转一次、输出的方波的周期是OCR比较匹配周期的2倍、即32.768ms,对应的频率为30.5Hz
示波器测量结果为16.2ms、和30.7Hz,和计算结果基本一致。
而TCNT2没有溢出,没有发生溢出中断,所以PA0引脚没有波形输出。
3、如果设置成比较匹配发生时OC2引脚置1,结果仅仅是OC2引脚一直拉高,PA1引脚的输出依然是30.5Hz的方波,PA0引脚无波形。
4、OCR2=255时,TCNT2才可以溢出,才会发生溢出中断,PA0引脚才会有波形输出。
-------------------------------------------------------------------------------------------------------------------------------------
3、在比较匹配时、可以让OC2引脚交替出现清0和置1,以输出方波和PWM波形
方波:
测试代码(方波):Drv_Timer2.c中修改比较匹配中断、让OC2清0和置1两种配置交替出现,而main.c不变:
// ========================================================================================================== // TIMER2 比较匹配中断服务程序 // ========================================================================================================== ISR(TIMER2_COMP_vect) { volatile static uint8_t temp = 0; PORTA ^= (1 << PA1); if(0 == temp) { temp = 1; Drv_Timer2_init(T2_WGM_CTC, T2_COM_MODE_CLEAR, T2_CLK_SOURCE_CLK_1024); } else { temp = 0; Drv_Timer2_init(T2_WGM_CTC, T2_COM_MODE_SET, T2_CLK_SOURCE_CLK_1024); } }
测试结果(方波):
1、OC2引脚出现方波,周期和PA1引脚一致,都是比较匹配周期的2倍,即32.768ms。
示波器测试如下:
PWM波形:
在Drv_Timer2.c的比较匹配中断服务程序中,修改OCR2的值,就可以更改OC2引脚的方波的占空比。使用变量来控制占空比,就可以得到了PWM波形:
测试代码([b]PWM波):[/b]
// ========================================================================================================== // TIMER2 比较匹配中断服务程序 // ========================================================================================================== ISR(TIMER2_COMP_vect) { volatile static uint8_t temp = 0; PORTA ^= (1 << PA1); if(0 == temp) { temp = 1; Drv_Timer2_set_TCNT2_OCR2(0, 64); Drv_Timer2_init(T2_WGM_CTC, T2_COM_MODE_CLEAR, T2_CLK_SOURCE_CLK_1024); } else { temp = 0; Drv_Timer2_set_TCNT2_OCR2(0, 255-64); Drv_Timer2_init(T2_WGM_CTC, T2_COM_MODE_SET, T2_CLK_SOURCE_CLK_1024); } }
测试结果([b]PWM波):[/b]
1、占空比为64 / 256 = 25%。
示波器测试如下:
高电平宽度为8ms,脉冲周期为30.89ms,占空比为25.9%,和计算结果基本一致。
2、中断周期为32.768ms,每次进入中断都需要CPU来重新配置,如果中断频率很高,CPU的任务就会很繁重。
使用第三步和第四步的两种PWM模式,就可以让CPU避开这些工作。
而CTC模式一般就用来产生方波。
CTC模式不要用来做频率高的PWM
比如:8MHz、1预分频下,OCR2=10时,OC2的PWM波形和PA1引脚的输出都不正常。----待解释下面的输出波形-question-001示波器输出如下:
在中断中不调用Drv_Timer2_init()来修改TCCR2,PA1得到的PWM波形就OK,只是CPU的任务会较重。
-------------------------------------------------------------------------------------------------------------------------------------
强制比较匹配FOC2:
最后,普通模式下使用FOC2强制比较匹配有什么效果呢,待测试-question-002要强制匹配有输出,就得设置OC2引脚为比较匹配模式中的一种,如比较匹配时取反。
但是只要设置了OC2引脚,比较匹配立即生效,好像和FOC2是否设置无关。
-------------------------------------------------------------------------------------------------------------------------------------
第三步: 快速PWM模式
-------------------------------------------------------------------------------------------------------------------------------------第四步: 相位修正PWM模式
相关文章推荐
- UIScrollView无法响应touch事件解决方法
- UI(base)-1
- iOS开发示例————使用CAShapeLayer&UIBezierPath绘制数据饼图
- Invalid byte 3 of 3-byte UTF-8 sequence.
- Undefined symbols for architecture x86_64:
- java 双层for的break continue代码精简
- The JSP specification requires that an attribute name is preceded by whitespace
- Map的插入操作和按照value排序
- UITableView中tableHeadView的BUG
- 使用CAShapeLayer与UIBezierPath画出想要的图形
- Solr中配置文件schema.xml之copyField 与multiValued用途
- GUI(图形用户界面)
- Requested registry access is not allowed(不允许所请求的注册表访问权)
- Maven项目Build jar
- Android Studio 2.0以后出现Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled.
- 【APIs — A Strategy Guide】第一章 API的机遇
- ViewPager 里面嵌套界面
- WPF checkbox绑定和通过值更新将存入的 1-0 转换成 true false
- Datagrid动态设置列标题的的扩展方法
- vector list array deque