返回列表 发帖

m16 time1 無法正確 1sec 跑一次 timer1_ovf_isr

學習進度: 1sec 霹靂燈(五顆LED來回閃爍 1~5~1)
實作目標: m16/內建1Mhz OSC/ timer1方式 1sec 跑一次 timer1_ovf_isr 點燈
問題未解: 以 ICC AVR 內建的 Applicate Builder 生成的 time1 無法正確 1sec 跑一次 timer1_ovf_isr
以下為實作源碼,請學長們指正.謝謝.
----------------------------------------------------------------------------
#include <iom16v.h>
#include <macros.h>
#include "delaytime.c"
#include "led.h"
#include "led.c"

unsigned int timer1_count=0 ;

void LED_Init(void)
{

         DDRA|=0XE0;
         PORTA&=0X1F;
         DDRC|=0X03;
         PORTC&=0XFC;
}
void key_Init(void)
{
         DDRC|=0XE0;
         DDRC&=0XE3;
         PORTC&=0X1F;
}

//TIMER1 initialize - prescale:256
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 1Sec
// actual value:  1.000Sec (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0xF0; //setup
TCNT1L = 0xBE;
OCR1AH = 0x0F;
OCR1AL = 0x42;
OCR1BH = 0x0F;
OCR1BL = 0x42;
//OCR1CH = $OCR1CH$;
//OCR1CL = $OCR1CL$;
ICR1H  = 0x0F;
ICR1L  = 0x42;
TCCR1A = 0x00;
TCCR1B = 0x04; //start Timer
}

void Gpio_Init(void)
{
           LED_Init();
         key_Init();
        timer1_init();
}

#pragma interrupt_handler timer1_compa_isr:7
void timer1_compa_isr(void)
{
//compare occured TCNT1=OCR1A
}

#pragma interrupt_handler timer1_compb_isr:8
void timer1_compb_isr(void)
{
//compare occured TCNT1=OCR1B
}

#pragma interrupt_handler timer1_ovf_isr:9
void timer1_ovf_isr(void)                       // 燈號運作正常但時序不正確無法掌控...
{
//TIMER1 has overflowed
TCNT1H = 0xF0; //reload counter high value
TCNT1L = 0xBE; //reload counter low value
        timer1_count++;
        switch(timer1_count)
        {
                case 1:
                {
                          LED2_OFF;
                        LED1_ON;
                } break;
                case 2:
                {
                         LED1_OFF;
                        LED2_ON;
                } break;
                case 3:
                {
                          LED2_OFF;
                        LED3_ON;
                } break;
                case 4:
                {
                          LED3_OFF;
                        LED4_ON;
                } break;
                case 5:
                {
                          LED4_OFF;
                        LED5_ON;
                } break;
                case 6:
                {
                          LED5_OFF;
                        LED4_ON;
                } break;
                case 7:
                {
                          LED4_OFF;
                        LED3_ON;
                } break;
                case 8:
                {
                          LED3_OFF;
                        LED2_ON;
                        timer1_count=0;
                } break;
        }
}

void main(void)
{
CLI(); //disable all interrupts
         Gpio_Init();
         ALL_ON;
         delay_nms(500);
         ALL_OFF;
         delay_nms(500);

MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x1C; //timer interrupt sources
SEI(); //re-enable interrupts
         while(1)
         {
                          // led();
         }
}

回复 1# jemmy0938


    不用采用那种方式,可以采用如下方式:
  1. /********************************************************
  2. * timer2_init: 初始化定时器2:普通模式定时0.02s *
  3. * 输入:无 *
  4. * 输出:无 *
  5. ********************************************************/
  6. void timer2_init(void)
  7. {
  8. TCCR2=0; //无时钟源,普通模式
  9. // OCR2=100; //定时0.02s/8M 100
  10. TCNT2=100;
  11. TIMSK|=(1<<TOIE2); //溢出中断允许
  12. }
  13. /*********************************
  14. * timer2_start:开启定时器2 *
  15. * 输入:无 *
  16. * 输出:无 *
  17. *********************************/
  18. void timer2_start(void)
  19. {
  20. TCCR2=0b00000111;
  21. }



  22. /*******************************************************************
  23. * timer2_isr: 定时器2中断处理函数 *
  24. * 输入:无 *
  25. * 输出:无 *
  26. *******************************************************************/
  27. #pragma interrupt_handler timer2_isr:5
  28. void timer2_isr(void)
  29. {
  30. TCNT2=100;
  31. timer2_count++;
  32. switch (timer2_count)
  33. {
  34. //第0.2s
  35. case 10:
  36. {
  37. //adc_start(0); //采集电流
  38. } break;

  39. }

  40. }
复制代码

TOP

本帖最后由 panfeng881112 于 2010-11-19 21:25 编辑

回复 1# jemmy0938


    首先欢迎您来我们论坛提问!
这里有一个公式!不知道能帮到您多少!
发生溢出中断时间(us)=震荡主频(Hz)*(65535-(TCNT1H*256+TCNT1L))


如果还有疑问尽管来提!要相信我们一定可以帮您解决的!

TOP

感謝各位學長們教導..@@
經過多方驗證後發現應該是MCU主頻錯誤導致頻率誤差.
這幾天一直誤認 PROGISP 中的 fuse 設定就是由片內讀取的設定 int 1Mhz.
經重新 fuse 設 int. 8Mhz+64ms 以 256 除頻 timer1 得出正確結果 1sec.
下列程式執行正確無誤...@@
-------------------------------------------------------------------------------------
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0x85; //setup
TCNT1L = 0xEF;
OCR1AH = 0x7A;
OCR1AL = 0x11;
TCCR1A = 0x00;
TCCR1B = 0x0C; //start Timer
}

#pragma interrupt_handler timer1_compa_isr:7
void timer1_compa_isr(void)
{
        timer1_count++;
}


void main(void)
{
CLI(); //disable all interrupts
         Gpio_Init();
         timer1_init();

         ALL_ON;
         delay_nms(200);
         ALL_OFF;
         delay_nms(200);

MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x10;

SEI(); //re-enable interrupts
         while(1)
         {
        switch(timer1_count)
        {
                case 1:
                {
                          LED2_OFF;
                        LED1_ON;
                } break;
                case 2:
                {
                         LED1_OFF;
                        LED2_ON;
                } break;
                case 3:
                {
                          LED2_OFF;
                        LED3_ON;
                } break;
                case 4:
                {
                          LED3_OFF;
                        LED4_ON;
                } break;
                case 5:
                {
                          LED4_OFF;
                        LED5_ON;
                } break;
                case 6:
                {
                          LED5_OFF;
                        LED4_ON;
                } break;
                case 7:
                {
                          LED4_OFF;
                        LED3_ON;
                } break;
                case 8:
                {
                          LED3_OFF;
                        LED2_ON;
                        timer1_count=0;
                } break;
        }
}
}

TOP

调试通了,那就恭喜了。

TOP

我是新手!谢谢分享!学习了!呵呵~

TOP

本帖最后由 jemmy0938 于 2010-11-21 16:23 编辑

請問各位學長們:
設定 PORTC=0X03/ DDRC=0X03 後,量第2,3,4 依然是5V.這樣有正確嗎?
目前正學 KEYPAD 用到 PORTC 2~7, 可是怎樣設2,3,4 電壓都是 5V.
各位學長們有這情況嗎?經設定 PORTC=0X03/ DDRC=0X03 測 PC2,3,4,5 為高.測 6,7 可受控.
設 PORTD=0x00 / DDRD =0x00 測 PD7 為高,其他都正常.
這現象是 mcu 故障了?

TOP

回复 7# jemmy0938


    设定IO口输出方向:1 用或的方式;0用与的方式;
    如 PC0要为输出,则  DDRC|=0X01;
    如PC10要为输入,则  DDRC&=0XFE;
    同理控制的时候。

TOP

謝謝學長教導:再問一個情況作為總結.
中斷 T/C1 OVL + comp A+B 三種一起使用可以嗎?
1)OVL 方式功能一直都正常
2) COMP A/B 偶不正常,如:開機進 COMP A 第一次就停了.
3)兩天前一直用OVL+COMPA+COMPB,今天忽然又無法使用了,是否是編譯器的問題?
代碼如下,
----------------------------------------------------------------------------
void timer1_init(void)
{
TCCR1B = 0x00;
TCNT1H = 0x85;
TCNT1L = 0xEE;
OCR1AH = 0x01;
OCR1AL = 0x38;
OCR1BH = 0x01;
OCR1BL = 0x38;
TCCR1A = 0x00;
TCCR1B = 0x0C; //start Timer
}

void port_init(void)
{
PORTA = 0x00;
DDRA  = 0x00;
PORTB = 0x0F;
DDRB  = 0x00;
PORTC = 0x0F; //m103 output only
DDRC  = 0x00;
PORTD = 0x00;
DDRD  = 0x00;
}


#pragma interrupt_handler timer1_compa_isr:7
void timer1_compa_isr(void)
{
//compare occured TCNT1=OCR1A
keyVal = ((PINB&0x0F) ^0X0F);
}

#pragma interrupt_handler timer1_compb_isr:8
void timer1_compb_isr(void)
{
//compare occured TCNT1=OCR1B
timer1_count++;
}

#pragma interrupt_handler timer1_ovf_isr:9
void timer1_ovf_isr(void)
{
//TIMER1 has overflowed
TCNT1H = 0x85; //reload counter high value
TCNT1L = 0xEE; //reload counter low value
}

void main(void)
{
CLI(); //disable all interrupts
         port_init();
         timer1_init();
         ALL_ON;
         delay_nms(200);
         ALL_OFF;
         delay_nms(200);

MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x1C;
   SEI(); //re-enable interrupt
         while(1)
         {

switch(timer1_count)
        {
                case 1:
                {
                          LED2_OFF;
                        LED1_ON;
                } break;
                case 2:
                {
                         LED1_OFF;
                        LED2_ON;
                } break;
                case 3:
                {
                          LED2_OFF;
                        LED3_ON;
                } break;
                case 4:
                {
                          LED3_OFF;
                        LED4_ON;
                } break;
                case 5:
                {
                          LED4_OFF;
                        LED5_ON;
                } break;
                case 6:
                {
                          LED5_OFF;
                        LED4_ON;
                } break;
                case 7:
                {
                          LED4_OFF;
                        LED3_ON;
                } break;
                case 8:
                {
                          LED3_OFF;
                        LED2_ON;
                        timer1_count=0;
                } break;
//                case 6:
//                 {
        //                   ALL_OFF;
        //                   timer1_count=0;
        //        } break;
        }

}
}

TOP

經查 <ATMEGA16单片机中文说明> 後發現 CTC 模式下比較觸發後會將 TCNT1 清零,
若此.則溢出中斷根本就不會發生了.可是網路上卻有不少範例是用 CTC 比較+溢出中斷,非常不解.

TOP

返回列表

最新关注 关闭


关于论坛注册,最新修改,请网友们注意

由于最近大量垃圾信息出现在我们的论坛,为了营造一个良好的氛围,目前论坛只开发邀请注册,你可以点击以下链接自动邀请注册(如果有人使用了点击下一个试一试) ...


查看
珩源工控论坛热诚欢迎您联系我们进行合作!

Powered by Discuz! 7.2© 2001-2009 Comsenz Inc.

珩源工控论坛 ( 桂ICP备19004328号) |论坛统计|WAP| 客服中心-www.hymcu.com
  

GMT+8, 2024-11-24 17:39, Processed in 1.094974 second(s), 5 queries, Gzip enabled.