Если вы о таймере на миллис, то пробовал. Шаговик на больших оборотах начинает работать с провалами.
Так что, вашего кода мы не увидим?
Так и будем играть в угадайку?
Вам не приходит в голову, что если б вы знали, как правильно настроить работу шаговика на миллис - вы бы сюда не пришли?
Как пробовал, что пробовал … ХЗ – сами догадывайтесь.
Считал, что если таймер0 занят милисами и микросами, а первый еще чем то, то единственный свободный остается только второй.
Код для серво и шаговика:
#define SERVO1_PIN 10 // Серва компонента
#define SERVO2_PIN 9 // Серва компонента В
#include <Wire.h>
#include "Parser.h"
#include "AsyncStream.h"
AsyncStream<50> serial(&Serial, ';');
//-----------------------Шаговый двигатель-------------------------------------------------------
#include <GyverStepper2.h>
GStepper2< STEPPER2WIRE> stepper(1500, 7, 12, 8);//(шагов_На_Оборот, pin step, pin dir, pin en)
//------------------- формат пакета для приёма----------------------------------------------------
uint8_t speed; // Мешалка
uint8_t speed1; // Вибростол
uint8_t steer; // Серво А
uint8_t steer1; // Серво В
uint16_t sum; // Пересылаемая контрольная сумма
uint16_t sum1; // Сумма данных принятая по факту
//--------------------------Серво------------------------------------------------------------------
#include <ServoSmooth.h> //........#include <Servo.h>
ServoSmooth servo1 ; // Серва компонента А
ServoSmooth servo2 ; // Серва компонента В
// переменные таймеров
uint32_t myTimer1, myTimer2;
#include "GyverTimers.h"
void setup() {
pinMode(6, OUTPUT);
Serial.begin(38400);
Serial.setTimeout(50); // Установка таймаута для парсинга из буфера по сериал
Timer2.setFrequency(9000); // Устанавливаем период таймера 10000 мкс -> 100 гц
Timer2.enableISR(CHANNEL_B); // Запускаем прерывание на канале B таймера 2
//// outputEnable(CHANNEL_B, SET_PIN);
//// outputDisable(CHANNEL_B);
// //------------------------Включаем шаговик---------------------------------
stepper.setMaxSpeed(100);//stepper.setRunMode(KEEP_SPEED);
stepper.setAcceleration(200);
//
// //------------------------- Серво------------------------------------
servo1.attach(10, 0); //серво компонента А на пин D6, нулевое положение при включении в 0 градусов
servo2.attach(9, 100);//серво компонента В на пин 5, нулевое положение при включении в 180 градусов
servo1.setSpeed(250);// скорость для серво А - 180
servo2.setSpeed(250);//скорость для В
servo1.setAccel(0.8);//ускорение для А
servo2.setAccel(0.8);// ускорение для серво В - 0,5
servo1.setAutoDetach(false); // отключить автоотключение (detach) при достижении целевого угла (по умолчанию включено)
servo2.setAutoDetach(false); // отключить автоотключение (detach) при достижении целевого угла (по умолчанию включено)
}
void loop() {
//-----------------Приём данных------------------
static byte prevAm = 0;
static uint32_t tmr = 0;
byte am = Serial.available();
if (am != prevAm) {
prevAm = am;
tmr = millis();
}
if ((am && millis() - tmr > 10) || am > 80) {
char str[30];
int amount = Serial.readBytesUntil(';', str, 30);
str[amount] = NULL;
// разделяет строку на подстроки
int data[5]; // буфер интов
int count = 0; // счётчик интов
char* offset = str; // указатель для работы
while (true) {
data[count++] = atoi(offset); // пишем число в буфер
offset = strchr(offset, ','); // поиск следующей запятой
if (offset) offset++; // если это не NULL - продолжаем
else break; // иначе покидаем цикл
speed = data[0]; // Мешалка
speed1 = data[1]; // Вибростол
steer = data[3]; // Серво А
steer1 = data[2]; // Серво В
sum = data[4]+1; // пересланная сумма
sum1 = speed1 + speed + steer1 + steer +1;
if (sum1 = sum) {
servo1.setTargetDeg(100-steer); // Серва компонента А (10 пин), задан угол
servo2.setTargetDeg(100-steer1); // Серва компонента В (9 пин) задан угол
stepper.setSpeed(speed*25); // шагов/сек
if (speed>3) { //проверка запуска мешалки и включение питание на ша9 говик
stepper.enable();// включить питание и EN
} else
stepper.disable();// отключить питание и EN
} else;
}
}
}
ISR(TIMER2_B) { // вызываем tick-и
stepper.tick();
servo1.tick();
servo2.tick();
}
Рассматривал вариант подключения второй нано. Мегу не рассматривал. Рассматривал RP, STM, ESP.
Показались сложными на порядок с поиском библиотек и примеров
Спасибо за наводку.
Подробно код не смотрел.
Целесообразность вызова servo1.tick(); в прерывании под сомнением, т.к. управляющие сигналы на серво выдаются с периодом 20 мс, и если loop выполняется дольше 10 мс, то велика вероятность, что это можно исправить.
Но если принять, что данный вызов правилен, то перенос на Таймер0 не сложен. Надо настроить прерывание на TIMER0_B или TIMER0_A или на то и на то. Т.к. периодичность прерывания TIMER0_A/B примерно 1 мс, то если надо больше, то добавить в прерывание счетчик, и вызывать тики каждое N - ное прерывание. В коде TIMER0_B_N
Дополнительно лучше разнести на разные периоды вызовы тиков, чтобы не затягивать выполнение прерывания TIMER0_A/B Например если то N=3 то stepper тикает на N=1, servo1 на N=2, servo1 на N=3. Но это уже “улучшения”, просто 1 в 1 переносится легко.
ISR(TIMER0_B) { // вызываем tick-и
static byte cnt = 0;
if(++cnt == TIMER0_B_N){
cnt=0;
stepper.tick();
servo1.tick();
servo2.tick();
}
}
Понял, спасибо за разъяснения.
Буду пробовать.
Шаговики на большой скорости всё равно будут терять момент - хоть перестраивай таймер, хоть не перестраивай.
Вот это вообще плохо.
Да, в таком случае понятно, почему тики servo в прерываниях таймера работают лучше чем в loop.
Лучше не нашел.
Ну а шаговик не просто теряет момент, а происходит сбой даже на холостом ходу без нагрузки. Причем если убрать все и оставить только шаговик, то сбоев нет даже с требуемой нагрузкой (она не большая).
То есть причина в потере управляющих импульсов step изза излишней загрузки расчетами процессора других строчек кода помимо шаговика. Особенно злосчастный парсинг замедляет всю систему.
Переход на прерывание по таймеру спасло и более менее работает без провалов.
Вообще автором этого куска (он, кусок кстати не полный, там много к нему относится) заявлялось, что ридбайтунтил работает асинхронно через дополнительный, допомвведенный буфер без приостановки выполнения кода при чтении и это существенно увеличивает скорость чтения ридбайтс по сериал и это как бы очень хорошее по скорости решение.
Так что я выбирал метод парсинга исходя из того что стандартный ридбайтунтил существенно замедляет выполнение кода и это нужно как-то исправить. И скорее всего вы дали оценку методу парсинга без учёта выше озвученного.

AsyncStream<50> serial(&Serial, ';');
То, что вы пишите, скорее всего заверялось для serial с маленькой s . А вы используете Serial.readBytesUntil с БОЛЬШОЙ S, т.е. обычный стандартный.
В библиотеке AsyncStream.h фоновое получение данных происходит при вызове serial.available() (с маленькой буквы s)
П.С. Я этой библиотекой не пользовался.

И скорее всего вы дали оценку методу парсинга без учёта выше озвученного
Можете даже не сомневаться. Я, как увидел число 30, сразу предположил, что тут явно цикл ожидания с таймаутом.

тут явно цикл ожидания с таймаутом.
А заявлено как ожидание до терминатора, которым выступает сомвол “;”, присутствующий в конце каждого пакета.
И как только этот символ “;” принимается, то ожидание прекращается.
А тайм аут указан на всякий случай как крайне нештатная ситуация.

А заявлено как ожидание до терминатора
Где же тут асинхронность?

Где же тут асинхронность?
Ссылку на видео (Ютуб) автора кода с разъяснениями могу дать если интересно.
Прям в то место. По времени минута или две.

То, что вы пишите, скорее всего заверялось для serial с маленькой s . А вы используете Serial.readBytesUntil с БОЛЬШОЙ S, т.е. обычный стандартный
Скрин с кода автора

Ссылку на видео (Ютуб) автора кода с разъяснениями могу дать если интересно.
Да мне не особо надо, я ридантилами не пользуюсь.

Скрин с кода автора
Автор тоже мог описаться. Особенно если это гайвер.

Автор тоже мог описаться. Особенно если это гайвер.
Навряд ли.
Работает быстрее чем просто стандартный ридбайтунтил.
Это же легко проверить.
Он собственно в видео это и проверяет. Делает и так и так.