Недостатки использования timer0 с внешним входом?
Я работаю над проектом управления дифференциальным приводом, в котором для одометрии используются датчики скорости.
Я подсчитываю количество нарастающих фронтов, используя counter0 и counter5 (на Arduino Mega 2560). Само по себе это работает отлично, но когда я объединяю этот код с другими частями своего кода, многое перестаёт работать, и я не могу понять, почему. Сейчас я предполагаю, что это связано с timer0.
Итак, мой вопрос: что может пойти не так при изменении регистров для timer0? Я знаю, что delay(), millis(), micros() и ШИМ на выводах 4 и 13 больше не будут доступны, но есть ли ещё что-то, о чём мне следует знать? Есть ли библиотеки, которые перестают работать?
Если это так, я думаю использовать аппаратные прерывания для одометрии.
Заранее спасибо.
Редактировать: Вот дополнительная информация о проекте:
В проекте я использую контроллер на основе поведения для создания робота с дифференциальным приводом, который движется к некоторым целевым координатам, избегая препятствий.
Измерение скорости осуществляется с помощью энкодеров и оптопар. Эти значения также используются для обновления положения и направления движения робота. Измерение происходит каждые 210 миллисекунд.
Расстояние до препятствия измеряется с помощью 7 ультразвуковых датчиков, которые управляются с помощью прерываний по смене контакта.
Единственные внешние библиотеки, которые я использую, — это TimerOne.h и TimerThree.h (которые не используют timer0), и я позаботился о том, чтобы не использовать timer0 (по крайней мере напрямую) в тех частях, которые я написал сам.
Мой код работает на основе прерываний, поэтому мне интересно, может ли это быть причиной неправильного поведения.
Вот основной код
#include "definitions.h" // содержит константы, которые должны быть доступны многим файлам
#include "diff_cntrl.h" // управляет колесами (скорость левого и правого), использует таймеры 0 и 5 для измерения скорости
#include <TimerThree.h> // используется для генерации прерываний таймера для дифференциального управления
#include "A7.h" // используется для связи с использованием модуля A7 через Serial1
#include "M_Ultrasonics.h" // измеряет расстояние от 7 ультразвуковых датчиков, используя прерывания по изменению контакта на A8 - A14 (PORTK) и TimerOne.h
#include "FuzzyBBC.h" // контроллер на основе нечеткой логики (выполняет только вычисления с плавающей точкой
volatile double dists[NUM_US]; // массив, в котором будут храниться расстояния до препятствий
volatile uint8_t done = 0; // флаг устанавливается M_Ultrasonics.h, когда измерены все 7 расстояний
FuzzyBBC fbbc; // ссылка на контроллер на основе поведения
volatile double xG = 0, yG = 0; // координаты цели
volatile double v = 0, w = 0; // желаемая скорость и угловая скорость. устанавливается fbbc и используется дифференциальным контроллером
// переменные, хранящие текущее состояние
volatile double x = 0, y = 0, phi = 0; // координаты и направление
volatile double dx, dy, dphi; // изменения координат и направления (используется для отладки
// переменные, используемые для управления скоростью двигателей: опорная скорость, фактическая скорость, значение счетчика, выходное напряжение для левого и правого двигателей
volatile double l_ref = 0, l_spd = 0, r_ref = 0, r_spd = 0;
volatile uint8_t l_ctr = 0, r_ctr = 0;
volatile uint8_t l_volt = 0, r_volt = 0;
volatile boolean newvolt = true; // флаг устанавливается при вычислении нового значения напряжения
volatile boolean updated = false; // флаг установлен, чтобы разрешить передачу данных на удаленную машину
volatile uint8_t update_count = 0;
//------------отладочные переменные-----------------
volatile double dvl, dvr;
//-------------------------------------------
void setup()
{
delay(5000);
A7begin(); // запускает модуль A7 и подключается к предопределенной удаленной машине
initMotors(); // инициализируем контакты для управления двигателем (я использую драйвер двигателя LM293D)
setup_cntr(); // устанавливаем регистры для timer0 и timer5
// vw2lr();
fbbc.begin(&xG, &yG, NUM_US, dists, &x, &y, &phi, &v, &w); // запуск контроллера нечеткой логики, он имеет прямой доступ к предоставленным переменным
HCRS04.begin(T_US, dists, &done); // запуск контроллера ультразвуковых датчиков (он запускается каждые 30 миллисекунд
Timer3.initialize(T_MOTOR*1000L); // прерывания таймера для управления скоростью (T_MOTOR = 210 миллисекунд)
Timer3.attachInterrupt(cntrISR);
}
void loop() {
if(done) // ждать обновления расстояний до препятствий
{
arbiter(); // обновить v и w
if(updated && !waiting){ // отправка данных на удаленную машину
String info = "v: " + String(v) + "\tw: " + String(w) +
"\t\tvl: " + String(l_spd) + "\tlref: " + String(l_ref) + "\tlvolt: " + String(l_volt) +
"\t\tvr: " + String(r_spd) + "\trref: " + String(r_ref) + "\trvolt: " + String(r_volt) +
"\t\tx: " + String(x) + "\ty: " + String(y) + "\txG: " + String(xG) + "\tyG: " + String(yG);
LogInfo(info);
updated = false;
}
done = false;
}
if (A7_STREAM.available() > 0) { // получить входные данные от модуля A7 (Serial1)
String msg = "";
if(waiting){
get_A7_resp(); // прочитать сообщение (функция в A7.h)
msg = resp; // сохранить сообщение (переменная в A7.h)
resp = "";
}
else{
msg = readStr();
}
if (msg.length() > 2) // обработать полученное сообщение
{
if (msg.substring(0, 2).equals("xy")) {
readXYG(msg);
resp = "";
}
else if(msg.equals("stop")){
xG = x;
yG = y;
resp = "";
}
else if(msg.equals("+TCPCLOSE:0")){
disconnected();
}
}
}
}
inline void arbiter(){
fbbc.arbiter();
newvolt = true;
vw2lr(); // преобразует v и w в левую и правую скорость
}
inline void cntrISR() // ISR, который запускается каждые 210 миллисекунд (для управления скоростью)
{
// вычислить скорость автомобиля
read_rm();
read_lm();
ctr2lr(); // преобразовать значения счетчика в сантиметры в секунду
if (newvolt){
spd2volt_init();
newvolt = false;
}
else
spd2volt();
// обновить значения двигателя
analogWrite(L_PWM_PIN, l_volt);
analogWrite(R_PWM_PIN, r_volt);
updatePos();
}
inline void updatePos() // вычислить новое положение (используя уравнения кинематики дифференциального привода)
{
lr2xyphi();
}
inline void readXYG(String cmd) // получить новые координаты цели
{
int sp1 = cmd.indexOf(' ');
int sp2 = cmd.indexOf(' ', sp1 + 1);
xG = (double)cmd.substring(sp1 + 1, sp2).toInt();
yG = (double)cmd.substring(sp2 + 1, cmd.indexOf('~',sp2+1)).toInt();
}
код инициализации двигателя:
inline void setup_cntr()
{
pinMode(CTR0_PIN, INPUT_PULLUP);
pinMode(CTR5_PIN, INPUT_PULLUP);
TCNT5H = 0;
TCNT5L = 0;
TCCR5B = 0X07;
TCNT0 = 0;
TCCR0B = 0X07;
}
inline void initMotors(){
pinMode(L_FWD_PIN, OUTPUT);
pinMode(L_BACK_PIN, OUTPUT);
pinMode(L_PWM_PIN, OUTPUT);
pinMode(L_EN_PIN, OUTPUT);
digitalWrite(L_EN_PIN, HIGH);
digitalWrite(L_FWD_PIN, HIGH);
digitalWrite(L_BACK_PIN, LOW);
pinMode(R_FWD_PIN, OUTPUT);
pinMode(R_BACK_PIN, OUTPUT);
pinMode(R_PWM_PIN, OUTPUT);
pinMode(R_EN_PIN, OUTPUT);
digitalWrite(R_EN_PIN, HIGH);
digitalWrite(R_FWD_PIN, HIGH);
digitalWrite(R_BACK_PIN, LOW);
}
код ультразвуковых датчиков:
#include "M_Ultrasonics.h"
M_Ultrasonics HCRS04;
void measISR();
void trigISR();
M_Ultrasonics::M_Ultrasonics()
{
pinIndex = -1;
for(int i=0; i < NUM_US; i++)
{
pinMode(trigs[i],OUTPUT); // trigs: массив, содержащий триггерные контакты ультразвуковых датчиков
digitalWrite(trigs[i],LOW);
}
}
void M_Ultrasonics::begin(uint32_t period, volatile double *dists_, volatile uint8_t *done_)
{
Timer1.initialize(period*1000);
Timer1.attachInterrupt(trigISR);
dists = dists_;
done = done_;
pinIndex = -1;
for(int i=0; i < NUM_US; i++)
{
pinMode(trigs[i],OUTPUT);
digitalWrite(trigs[i],LOW);
dists[i] = MAX_DIST;
}
enable_pci();
}
void M_Ultrasonics::end()
{
Timer1.stop();
Timer1.detachInterrupt();
PCICR = 0;
}
inline void M_Ultrasonics::trig() // отправка сигнала триггера на датчик
{
pinIndex ++;
if(pinIndex == NUM_US)
{
pinIndex = 0;
*done = 1;
}
set_pci();
digitalWrite(trigs[pinIndex], HIGH);
delayMicroseconds(ping);
digitalWrite(trigs[pinIndex], LOW);
}
inline void M_Ultrasonics::enable_pci() // включить прерывания по изменению контакта на PORTK
{
PCICR = 0x04;
}
inline void M_Ultrasonics::set_pci() // активировать прерывания для текущего контакта
{
PCMSK2 = (1<<pinIndex);
}
inline unsigned long M_Ultrasonics::read_time() // преобразует значение таймера в микросекунды
{
return (/*(TCNT1H<<8) | */TCNT1L) * F_CLOCK;
}
inline void M_Ultrasonics::meas()
{
if(PINK & (1<<pinIndex)) { // проверяем, находится ли контакт на высоком уровне
s_echo = /*micros();/*/read_time();
dists[pinIndex] = MAX_DIST*DOBST_COEFF;
}
else
{
f_echo =/* micros();/*/read_time();
// d = (f_echo-s_echo)*soundSpeed/2E4;
if(d < MAX_DIST) {
dists[pinIndex] = d/**DOBST_COEFF*/;
}
// dists[pinIndex] = d; // (double)(f_echo - s_echo);
}
}
ISR (PCINT2_vect) // здесь обрабатывается прерывание по смене контакта для A8-A14
{
measISR();
}
void measISR() // ISR вызывается по переднему или заднему фронту на текущем выводе
{
HCRS04.meas();
}
void trigISR() // функция вызывается каждые 30 миллисекунд для активации следующего ультразвукового датчика
{
HCRS04.trig();
}
@mahdiou, 👍3
Обсуждение1 ответ
Лучший ответ:
Многие библиотеки ожидают работы delay(), millis() или micros().
Я скопировал комментарий Эдгара Бонета сюда, чтобы дать полноценный ответ, потому что Stack Exchange поднимает старые вопросы без ответов в надежде, что кто-то на них ответит. Именно поэтому вы отвечаете как на ответ, а не как на комментарий., @Nick Gammon
В половине случаев, когда я отвечаю, кто-то говорит, что это должен быть комментарий. Я начинаю думать, что нет «правильного» способа пользоваться этим сайтом, который бы не вызвал жалоб., @Delta_G
@Delta_G Политика чётко изложена в [помощи], это чёткое руководство, как это сделать, а не то, что пишут случайные люди. Ответы есть ответы, комментарии есть комментарии., @the busybee
Автор вопроса утверждает, что они не используют никаких библиотек, которые могли бы использовать эти функции. Так что этот ответ уже был в вопросе. Вот почему это был всего лишь комментарий., @Juraj
- Установка timer3 в режиме CTC - конфликт с сервобиблиотекой
- Как измерить ультразвуковой датчик без импульсного метода?
- Проблема прерывания библиотеки MPU6050 Arduino Jeff Rowberg
- Arduino Mega TIMER1 интервал в одну секунду
- Таймеры, выводы ШИМ и цифровые выходы на Arduino Mega
- Точность синхронизации Arduino nano
- Мега: присоединение Interrupt на выводе 18/19/20/21 не работает
- Считать данные датчика повторно через указанное время?
Расскажите, а ещё лучше — покажите, что делают «другие части» вашего кода. Существует бесконечное множество возможностей прерывания., @mystery
Многие библиотеки ожидают работы
delay(),millis()илиmicros()., @Edgar Bonet@EdgarBonet В таком случае, я думаю, лучше оставить его неиспользованным. Спасибо., @mahdiou