Управление шаговиком - фризы про опросе датчиков. Как избежать?

Доброго времени суток!

Делаю небольшой проект, в котром кручу шаговый двитель в цикле и далее опрашиваю датчик температуры и вывожу на дисплей.
Так вот… в loop() указываю цикл, в котором включаю шаговик и задаю частоту вращения, и кручу его в цикле 1 сек. После, код продолжается и идет опрос температуры и вывод на дисплей.
Пока идет опрос и вывод, мотор шаговик-то молчит… и это происходит ну примерно 1/4 секунды.
ВОПРОС: Как правильно построить логику, чтобы дигатель крутился постоянно без микрофризов и при этом выполнялся остальной код?
пока что, в голову приходит добавить еще одну ардуинку, но это кажись какой-то колхоз.
Можно ли это всё организовать на 1й ардуинке?

В 100500-ой строке кода уменьши delay().А то твой МК на 97 -выводе дает вместо 1 полторашку.

1 лайк

Да. Написать неблокирующий код опроса датчиков.

Нет delay(), не используется…

Подскажете?

а код покажите?

#include <GyverPID.h>
#include <PIDtuner.h>
#include <PIDtuner2.h>

#include <GyverMAX6675.h>
#include <GyverMAX6675_SPI.h>

#include <LiquidCrystal_I2C.h>
#define Step     2
#define Dir      3
#define Enabl    4

#define But_OK   5
#define But_EXIT 6
#define But_UP   7
#define But_DOWN 8

#define HEAT     9
#define Drive_ON 10

#define CS_PIN   11 // cs
#define DATA_PIN 12 // sd
#define CLK_PIN  13 // sck

#define frequency 2500 // частота

GyverMAX6675 <CLK_PIN, DATA_PIN, CS_PIN> sensor;
LiquidCrystal_I2C lcd(0x27, 20, 4); 

//uint32_t timer = 0;
uint32_t Temp = 0; // текущая температура
uint32_t SetTemp = 228; // Установленая температура
uint32_t TempCanDrive = 215; // Температура начала старта вращения
bool TempUp;
bool TempDown;
bool OnOff; //= HIGH;
bool Rotate;
bool CanDrive; // разрешено наматывать
String STATUS;

void setup() {
  lcd.init();                      // initialize the lcd 
  
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print(">");
  
  pinMode(Step,     OUTPUT);
  pinMode(Dir,      OUTPUT);
  pinMode(Enabl,    OUTPUT);  digitalWrite(Enabl, HIGH);
  pinMode(Drive_ON, OUTPUT);  digitalWrite(Drive_ON, HIGH);
  pinMode(Temp,     INPUT);
  pinMode(SetTemp,  OUTPUT);
  pinMode(HEAT,     OUTPUT);  digitalWrite(HEAT, HIGH);
  pinMode(But_OK,   INPUT);
  pinMode(But_EXIT, INPUT);
  pinMode(But_UP,   INPUT);
  pinMode(But_DOWN, INPUT);
  Rotate = LOW;
  digitalWrite(Dir, Rotate); 
  LcdTemp();
}


//---------------------------------------------
void loop() {
  TempUp    = digitalRead(But_OK);
  TempDown  = digitalRead(But_EXIT);

  SetNewTemp();
  if (CanDrive){
    digitalWrite(Drive_ON, LOW);
    digitalWrite(Enabl, LOW); 
  }else{
    digitalWrite(Drive_ON, HIGH);
    digitalWrite(Enabl, HIGH); 
  }

  for(int i = 0; i<1000; i++)  {
    digitalWrite(Step, HIGH);
    delayMicroseconds(frequency);
    digitalWrite(Step, LOW);
  }
  LcdTemp();
  OnOffHeat();
  Direct();
}
//**********************************************



// Устанавливаем новую температуру кнопками
void SetNewTemp(){
  if (TempUp){SetTemp++;}
  if (TempDown){SetTemp = SetTemp-1;}
}

// выводим на экран направление вреащения
void Direct(){
  lcd.setCursor(1,2);
  if (Rotate){
    lcd.setCursor(1,2);
    lcd.print("Rotate: Left");
  }else{
    lcd.print("Rotate: Right");
  }
}


// выводим состояние температуры
void LcdTemp(){
    lcd.setCursor(1, 0);
    lcd.print("Temp:");

    if (sensor.readTemp()){
      Temp = sensor.getTemp();
      lcd.setCursor(1, 0);
      lcd.print("Temp:"+String(Temp)+" ("+String(SetTemp)+")");
      if (Temp >= TempCanDrive){
        CanDrive = true;
      }else{
        CanDrive = false;
      } 
    }else{
        CanDrive = false;
      }
  lcd.setCursor(1, 3);
  lcd.print("CanDrive: "+String(CanDrive)+" ("+String(TempCanDrive)+")");
}

// включаем / выключаем нагреватель
void OnOffHeat(){

  if (Temp > SetTemp-3){
    OnOff = HIGH;
  }

  if (Temp < SetTemp-4){
    OnOff = LOW; 
  }

  digitalWrite(HEAT, OnOff);

  lcd.setCursor(1, 1);
  if (OnOff) {STATUS = "Off";} else {STATUS = "On ";}
  lcd.print("Nagrev:"+STATUS);
}

это убирать, в сетапе настроить таймер на частоту frequency и в его прерывании дергать ногой Step.

вариант второй,
меняете Step и Dir местами

#define Step     3
#define Dir      2

цикл тоже убираете, пишите в сетапе

analogWrite(Step, 127);

скорость двигателя поменять можно, но в небольших пределах.

Печатать на каждой итерации температуру не нужно, выводить только числа в заданной позиции.
За раз выводить одну метрику раз в 500 мс, например. За полторы секунды три штуки будут обновлены без особых тормозов.

MAX6675 опрашивается быстро, если гувер не зафейлил ничего в библиотеке.

Вот тут не понял, это как?

примерно так, один из вариантов

void setup() {
  cli();           // Отключить глобальные прерывания
  TCCR1A = 0;      // Сбросить регистр TCCR1A
  TCCR1B = 0;      // Сбросить регистр TCCR1B
  TCNT1  = 0;      // Сбросить значение счетчика

  OCR1A = 4999;    // Значение сравнения для 2.5 мс (16 МГц / 8 / 5000 - 1)
  TCCR1B |= (1 << WGM12);  // Режим CTC (сброс при совпадении)
  TCCR1B |= (1 << CS11);   // Предделитель = 8
  TIMSK1 |= (1 << OCIE1A); // Разрешить прерывание по совпадению

  sei();           // Включить глобальные прерывания
}

// Обработчик прерывания таймера 1
ISR(TIMER1_COMPA_vect) {
  // Ваш код здесь (выполняется каждые 2.5 мс)
}

void loop() {
  // Основной код
}