Как правильно использовать 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;
}
@Ole, 👍1
Обсуждение1 ответ
Лучший ответ:
У вас есть три разные переменные с именами 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
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Ошибка: "недопустимое использование нестатической функции-члена" при вызове функции из моего собственного класса-метода
- Почему необходимо использовать ключевое слово volatile для глобальных переменных при обработке прерываний в ардуино?
- Серийное прерывание
- Массив динамического размера в качестве члена класса
- Прерывание ардуино при смене контакта
- Влияет ли `millis()` на длинные ISR?
- Как прервать функцию цикла и перезапустить ее?
Вы подключали этот контакт к земле ранее, прежде чем перейти на 3,3 В? Используете ли вы внешние подтягивающие или подтягивающие резисторы? На контакте уже могло быть 3,3 В, поэтому его подключение к 3,3 В не привело бы к возникновению нарастающего фронта. Вы пытались подключить и повернуть фактический энкодер?, @chrisl