Как правильно использовать ISR внутри определения класса?

Я хочу написать класс для модели велосипеда.

Для управления рулевым управлением я использую двигатель постоянного тока с двумя энкодерами. Чтобы получить угол поворота stAng велосипеда, я подключаю прерывание к контакту ST_ENC_A, к которому подключен один из энкодеров. Это прерывание подключается, когда велосипед инициализируется с помощью функции bike.begin(). Когда срабатывает прерывание, срабатывает функция увеличения угла поворота incStAng. Указанная функция является членом класса Bike. Чтобы весь код скомпилировался и загрузился, мне пришлось сделать функцию увеличения угла поворота static void incStAng() и переменную угла поворота volatile static float stAng статический.

Код работает, ошибок и предупреждений нет.

Теперь, когда я подаю на контакт ST_ENC_A напряжение 3,3 В, должно срабатывать прерывание, и я должен видеть напечатанное значение stAng, увеличивающееся в последовательном мониторе. Это не вариант. Он остается равным 0,00.

Это мой первый настоящий урок, который я пишу. Я хочу создать только один экземпляр своего велосипеда, поэтому статическое определение stAng и incStAng не должно вызывать проблем.

До сих пор я нашел следующие веб-сайты полезными для получения информации о 'static' и ISR.

Я был бы рад, если бы кто-нибудь мог мне помочь и подсказать, почему угол поворота не увеличивается, когда я подаю на указанный контакт 3,3 В!

Плата: Arduino Nano RP2040 Connect

Ниже вы увидите файлы .ino, .h, .cpp в этом порядке.

// myBike.ino - основной файл

#include "Bike.h"

Bike bike;

void setup() {
  Serial.begin(9600);
  bike.begin();
}

void loop() {
  float val = bike.getStAng();
  Serial.println(val);
}
// Bike.h - заголовочный файл для библиотеки Bike

#ifndef Bike_h
#define Bike_h

#include "Arduino.h"

class Bike {
  public:
    Bike();
    void begin();
    float getStAng();
  private:
    volatile static float stAng;
    static void incStAng();
};

#endif
// Bike.cpp - файл реализации для библиотеки Bike

#include "Bike.h"

#define ST_ENC_A      12
#define ST_ENC_B      11

#define DEG_PER_CNT   0.51428571428

Bike::Bike() {
  pinMode(ST_ENC_A, INPUT);
  pinMode(ST_ENC_B, INPUT);
}

void Bike::begin() {
  attachInterrupt(digitalPinToInterrupt(ST_ENC_A),incStAng,RISING);
}

void Bike::incStAng() {
  volatile float stAng;
  int b = digitalRead(ST_ENC_B);
  if(b==HIGH){
    stAng = stAng - DEG_PER_CNT;
  }else{
    stAng = stAng - DEG_PER_CNT;
  }
}

float Bike::getStAng() {
  volatile float stAng;
  return stAng;
}


, 👍1

Обсуждение

Вы подключали этот контакт к земле ранее, прежде чем перейти на 3,3 В? Используете ли вы внешние подтягивающие или подтягивающие резисторы? На контакте уже могло быть 3,3 В, поэтому его подключение к 3,3 В не привело бы к возникновению нарастающего фронта. Вы пытались подключить и повернуть фактический энкодер?, @chrisl


1 ответ


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

3

У вас есть три разные переменные с именами stAng здесь:

  • статический член класса Bike, объявленный, но не определено и никогда не используется
  • локальная переменная метода Bike::incStAng()
  • локальная переменная метода Bike::getStAng()

Должна быть только одна такая переменная. Для этого следует определить первый: в Bike.cpp

volatile float Bike::stAng;

и избавиться от двух других.

Примечание: я бы рекомендовал избегать вычислений с плавающей запятой внутри ISR, так как они могут быть довольно медленными. Вместо этого подсчитайте целое число шагов энкодера в ISR и преобразовать в угол в пределах Велосипед::getStAng().

,

Спасибо за эту быструю помощь, это работает, как я хочу! Я все еще задаюсь вопросом, почему это должно быть так, хотя. Добавление этих двух локальных переменных, о которых вы упомянули, привело к компиляции кода, поэтому я это сделал. Итак, в классе я объявляю stAng только как статический член, но определяю его с помощью volatile float Bike::stAng; в Bike.cpp, верно? Я не понимаю основного правила, почему я должен делать это таким образом. Не могли бы вы дать мне краткое объяснение? Если я добавляю в класс нестатическую переменную и хочу получить к ней доступ и изменить ее с помощью метода Bike, мне не нужно добавлять такое определение в Bike.cpp., @Ole

@Ole: определение класса в Bike.h определяет только _type_. Нет данных. Строка «Велосипед» в myBike.ino определяет объект «Велосипед» и, следовательно, все данные, принадлежащие этому объекту (которых в данном случае просто нет). Статический элемент данных не принадлежит какому-либо объекту и, следовательно, должен определяться в другом месте. Он также должен быть определен только _один раз_, поэтому файл .h, который потенциально может быть включен в несколько других файлов, не подходит., @Edgar Bonet