如何在ATmega328上停止计时器

时间:2017-06-24 10:07:04

标签: timer arduino avr

我写了一些简单的代码,我在我的Arduino Uno上使用了timer1。问题是我无法以任何方式停止计时器。

我正在使用该程序计数并在显示屏上显示引脚2上外部中断的数量,同时测量时间。但是当我按下按钮fin时,我想停止为程序生成中断,这会增加名为cas的可变时间。你能以某种方式帮忙吗?

我的代码:

#include <OLED_I2C.h>
#define alarm_output 10 
#define fin 13

int suma=0;
int alarm=0;
float cas=0;

OLED  myOLED(SDA, SCL, 8);
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];
extern uint8_t SmallFont[];

void setup(void) {

   pinMode(alarm_output,OUTPUT);
   digitalWrite(alarm_output,LOW);
   pinMode(fin,INPUT_PULLUP);
   pinMode(9,INPUT_PULLUP);

   //interrupt
   interrupts(); 
   attachInterrupt(digitalPinToInterrupt(2), displej, CHANGE);

   //first screen
   myOLED.begin();
   myOLED.setFont(SmallFont);
   myOLED.print("TIME:", 0, 30);
   myOLED.print("INTERRUPT:", 0, 56);
   myOLED.print("Laser game", CENTER, 0);
   myOLED.setFont(MediumNumbers);
   myOLED.printNumF(cas,1,RIGHT,20);
   myOLED.setFont(BigNumbers);
   myOLED.printNumI(suma, RIGHT, 40);
   myOLED.update();

   //start loop
   up:;
   if(digitalRead(9)==1)
      goto up;

   // TIMER 1 for interrupt frequency 10 Hz:
   cli(); // stop interrupts
   TCCR1A = 0; // set entire TCCR1A register to 0
   TCCR1B = 0; // same for TCCR1B
   TCNT1  = 0; // initialize counter value to 0
   // set compare match register for 10 Hz increments
   OCR1A = 24999; // = 16000000 / (64 * 10) - 1 (must be <65536)
   // turn on CTC mode
   TCCR1B |= (1 << WGM12);
   // Set CS12, CS11 and CS10 bits for 64 prescaler
   TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
   // enable timer compare interrupt
   TIMSK1 |= (1 << OCIE1A);
   sei(); // allow interrupts
}

void displej(){
   suma++;
   alarm=3; 
}

ISR(TIMER1_COMPA_vect){
   cas=cas+0.1;
   if(alarm>0)
      alarm--;  

}

void loop(void) {
   myOLED.setFont(MediumNumbers);
   myOLED.printNumF(cas,1,RIGHT,20);
   myOLED.setFont(BigNumbers);
   myOLED.printNumI(suma, RIGHT, 40);
   myOLED.update();

   if(digitalRead(fin)==0){
      cli();
      TCCR1B |= (0 << CS12) | (0 << CS11) | (0 << CS10);  //this do now work
      detachInterrupt(digitalPinToInterrupt(2));
      sei();
   }
   if(alarm>0)
       digitalWrite(alarm_output,HIGH);
   else
       digitalWrite(alarm_output,LOW);

   delay(10);

}

2 个答案:

答案 0 :(得分:2)

当然可以!有两种方法可以做到。您只需停止计时器中断,但使用以下命令保持计时器运行:

TIMSK1 &= ~(1 << OCIE1A);

或者,您可以通过将时钟源更改为“无”来完全停止计时器

TCCR1B &= ~(1<< CS12);
TCCR1B &= ~(1<< CS11);
TCCR1B &= ~(1<< CS10);

它有效地撤消了您首先选择时钟源所做的操作。此后,CS12-CS11-CS10位将为0-0-0,时钟源将停止。见第134数据表。

答案 1 :(得分:1)

我已经测试了“关闭计时器”的所有三种方法。只需在下面的代码中注释掉您喜欢的那个就可以看到它。这三个都有效地让Arduino的LED熄灭闪烁。

void setup(void) {
   pinMode(13,OUTPUT);
   digitalWrite(13,LOW);
   interrupts(); 

   // TIMER 1 for interrupt frequency 10 Hz:
   cli(); // stop interrupts
   TCCR1A = 0; // set entire TCCR1A register to 0
   TCCR1B = 0; // same for TCCR1B
   TCNT1  = 0; // initialize counter value to 0
   // set compare match register for 10 Hz increments
   OCR1A = 24999; // 200 millisecond cycle
   // turn on CTC mode
   TCCR1B |= (1 << WGM12);
   // Set CS12, CS11 and CS10 bits for 64 prescaler
   TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
   // enable timer compare interrupt
   TIMSK1 |= (1 << OCIE1A);
   sei(); // allow interrupts
}

volatile uint8_t count = 0;
volatile uint8_t timer_flip = 0;


ISR(TIMER1_COMPA_vect){
   if (timer_flip == 0)
     timer_flip = 1;
   else
     timer_flip = 0;

   if (timer_flip == 1)
     digitalWrite(13, HIGH);
   else
     digitalWrite(13, LOW);

   count++;  
}

void loop(void)
{
  if (count > 100)  // runs for a few seconds
  {
    //cli();  // One way to disable the timer, and all interrupts

    //TCCR1B &= ~(1<< CS12);  // turn off the clock altogether
    //TCCR1B &= ~(1<< CS11);
    //TCCR1B &= ~(1<< CS10);

    //TIMSK1 &= ~(1 << OCIE1A); // turn off the timer interrupt
    }
  }

这个确切的代码现在正在我旁边的Uno上运行。我已经测试了上面所有三个“关闭”机制,它们都有效。

为了制作一个最小的,可验证的例子,我剥离了所有OLED的东西。我将引脚13更改为输出并将其设置为闪烁LED(尽管它可以停止定时器和/或中断明显禁用)。

几个学习要点:

  • 如果没有额外的电路,就不应该使用引脚13作为“fin”按钮 - 请参阅this Arduino official reference
  • 您应该声明volatile在中断服务程序中写入的任何变量。
  • 您选择关闭计时器的方法取决于您的目标。您只需禁用定时器中断,禁用所有中断,或者只是关闭时钟源。选择权归你所有。