Настройка timer3 в режиме CTC - конфликт с библиотекой сервоприводов

10

Я хотел бы установить таймер для вызова функции 800 раз в секунду. Я использую Arduino Mega и Timer3 с прескалером 1024. Чтобы выбрать фактор прескалера, я рассмотрел следующие шаги:

  • Частота процессора: 16 МГц
  • Разрешение таймера: 65536 (16 бит)
  • Разделить частоту процессора выбранного предделителем: 16x10 ^ 6/ 1024 = 15625
  • Разделите остаток на нужную частоту 62500/800 = 19 .
  • Поместите результат + 1 в регистр OCR3.

Я использовал следующую таблицу для установки регистров TCCR3B:

введите описание изображения здесь

Ошибка

Невозможно скомпилировать код. Это ошибка, возвращаемая компилятором:

Servo \ Servo.cpp.o: в функции '__vector_32': C: \ Program Files (x86) \ Arduino \ library \ 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
}

Как решить конфликт с серво-библиотекой?

РЕШЕНИЕ

Конфликт решен с помощью следующего кода. Он компилируется, но счетчик, связанный с таймером 800 Гц, не увеличивает его значение.

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

Поскольку основная проблема была решена, я создал еще один вопрос здесь , связанный с проблемой счетчиком приращения.

UserK
источник
Вы используете библиотеку сервоприводов в своей программе или нет?
jfpoilpret
2
Servo.cpp, вероятно, также выполняет ISR (TIMER3_COMPA_vect)
TMa
1
Просто используйте Timer1, 4 или 5 вместо этого.
Гербен
1
Серво определяет функции прерывания для таймеров 1,3,4 и 5 на мегагерцах для COMPA. Как насчет использования COMPB?
BrettAM
1
Вы правы . Они просто используют все таймеры. Я предполагаю, что вы должны немного изменить библиотеку, удалив #define _useTimer3строку, или попробуйте поставить #undef _useTimer3сразу после включения.
Гербен

Ответы:

4

К сожалению, библиотека Servo резервирует выходные данные сравнения A (OCR * A) на таймерах 1,3,4 и 5 при загрузке на Arduino Mega. Каждый из них может иметь только один ISR, поэтому вы не сможете определить свой собственный TIMER * _COMPA_vect, пока используете Servo без изменения библиотеки.

Однако каждый аппаратный таймер оснащен двумя выходными регистрами сравнения. Серво не требует никаких прерываний TIMER * _COMPB_vect, поэтому они бесплатны и работают точно так же.

Вы должны следить за действиями библиотек Servo, это может изменить конфигурацию вашего таймера. Порядок по умолчанию для Megas составляет 5,1,3,4 и дает каждые 12 сервоприводов. Он настраивает таймер только тогда, когда он ему нужен, поэтому с таймером 3 все будет в порядке, пока вы не добавите этот 25-й сервопривод.

Чтобы изменить код, используйте OCR3B вместо OCR3A (регистры сравнения выходов) и установите бит OCIE3B вместо OCIE3A в TIMSK3 (биты разрешения прерывания сравнения выходов). Затем вы можете изменить функцию ISR на ISR(TIMER3_COMPB_vect){}

Режим CTC работает только с OCR3A, но если вы установите TCNT3 на 0 в своей функции прерывания, вы можете получить аналогичное поведение. Не забудьте удалить строку, которая включает режим CTC, используя WGM12.

BrettAM
источник
Хорошо, спасибо! Любой совет по увеличению счетчика ?
UserK