Configurando o timer3 no modo CTC - conflito com a biblioteca servo

10

Gostaria de configurar um timer para chamar uma função 800 vezes por segundo. Estou usando o Arduino Mega e o Timer3 com um pré-calibrador de 1024. Para escolher o fator do pré-calibrador, considerei as seguintes etapas:

  • Freq da CPU: 16MHz
  • Resolução do temporizador: 65536 (16 bits)
  • Freq Divide CPU pela prescaler escolhido: 16x10 ^ 6/ 1024 = 15625
  • Divida o restante pela frequência desejada 62500/800 = 19 .
  • Coloque o resultado + 1 no registro OCR3.

Eu usei a tabela a seguir para definir registros do TCCR3B:

insira a descrição da imagem aqui

O erro

É impossível compilar o código. Este é o erro retornado pelo compilador:

Servo \ Servo.cpp.o: Na função '__vector_32': C: \ Arquivos de Programas (x86) \ Arduino \ libraries \ Servo / Servo.cpp: 110: definição múltipla de '__vector_32' AccelPart1_35.cpp.o: C: \ Arquivos de programa (x86) \ Arduino / AccelPart1_35.ino: 457: definidos aqui primeiro c: / arquivos de programa (x86) / arduino / hardware / ferramentas / avr / bin /../ lib / gcc / avr / 4.3.2 /. ./../../../avr/bin/ld.exe: Desativando o relaxamento: ele não funcionará com várias definições

O código

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
}

Como resolver o conflito com a biblioteca servo?

SOLUÇÃO

Conflito resolvido usando o seguinte código. Ele é compilado, mas o contador associado ao timer de 800Hz não aumenta seu valor.

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++;
}

Como o problema principal foi resolvido, criei outra questão aqui relacionada ao problema da incremento do contador.

UserK
fonte
Você usa a biblioteca servo no seu programa ou não?
Jfpoilpret
2
Provavelmente o servo.cpp também faz ISR (TIMER3_COMPA_vect)
TMa
11
Basta usar o Timer1, 4 ou 5.
Gerben
11
Servo define funções de interrupção para temporizadores 1,3,4 e 5 em megas para COMPA. Que tal usar o COMPB?
BrettAM
11
Você está certo . Eles estão apenas monopolizando todos os temporizadores. Eu acho que você precisa alterar a biblioteca um pouco removendo a #define _useTimer3linha ou tente colocar um #undef _useTimer3logo após o include.
Gerben

Respostas:

4

Infelizmente, a biblioteca Servo reserva a saída de comparação A (OCR * A) nos timers 1,3,4 e 5 quando carregada em um mega arduino. Cada um pode ter apenas um ISR; portanto, você não poderá definir seu próprio TIMER * _COMPA_vect enquanto usar o Servo sem modificar a biblioteca.

No entanto, cada temporizador de hardware está equipado com 2 registros de comparação de saída. O servo não reivindica nenhuma interrupção TIMER * _COMPB_vect, portanto, essas são de uso livre e funcionam exatamente da mesma maneira.

Você deve observar as atividades das bibliotecas Servo, pois isso pode alterar a configuração do seu timer. O pedido padrão é em megas é 5,1,3,4 e fornece a cada 12 servos. Ele só configura o temporizador quando necessário, portanto, você deve usar o temporizador 3 até adicionar o 25º servo.

Para alterar seu código, use OCR3B em vez de OCR3A (os registros de comparação de saída) e defina o bit OCIE3B em vez de OCIE3A no TIMSK3 (os bits de comparação de saída ativados). Então você deve mudar sua função ISR para ISR(TIMER3_COMPB_vect){}

O modo CTC funciona apenas com OCR3A, mas se você configurar o TCNT3 para 0 na sua função de interrupção, poderá obter um comportamento semelhante. Lembre-se de remover a linha que ativa o modo CTC usando o WGM12.

BrettAM
fonte
Ok obrigado! Algum conselho sobre o incremento do contador ?
UserK