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

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

  • Частота процессора: 16 МГц.
  • Разрешение таймера: 65 536 (16 бит)
  • Разделите частоту ЦП на выбранный прескалер: 16 x 10^6/1024=15 625
  • Разделите оставшуюся часть на нужную частоту. 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:\Program Files (x86)\Arduino/AccelPart1_35.ino:457: впервые определен здесь c:/program файлы (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()
{
 [...]
  // инициализируем Таймер3
  cli();          // отключаем глобальные прерывания
  TCCR3A = 0;     // установить весь регистр TCCR3A в 0
  TCCR3B = 0;     // то же самое для TCCR3B

  // установить сравнение регистра совпадения с желаемым счетчиком таймера: 800 Гц
  OCR3A = 20;
  // включить режим CTC:
  TCCR3B |= (1 << WGM12);
  // Установите биты CS10 и CS12 для предделителя 1024:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // включить прерывание сравнения таймера:
  TIMSK3 |= (1 << OCIE3A);
  // разрешить глобальные прерывания:
  sei();
}

void loop()
{
 // Выводить каждую секунду количество вызванных ISR -> должно быть 100
 if ( millis() % 1000 == 0)
 {
   Serial.println();
   Serial.print(" tick: ");
   Serial.println(contatore);
   contatore = 0;
 }
}

[...]

// Это 457-я строка
ISR(TIMER3_COMPA_vect)
{
    accRoutine();
    contatore++;
}

void accRoutine()
{
  // считывает аналоговые значения
}

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

РЕШЕНИЕ

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

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  // Инициализировать таймер
  cli();          // отключаем глобальные прерывания
  TCCR3A = 0;     // установить весь регистр TCCR3A в 0
  TCCR3B = 0;     // то же самое для TCCR3B

  // установить сравнение регистра совпадения с желаемым счетчиком таймера: 800 Гц
  OCR3B = 20;
  // включить режим CTC:
  TCCR3B |= (1 << WGM12);
  // Установите биты CS10 и CS12 для предделителя 1024:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // включить прерывание сравнения таймера:
  TIMSK3 |= (1 << OCIE3B);
  // разрешить глобальные прерывания:
  sei();

  Serial.println("Setup completed");
}

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

ISR(TIMER3_COMPB_vect)
{
  cont++;
}

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

, 👍10

Обсуждение

Используете ли вы сервобиблиотеку в своей программе или нет?, @jfpoilpret

Вероятно, Servo.cpp также выполняет **ISR(TIMER3_COMPA_vect)**, @TMa

@jfpoilpret да, я использую моторы. Я добавлю строки в вопросе. Я читал, что библиотека сервоприводов использует timer1 на atmega328., @UserK

@jfpoilpret Возможно, изменение таймера решит проблему., @UserK

Просто используйте Timer1, 4 или 5 вместо этого., @Gerben

Servo определяет функции прерывания для таймеров 1, 3, 4 и 5 на мегабайтах для COMPA. Как насчет использования COMPB?, @BrettAM

Еще не пробовал, в ближайшее время сделаю. Сколько таймеров доступно, учитывая, что я использую такие функции, как millis(), micros(), сервопривод, последовательный порт и связь i2c?, @UserK

@Gerben Спасибо, я думаю, у меня возникла бы та же проблема с использованием timer1, поскольку он также используется библиотекой сервоприводов., @UserK

[Вы правы] (https://github.com/arduino/Arduino/blob/master/libraries/Servo/Servo.h#L60-64). Они просто жрут все таймеры. Я предполагаю, что вам нужно немного изменить библиотеку, удалив строку #define _useTimer3, или попробовать поставить #undef _useTimer3 сразу после включения., @Gerben

@BrettM Я пробовал с COMPB. Он компилируется, но таймер не работает. Должен ли я установить выходной регистр сравнения OCR3B на 625 вместо OCR3A?, @UserK

Вам нужно будет загрузить ORC3B вместо ORC3A да. Также вам необходимо включить прерывание сравнения B в TIMSK3 (изменить OCIE3A на OCIE3B), @BrettAM

@BrettM Не могли бы вы ответить на вопрос с предоставленными предложениями?, @UserK


1 ответ


Лучший ответ:

3

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

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

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

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

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

,

Хорошо спасибо! Любые советы по увеличению [счетчика](http://arduinoprosto.ru/q/5431/how-to-update-a-variable-in-an-isr-using-timers)?, @UserK