Шаговый двигатель зависает на долю секунды при приеме данных по MODBUS

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Добрый день.

Вижу крохотный лаг во вращении шагового двигателя которому надо передавать скорость по modbus
от Мастера не зависит, пробовал разные, при отключении шины RS485 вращается без запинок.

Пожалуйста помогите, что можно сделать?

C++:
#define StepperEnb 10
#define StepperDir 9
#define StepperPul 8
#define ledPin 3
#include "GyverStepper.h"
#include <ModbusRtu.h>

GStepper<STEPPER2WIRE> MainSt(800, StepperPul, StepperDir, StepperEnb); // двигатель драйвер step, dir, пин enable
int modbus_array[1] = {2000}; //Готовим массив данных
Modbus bus(2,1,4); // this is slave @2 and RS-232 or USB-FTDI
long LEDTimer = 0; int ledState = LOW;

void setup() {
MainSt.setRunMode(KEEP_SPEED); // режим поддержания скорости
MainSt.setSpeed(2000); // скорость в шагах/сек
MainSt.reverse(true);
MainSt.autoPower(true);
MainSt.enable();
pinMode(ledPin, OUTPUT);
bus.begin( 19200 ); // baud-rate at 19200
}

void loop() {
MainSt.tick(); //тикаем
bus.poll(modbus_array,1);       //Used to receive or write value from Master
if(millis() - LEDTimer > 500) {
    LEDTimer = millis();
    ledState = !ledState;
    digitalWrite(ledPin, ledState);  //мигаем
    if (modbus_array[0] ==0) {
                              MainSt.brake();
                              } else {
                                      MainSt.setSpeed(modbus_array[0]); //обновляем скорость
                                      }
  }

}
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,968
632
44
Обычно такое решается работой с прерываниями.
Первое прерывание используется при наличии данных в буфере uart. Но тут скорее всего придется библиотеку modbus ковырять.
Второе прерывание используется по таймеру для тика шаговика.

Первое что нашел:
serialEvent() - Arduino Reference
Arduino и прерывания таймера / Хабр (habr.com)
 
Изменено:

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
переписал бе бибилотеки. думал что из-за этого
но нет. лаг делает именно RS485 при приеме

C++:
#define StepperEnb 10
#define StepperDir 9
#define StepperPul 8
#include <ModbusRtu.h>

int motorSpeed = 2000;
long StT, StD = 100;
bool s=0;

int modbus_array[1] = {2000}; //Готовим массив данных
Modbus bus(2,1,4); // this is slave @2 and RS-232 or USB-FTDI

void setup() {
pinMode(StepperEnb, OUTPUT);
pinMode(StepperDir, OUTPUT);
pinMode(StepperPul, OUTPUT);

digitalWrite(StepperEnb, LOW);
digitalWrite(StepperDir, LOW);
bus.begin( 19200 ); // baud-rate at 19200
StT = micros();
}

void loop() {
bus.poll(modbus_array,1);       //Used to receive or write value from Master
StD = 500000/modbus_array[0];

if(StT+StD < micros()){
    StT = micros();
    s = not(s);
    digitalWrite(StepperPul, s);
  }
}
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,968
632
44
@78125, Лаги будут до тех пор, пока в главном цикле делается и прием данных, и обработка тика шаговика.
Попробуй для начала вынести тик шаговика в прерывание по таймеру.
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
Избыточное цитирование. Отредактируй или сообщение будет удалено
Обычно такое решается работой с прерываниями.
Первое прерывание используется при наличии данных в буфере uart. Но тут скорее всего придется библиотеку modbus ковырять.
Второе прерывание используется по таймеру для тика шаговика.

Первое что нашел:
serialEvent() - Arduino Reference
Arduino и прерывания таймера / Хабр (habr.com)
Спасибо. я правильно вас понял, что надо попробовать
MainSt.tick();
засунуть в внешний таймер а не loop?

в документации к gyverstepper написано что tick надо вызывать как можно чаще
но нет никаких примеров как часто его вызывать в таймере.
попробую покопать
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,968
632
44
Спасибо. я правильно вас понял, что надо попробовать
MainSt.tick();
засунуть в внешний таймер а не loop?
Именно.
Судя по всему modbus работает по прерыванию uart.

что tick надо вызывать как можно чаще
Нужно рассчитывать частоту вызова у таймера, потому как вызов с периодом меньше чем производится расчет может застопорить программу.
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
ТО есть его надо вызывать чуть чаще чем шаги вращения?
например 1000 шагов в секунду, то таймер должен быть не менее чем 1000 раз в секунду...
я так думаю.
попробую найти пример где то
 

78125

✩✩✩✩✩✩✩
1 Дек 2019
76
2
все получилось!
C++:
#include <GyverTimers.h>
void setup() {
Timer2.setFrequency(15000); //частота таймера 15кГц
Timer2.enableISR(CHANNEL_A); // Подключить прерывание таймера 2, канал A
    }

ISR(TIMER2_A) { //прерывание по таймеру 2А
MainSt.tick(); //тикаем
}
 
  • Лойс +1
Реакции: Геннадий П