Установка 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++;
}
Поскольку основная проблема решена, я создал еще один вопрос здесь, связанный с проблемой увеличения счетчика.
@UserK, 👍10
Обсуждение1 ответ
Лучший ответ:
К сожалению, библиотека 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
- Будет ли .ino-скетч ардуино компилироваться непосредственно на GCC-AVR?
- Прерывание переполнения Timer0 не работает
- Как измерить ультразвуковой датчик без импульсного метода?
- Компиляция кода через терминал
- неопределенная ссылка на `PPMintIn::PPMintIn(int)'
- Проблема прерывания библиотеки MPU6050 Arduino Jeff Rowberg
- Arduino Mega TIMER1 интервал в одну секунду
- Сборка mocoLUFA под OSX и Linux
Используете ли вы сервобиблиотеку в своей программе или нет?, @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