Impostazione timer3 in modalità CTC - conflitto con la servo libreria


10

Vorrei impostare un timer per chiamare una funzione 800 volte al secondo. Sto usando Arduino Mega e Timer3 con un prescaler di 1024. Per scegliere il fattore prescaler ho considerato i seguenti passaggi:

  • Frequenza CPU: 16 MHz
  • Risoluzione del timer: 65536 (16 bit)
  • Freq dividere CPU dal prescaler prescelto: 16x10 ^ 6/ 1024 = 15625
  • Dividi il resto per la frequenza desiderata 62500/800 = 19 .
  • Inserisci il risultato + 1 nel registro OCR3.

Ho usato la seguente tabella per impostare i registri di TCCR3B:

inserisci qui la descrizione dell'immagine

L'errore

È impossibile compilare il codice. Questo è l'errore restituito dal compilatore:

Servo \ Servo.cpp.o: nella funzione '__vector_32': C: \ Programmi (x86) \ Arduino \ libraries \ Servo / Servo.cpp: 110: definizione multipla di '__vector_32' AccelPart1_35.cpp.o: C: \ Programmi (x86) \ Arduino / AccelPart1_35.ino: 457: prima definito qui c: / programmi (x86) / arduino / hardware / tools / avr / bin /../ lib / gcc / avr / 4.3.2 /. ./../../../avr/bin/ld.exe: disabilitazione del rilassamento: non funzionerà con più definizioni

Il codice

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
}

Come risolvere il conflitto con la servo biblioteca?

SOLUZIONE

Conflitto risolto utilizzando il seguente codice. Si compila ma il contatore associato al timer a 800Hz non ne aumenta il valore.

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

Poiché il problema principale è stato risolto, ho creato qui un'altra domanda relativa al problema dell'incremento del contatore.


Usi la libreria dei servo nel tuo programma o no?
jfpoilpret,

2
Probabilmente Servo.cpp fa anche ISR (TIMER3_COMPA_vect)
TMa

1
Usa invece Timer1, 4 o 5.
Gerben,

1
Il servo definisce le funzioni di interruzione per i timer 1,3,4 e 5 su megas per COMPA. Che ne dici di usare COMPB?
BrettAM,

1
Hai ragione . Stanno solo controllando tutti i timer. Immagino che devi modificare leggermente la libreria rimuovendo la #define _useTimer3linea o provare a inserire #undef _useTimer3subito dopo l'inclusione.
Gerben,

Risposte:


4

Sfortunatamente, la libreria Servo riserva l'output confronta A (OCR * A) sui timer 1,3,4 e 5 se caricato su un Arduino Mega. Ognuno può avere solo un ISR, quindi non sarai in grado di definire il tuo TIMER * _COMPA_vect mentre usi Servo senza modificare la libreria.

Tuttavia, ogni timer hardware è dotato di 2 registri di confronto delle uscite. Il servo non rivendica alcuna interruzione TIMER * _COMPB_vect, quindi sono liberi di usare e funzionano esattamente allo stesso modo.

Dovresti fare attenzione alle attività delle librerie Servo, potrebbe cambiare la configurazione del tuo timer. L'ordine predefinito è su megas è 5,1,3,4 e per dare ogni 12 servi. Configura il timer solo quando ne ha bisogno, quindi dovresti usare il timer 3 fino a quando non aggiungi quel 25o servo.

Per modificare il codice, utilizzare OCR3B anziché OCR3A (i registri di confronto delle uscite) e impostare il bit OCIE3B anziché OCIE3A in TIMSK3 (i bit di abilitazione dell'interruzione del confronto di uscite). Quindi è necessario modificare la funzione ISR in ISR(TIMER3_COMPB_vect){}

La modalità CTC funziona solo con OCR3A, ma se si imposta TCNT3 su 0 nella funzione di interruzione è possibile ottenere un comportamento simile. Ricorda di rimuovere la linea che attiva la modalità CTC usando WGM12.


Ok grazie! Qualche consiglio sull'incremento del contatore ?
UtenteK
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.