Недостатки использования 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();
}

, 👍3

Обсуждение

Расскажите, а ещё лучше — покажите, что делают «другие части» вашего кода. Существует бесконечное множество возможностей прерывания., @mystery

Многие библиотеки ожидают работы delay(), millis() или micros()., @Edgar Bonet

@EdgarBonet В таком случае, я думаю, лучше оставить его неиспользованным. Спасибо., @mahdiou


1 ответ


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

0

Многие библиотеки ожидают работы delay(), millis() или micros().

,

Я скопировал комментарий Эдгара Бонета сюда, чтобы дать полноценный ответ, потому что Stack Exchange поднимает старые вопросы без ответов в надежде, что кто-то на них ответит. Именно поэтому вы отвечаете как на ответ, а не как на комментарий., @Nick Gammon

В половине случаев, когда я отвечаю, кто-то говорит, что это должен быть комментарий. Я начинаю думать, что нет «правильного» способа пользоваться этим сайтом, который бы не вызвал жалоб., @Delta_G

@Delta_G Политика чётко изложена в [помощи], это чёткое руководство, как это сделать, а не то, что пишут случайные люди. Ответы есть ответы, комментарии есть комментарии., @the busybee

Автор вопроса утверждает, что они не используют никаких библиотек, которые могли бы использовать эти функции. Так что этот ответ уже был в вопросе. Вот почему это был всего лишь комментарий., @Juraj