将Timer3设置为CTC模式-与伺服库冲突


10

我想设置一个计时器,以便每秒调用一个函数800次。我正在使用预分频器为1024的Arduino Mega和Timer3。为选择预分频器,我考虑了以下步骤:

  • CPU频率:16MHz
  • 计时器分辨率:65536(16位)
  • 16x10 ^ 6 /:由所选择的预分频CPU频率1024 = 15625
  • 将其余部分除以所需的频率62500/800 = 19
  • 将结果+1放入OCR3寄存器。

我已使用下表设置TCCR3B的寄存器:

在此处输入图片说明

错误

不可能编译代码。这是编译器返回的错误:

Servo \ Servo.cpp.o:在功能'__vector_32'中:C:\ Program Files(x86)\ Arduino \ libraries \ Servo / Servo.cpp:110:'__vector_32'AccelPart1_35.cpp.o:C:\的多个定义程序文件(x86)\ Arduino / AccelPart1_35.ino:457:首先在这里定义c:/程序文件(x86)/ arduino / hardware / tools / avr / bin /../ lib / gcc / avr / 4.3.2 /。 ./../../../avr/bin/ld.exe:禁用松弛:它不适用于多个定义

编码

volatile int cont = 0;
unsigned long aCont = 0;
void setup()
{
 [...]
  // initialize Timer3
  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;
  // 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 << OCIE3A);
  // enable global interrupts:
  sei();
}

void loop()
{
 // Print every second the number of ISR invoked -> should be 100
 if ( millis() % 1000 == 0)
 {
   Serial.println();
   Serial.print(" tick: ");
   Serial.println(contatore);
   contatore = 0;
 }
}

[...]

// This is the 457-th line
ISR(TIMER3_COMPA_vect)
{
    accRoutine();
    contatore++;
}

void accRoutine()
{
  // reads analog values
}

如何解决与伺服库的冲突?

使用以下代码解决了冲突。它可以编译,但是与800Hz计时器关联的计数器不会增加其值。

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  // 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;
  // 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)
{
  cont++;
}

由于已经解决了主要问题,因此我在这里创建了另一个与计数器增加问题有关的问题。


您是否在程序中使用了伺服库?
jfpoilpret 2014年

2
Servo.cpp可能也会执行ISR(TIMER3_COMPA_vect)
TMa 2014年

1
只需使用Timer1、4或5即可。
Gerben

1
伺服为COMPA定义了以兆为单位的定时器1、3、4和5的中断功能。如何使用COMPB?
BrettAM

1
你说的对。他们只是在浪费所有计时器。我猜您必须通过删除该#define _useTimer3行来稍微更改库,或者尝试#undef _useTimer3在包含之后添加一个权利。
Gerben 2014年

Answers:


4

不幸的是,当加载到arduino mega上时,Servo库在定时器1、3、4和5上保留输出比较A(OCR * A)。每个服务器只能有一个ISR,因此在使用Servo时,如果不修改库就不能定义自己的TIMER * _COMPA_vect。

但是,每个硬件计时器都配有2个输出比较寄存器。伺服不要求任何TIMER * _COMPB_vect中断,因此这些中断可以自由使用,并且工作原理完全相同。

您应该注意Servo库的活动,这可能会更改计时器的配置。默认顺序是兆,5、1、3、4,每12个舵机一次。它仅在需要时配置计时器,因此您应该可以使用计时器3,直到添加第25个伺服器为止。

要更改代码,请使用OCR3B代替OCR3A(输出比较寄存器),并将TIMSK3中的OCIE3B代替OCIE3A设置(输出比较中断允许位)。然后您将ISR功能更改为 ISR(TIMER3_COMPB_vect){}

CTC模式仅适用于OCR3A,但是如果在中断函数中将TCNT3设置为0,则可能会得到类似的行为。记住要删除使用WGM12打开CTC模式的行。


好,谢谢!关于增加计数器有什么建议吗?
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.