iskurt
24.Февраль.2025 13:46:17
1
Доброго времени суток!
Делаю небольшой проект, в котром кручу шаговый двитель в цикле и далее опрашиваю датчик температуры и вывожу на дисплей.
Так вот… в loop() указываю цикл, в котором включаю шаговик и задаю частоту вращения, и кручу его в цикле 1 сек. После, код продолжается и идет опрос температуры и вывод на дисплей.
Пока идет опрос и вывод, мотор шаговик-то молчит… и это происходит ну примерно 1/4 секунды.
ВОПРОС: Как правильно построить логику, чтобы дигатель крутился постоянно без микрофризов и при этом выполнялся остальной код?
пока что, в голову приходит добавить еще одну ардуинку, но это кажись какой-то колхоз.
Можно ли это всё организовать на 1й ардуинке?
В 100500-ой строке кода уменьши delay().А то твой МК на 97 -выводе дает вместо 1 полторашку.
1 лайк
Да. Написать неблокирующий код опроса датчиков.
iskurt
24.Февраль.2025 15:12:09
4
Штирлиц:
уменьши delay().
Нет delay(), не используется…
iskurt
24.Февраль.2025 16:08:07
7
xDriver:
а код покажите?
#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 опрашивается быстро, если гувер не зафейлил ничего в библиотеке.
iskurt
24.Февраль.2025 19:34:52
10
Вот тут не понял, это как?
xDriver
24.Февраль.2025 21:28:27
11
iskurt:
это как?
примерно так, один из вариантов
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() {
// Основной код
}