Как обычно, я знаю, как обойти эту проблему с помощью некрасивой работы с патчами, но я хочу сделать ее элегантной: я хотел бы сделать небольшую оболочку для двигателей, управляемую Arduino, что, к сожалению, означало бы написание отдельной подпрограммы прерывания для каждого экземпляр двигателя, потому что он должен изменить правильный счетчик шага (переменная-член класса двигателя), чтобы определить его скорость. Однако эти функции, очевидно, будут иметь одинаковую обработку …
Мой вопрос: как я могу определить, какой счетчик нужно изменить в уникальной подпрограмме прерывания?
Вот что у меня есть, я хотел бы скрыть прерывания от пользователя.
class Motor {
volatile int counter;
unsigned long lastUpdate; //Last timestamp update (for calculating the rate)
static const unsigned int RESOLUTION = 1024; //Number of steps in one rev
static const unsigned int RPMS_TO_RPM = 60000; //Convers rev/ms to rpm
public:
Motor() : counter(0)
{
lastUpdate = millis();
}
void encoderInput(bool pinA, bool pinB)
{
counter += (pinA ^ pinB)*(-1)+!(pinA ^ pinB);
}
int getRate() {
int ret = float(counter)/RESOLUTION/(millis() - lastUpdate)*RPMS_TO_RPM;
lastUpdate = millis();
counter = 0;
return ret;
}
};
/* Example:
* Motor motor1;
*
* void motor1_isr(void) {
* motor1.encoderInput(PIN_A, PIN_B);
* }
*
* void setup() {
* attachInterrupt(PIN_I, motor1_isr, CHANGE);
* Serial.begin(9600);
* }
*
* void loop() {
* Serial.println(motor1.getRate());
* delay(1000);
* }
*/
Спасибо за вашу помощь, я думаю, что это будет полезно и другим людям, как только это будет сделано 🙂
С Уважением,
Мистер Мистер
Вы столкнулись с фундаментальной проблемой: ISR вызывается без данных. Другими словами, функция ISR не предоставляет никаких данных, которые указывают ее источник прерывания.
Основной подход заключается в том, что человек, пишущий код, обеспечивает связь между вводом и действием путем жесткого кодирования функции. Хитрый подход, который вы ищете, — это метод, с помощью которого ISR может определить источник.
Таким образом, вы хотите иметь N двигателей с 2N входами от квадратурных энкодеров. Один обработчик прерываний подключен ко всем входным контактам в состоянии CHANGE. Один и тот же обработчик вызывается для всех N двигателей. Он может выяснить, какой двигатель обновлять, сравнивая входные контакты со значениями, которые он вызывал в последний раз. Если входные контакты изменились, вызовите этот двигатель. Вот код псевдо
Motor motor1;
Motor motor2;
onSomethingChanged() {
static int in1aprev, in1bprev;
static int in2aprev, in2bprev;
int in1a, in1b;
int in2a, in2b;
in1a = digitalRead(....
same for other in's
if( (in1a!=in1alast) || (in1b!=in1blast)) {
motor1.encoderInput(in1a,in1b);
in1alast = in1a;
in1blast = in1b;
}
if( (in2a!=in2alast) || (in2b!=in1blast)) {
motor2.encoderInput(in2a,in2b);
in1a2ast = in2a;
in1b2ast = in2b;
}
return;
}
Не так давно этот тип функции будет обрабатываться во всем чипе (см. программируемый контроллер прерываний ). Микросхема реализует всю логику для запуска и захвата источника прерывания. Основной процессор просто получает триггер «что-то случилось». Обработчик опрашивает чип, чтобы спросить «что случилось».
Предложив этот метод, я не уверен, что рекомендую. Ты не можешь скрывать что происходит с вашим кодом. Двигатель должен быть физически подключен к правильным контактам. Вы потребляли ограниченный ресурс — вы должны рассказать людям.
Других решений пока нет …