如何使用计时器更新ISR中的变量


8

我正在尝试使用计数器检查Timer3的频率。声明为易失性的计数器的值在ISR中递增,并且每秒在主循环中显示总和,并将该值重置为零。

计时器已正确设置。(如果选择3Hz计时器,我会看到LED闪烁)

问题

计数器不增加。这是输出:

Setup Completed
tick: 1
tick: 0
tick: 0
tick: 0

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);

  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B = 20; // 800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();

  Serial.println("Setup completed");
}

void loop()
{
  if (millis() % 1000 == 0)
  {
    Serial.print(" tick: ");
    Serial.println(cont);
    cont = 0;
  }
}

ISR(TIMER3_COMPB_vect)
{
  //digitalWrite(13, digitalRead(13) ^ 1);
  cont++;
}

编辑 此计时器用于从加速度计读取模拟值并将其存储在float数组中。但是此刻,我仍停留在此更新问题上。

解决方案1 感谢Gerben

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3A = 20; // 20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  delay(1000);
  Serial.println(cont);
  cont = 0;
}

ISR(TIMER3_COMPB_vect)
{
  cont++;
}

解决方案2 感谢BrettM

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B =  20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  //TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  Serial.println(cont); 
  cont = 0;
  delay(1000);

}

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}

如果您取消注释digitalWrite线路,您会看到LED每秒闪烁约一次(每0.66s)?
里卡多

是的,如果我取消注释digitalWrite并设置OCR3B = 5;指示灯以大约该频率闪烁。
UserK 2014年

那真是个谜。您是否尝试过注释cont = 0;循环内部?那会发生什么呢?
里卡多

1
尝试增加频率。我认为您的if语句在某种程度上可能比清除中断更频繁地清除计数器。但是随后您应该在输出中看到更多的内容。如果运行更长的时间(例如1分钟),然后粘贴结果。另外,更新问题时,请保留旧的输出,以使您的问题有意义(无需编辑历史记录)。
里卡多

1
我怀疑中断例程仅被调用一次,然后被禁用。我读过某个地方的文章,说在运行中断代码时禁用了中断,在某些情况下您必须重新启用它,但是我真的不确定是否是这种情况。希望会有更多知识渊博的人来救援...
Ricardo 2014年

Answers:


5

在CTC模式下,顶部OCR3A不是OCR3B

在那之后TIMSK3 |= (1 << OCIE3B);也应改为TIMSK3 |= (1 << OCIE3A);,并ISR(TIMER3_COMPB_vect)ISR(TIMER3_COMPA_vect)

对于3Hz,OCR3A应为5208,而不是20。

技术上TCCR3B |= (1 << WGM12);应该是TCCR3B |= (1 << WGM32);


使用您的配置,计数器不会更新,并且每秒都会显示“安装完成”语句(写在setup()函数中!)。真是奇怪的行为。
UserK 2014年

使用解决TIMSK3 |= (1 << OCIE3B);。谢谢格本!请修改您的答案,我将其作为解决方案。
UserK 2014年

1
我忘了提到您还需要更改ISR向量。ISR(TIMER3_COMPB_vect)应该是ISR(TIMER3_COMPA_vect)。如果未定义ISR,则AVR会重置自身,就像您遇到的一样。真高兴你做到了。
Gerben 2014年

3

似乎我以前对这个问题的回答还不完整,感谢您指出CTC模式仅适用于OCR3A Gerben。对于在发布答案前未测试答案,我深表歉意。

仅给出有关此问题的信息,Gerben的答案是完整的,但是由于您的其他问题暗示您由于Servo库而无法使用OCR3A,因此我将添加一点。(我还编辑了该答案)

您可以通过在中断例程中将TCNT3设置为0来模拟CTC模式的行为。切记删除在代码中打开CTC模式的行。

我已经通过以下ISR测试了您的代码:

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}

和定时器寄存器的这种配置

OCR3B = 5208; // 800Hz 5; // 3 Hz
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);

我不确定,这在高频下的准确性可能比CTC差一些,但是在3Hz时它可以完美工作。请注意,5208是正确的OCR值,而不是20(再次感谢Gerben)。


我已经尝试过您的代码,但是计数器没有增加。如您所说,我已TCNT3=0;在ISR()中添加,并//TCCR3B |= (1 << WGM32);在setup()中将其删除 。我也尝试过注释掉该cont=0;行,但是没有任何变化
UserK 2014年

1
确保代码以其他方式与问题中发布的内容匹配。尝试将循环更改为just println(cont); delay(1000);。另外,您仍然将cli()和TCCR3A等位包含在内吗?
BrettAM 2014年

好,谢谢。在800 Hz时仍然准确!
UserK 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.