Управление двигателем 28byj-48 с кнопки.

AKi
Offline
Зарегистрирован: 28.09.2018

Здравствуйте! Только начал осваивать ардуино. Пытаюсь управлять шаговым двигателем с кнопки: нажал - двигатель включился, нажал снова - остановился. Никак не могу понять, что надо сделать. Научился пока только вращать вал двигателя при зажатой кнопке. 

bwn
Offline
Зарегистрирован: 25.08.2014

Поймали кнопку, подняли флаг, поймали второй раз, опустили флаг. Если флаг поднят, вращаем, иначе стоп.

AKi
Offline
Зарегистрирован: 28.09.2018

Вот именно с флагом и непонятно. Пытался чужой пример под себя переписать, но это, ожидаемо, не дало нужного результата. Можете пример кода привести?

AKi
Offline
Зарегистрирован: 28.09.2018

Пока я дозрел до такого кода:

#include <AccelStepper.h>

#define motorPin1  8 // IN1 на драйвере ULN2003
#define motorPin2  9 // IN2 на драйвере ULN2003
#define motorPin3  10 // IN3 на драйвере ULN2003
#define motorPin4  11 // IN4 на драйвере ULN2003

const int buttonPin = 3;     // номер входа, подключенный к кнопке
int flag = 0;
int val = 0;

AccelStepper stepper_motor(8, motorPin1, motorPin3, motorPin2, motorPin4);
 
void setup () {

  stepper_motor.setMaxSpeed(1245);// максимальная скорость мотора
  stepper_motor.setSpeed(200);// дефолтная скорость мотора

  pinMode(buttonPin, INPUT);
}

void loop () {

 if(digitalRead(3)== LOW && flag == 0)
     {         
       flag=1;
       stepper_motor.runSpeed();   
    val++;
    
     }
    
     if(digitalRead(3) == LOW && flag == 1)
  {
   stepper_motor.stop();
    val = 0;
    flag = 0;
    
     }

}

 

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

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Работает, как написано. Но написано не так, как задумано.

Пока Вы держите кнопку, на D3 постоянно будет LOW и оба условия всегда станут исполнятся по-очереди. Найдите еще одну библиотеку, которая отслеживает именно нажатие кнопки (переход из HIGH в LOW).

bwn
Offline
Зарегистрирован: 25.08.2014

Ну для начала, вставьте код нормально, с номерами строк. Потом выкиньте все свои двигатели и научитесь гасить-зажигать светик на 13 пине. Когда получится, начинайте с двигателя совокуплять. Примерно так:
 


boolean flag = true;

void setup() {
  pinMode(13, OUTPUT);
  pinMode(3,INPUT);
  digitalWrite(13,LOW);
  
}

void loop() {
  if (digitalRead(3) == LOW && flag == true) {
    flag = !flag;
    digitalWrite(13, !digitalRead(13));
  }
  if (digitalRead(3,HIGH)) {
    flag =!flag;
  }
}

От дребезга ничего нет.

AKi
Offline
Зарегистрирован: 28.09.2018

Почитав книгу дозрел до такого кода:

const int LED=13; //Контакт 7 для светодиода
const int BUTTON=3; //Контакт 3 для кнопки
boolean lastButton = LOW; //Переменная для сохр. пред. состояния кнопки
boolean currentButton = LOW; //Переменная для сохр. текущ. состояния кнопки
boolean ledOn = false; // Текущее состояние светодиода

#include <AccelStepper.h> //Подключение библиотеки

//Опредение выходов для управления двигателем
#define motorPin1  8     
#define motorPin2  9     
#define motorPin3  10     
#define motorPin4  11   
#define HALFSTEP 8

AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);

void setup()
{
  pinMode (LED, OUTPUT); // Конфигурация контакта светодиода как выход
  pinMode (BUTTON, INPUT); //Конфигурация контакта кнопки как вход
  steppermotorfunction();
  stepper1.setMaxSpeed(1245);
  stepper1.setSpeed(271.6);
}

boolean debounce(boolean last) //Функция подавления дребезга кнопки
{
  boolean current = digitalRead(BUTTON); //Считать состояние кнопки
  if (last != current) //Если изменилось
  {
    delay(20); //Задержка 20мс
    current = digitalRead(BUTTON); //Считать состояние кнопки
    return current; //Возвращение состояние кнопки
  }
}

void steppermotorfunction()
{
  stepper1.runSpeed();
}

void loop()
{
  currentButton = debounce(lastButton);
  if (lastButton ==LOW && currentButton == HIGH) //Если нажатие
  {
    ledOn = !ledOn; //Инверсия состояния светодиода
    steppermotorfunction(); //Отсылка на функцию двигателя 
  }
    lastButton = currentButton;
    digitalWrite(LED, ledOn); //Изменить статус состояния светодиода

}

Но всё равно всё работает не совсем так, как хочется. При нажатии кнопки светодиод включается/отключается, а шаговик делает только 1 шаг.

sadman41
Offline
Зарегистрирован: 19.10.2016

Сколько раз при нажатии на кнопку переключается светодиод?

AKi
Offline
Зарегистрирован: 28.09.2018

При одном нажатии - светодиод 1 раз меняет состояние.

sadman41
Offline
Зарегистрирован: 19.10.2016

Отлично. Видите какую-либо связь между одинарной сменой состояния и одним шагом двигателя?

Подсказываю: делайте шаги, пока состояние светодиода равно true.

AKi
Offline
Зарегистрирован: 28.09.2018

Всё заработало. Спасибо за советы. Вот мой код. Вдруг кому то понадобиться.
Ещё есть вопросы по оптимизации. Возможно код ещё проще написать можно. Хотелось бы комментарии услышать.
 

const int LED=13; //Контакт 7 для светодиода
const int BUTTON=3; //Контакт 3 для кнопки
boolean lastButton = LOW; //Переменная для сохр. пред. состояния кнопки
boolean currentButton = LOW; //Переменная для сохр. текущ. состояния кнопки
boolean ledOn = true; // Текущее состояние светодиода

#include <AccelStepper.h> //Подключение библиотеки

//Опредение выходов для управления двигателем
#define motorPin1  8     
#define motorPin2  9     
#define motorPin3  10     
#define motorPin4  11   
#define HALFSTEP 8 //Полушаговый режим работы

AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4); //Инициализация управления

void setup() //Настройки
{
  pinMode (LED, OUTPUT); // Конфигурация контакта светодиода как выход
  pinMode (BUTTON, INPUT); //Конфигурация контакта кнопки как вход
  steppermotorfunction(); //Прописывание функции
  stepper1.setMaxSpeed(1245); //Установка максимальной скорости (об/мин)
  stepper1.setSpeed(271.6); //Установка скорости (шаг/сек)
}

boolean debounce(boolean last) //Функция подавления дребезга кнопки
{
  boolean current = digitalRead(BUTTON); //Считать состояние кнопки
  if (last != current) //Если изменилось
  {
    delay(20); //Задержка 20мс
    current = digitalRead(BUTTON); //Считать состояние кнопки
    return current; //Возвращение состояние кнопки
  }
}

void steppermotorfunction() //Описание функции двигателя
{
  stepper1.runSpeed(); //Начать движение с заданной скоростью
}

void loop() //Цикл
{
  currentButton = debounce(lastButton);
  if (lastButton ==LOW && currentButton == HIGH) //Если нажатие
  {
    ledOn = !ledOn; //Инверсия состояния светодиода
  }
    lastButton = currentButton;
    digitalWrite(LED, ledOn); //Изменить статус состояния светодиода
    
  if (ledOn ==true) //Если светодиод вкл, то
  {
     steppermotorfunction(); //Отсылка на функцию двигателя 
  } 

}

 

AKi
Offline
Зарегистрирован: 28.09.2018

Подумал над кодом и избавился от функции двигателя и сделал важное улучшение. Сразу не додумался, что надо подавать низкий уровень на управляющие входы драйвера двигателя. А так и двигатель не греется и ток малый потребляет устройство во время простоя.

 

const int LED=7; //Контакт 7 для светодиода
const int BUTTON=3; //Контакт 3 для кнопки
boolean lastButton = LOW; //Переменная для сохр. пред. состояния кнопки
boolean currentButton = LOW; //Переменная для сохр. текущ. состояния кнопки
boolean ledOn = true; // Текущее состояние светодиода
#include <AccelStepper.h> //Подключение библиотеки
//Опредение выходов для управления двигателем
#define motorPin1  8     
#define motorPin2  9     
#define motorPin3  10     
#define motorPin4  11   
#define HALFSTEP 8 //Полушаговый режим работы
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4); //Инициализация управления
void setup() //Настройки
{
  pinMode (LED, OUTPUT); // Конфигурация контакта светодиода как выход
  pinMode (BUTTON, INPUT); //Конфигурация контакта кнопки как вход
  stepper1.setMaxSpeed(1245); //Установка максимальной скорости (об/мин)
  stepper1.setSpeed(271.6); //Установка скорости (шаг/сек)
}
boolean debounce(boolean last) //Функция подавления дребезга кнопки
{
  boolean current = digitalRead(BUTTON); //Считать состояние кнопки
  if (last != current) //Если изменилось
  {
    delay(20); //Задержка 20мс
    current = digitalRead(BUTTON); //Считать состояние кнопки
    return current; //Возвращение состояние кнопки
  }
}
void loop() //Цикл
{
  currentButton = debounce(lastButton);
  if (lastButton ==LOW && currentButton == HIGH) //Если нажатие
  {
    ledOn = !ledOn; //Инверсия состояния светодиода
  }
    lastButton = currentButton;
    digitalWrite(LED, ledOn); //Изменить статус состояния светодиода   
  if (ledOn ==true) //Если светодиод вкл, то...
  {
     stepper1.runSpeed(); //Отсылка на функцию двигателя 
  } 
  if (ledOn ==false) //Если светодиод выкл, то...
  {
    stepper1.disableOutputs(); //Снять напряжение с обмотки двигателя
  }
}

 

jdigreze
Offline
Зарегистрирован: 14.01.2018

AKi пишет:

Подумал над кодом и избавился от функции двигателя и сделал важное улучшение. Сразу не додумался, что надо подавать низкий уровень на управляющие входы драйвера двигателя. А так и двигатель не греется и ток малый потребляет устройство во время простоя.

Не совсем оптимизация, но вот это:

  if (ledOn ==true) //Если светодиод вкл, то...
  {
     stepper1.runSpeed(); //Отсылка на функцию двигателя 
  } 
  if (ledOn ==false) //Если светодиод выкл, то...
  {
    stepper1.disableOutputs(); //Снять напряжение с обмотки двигателя
  }

можно переписать вот так:

  if (ledOn) stepper1.runSpeed(); else stepper1.disableOutputs();

 

AKi
Offline
Зарегистрирован: 28.09.2018

Не додумался до такого. Спасибо)

AKi
Offline
Зарегистрирован: 28.09.2018

Как мне добавить в код ещё две кнопки так, чтобы у них дребезг также программно подавлялся?

AKi
Offline
Зарегистрирован: 28.09.2018

Написал код. Всё работает как надо, но двигатель вращается со скоростью меньше рассчётной и если изменять скорость вращения двигателя в программе - ничего не меняется по факту. Не могу понять причину.

 

#include <AccelStepper.h> //Подключение библиотеки

const int LED = 8;
const int BUT1 = 5;
const int BUT2 = 6;
const int BUT3 = 7;
const int OUT1 = 2;
const int OUT2 = 3;

boolean lastButtonOn = LOW; //Переменная для сохр. пред. состояния кнопки
boolean currentButtonOn = LOW; //Переменная для сохр. текущ. состояния кнопки
boolean lastButtonLaser1 = LOW;
boolean currentButtonLaser1 = LOW;
boolean lastButtonLaser2 = LOW;
boolean currentButtonLaser2 = LOW;
boolean ledOn = true; // Текущее состояние светодиода

int flag1 = 0;
int flag2 = 0;

//Опредение выходов для управления двигателем
#define motorPin1 12    
#define motorPin2 11     
#define motorPin3 10     
#define motorPin4 9 
#define HALFSTEP 8 //Полушаговый режим работы
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4); //Инициализация управления

void setup() //Настройки
{
  pinMode (LED, OUTPUT); // Конфигурация контакта светодиода как выход
  pinMode (BUT1, INPUT); //Конфигурация контакта кнопки как вход
  pinMode (BUT2, INPUT);
  pinMode (BUT3, INPUT);
  stepper1.setMaxSpeed(1245); //Установка максимальной скорости (об/мин)
  stepper1.setSpeed(271.6); //Установка скорости (шаг/сек)
}

boolean debounce(boolean last, int BUT) //Функция подавления дребезга кнопки
{
  boolean current = digitalRead(BUT); //Считать состояние кнопки
  if (last != current) //Если изменилось
  {
    delay(20); //Задержка 20мс
    current = digitalRead(BUT); //Считать состояние кнопки
    return current; //Возвращение состояние кнопки
  }
}

void loop() //Цикл
{
  currentButtonOn = debounce(lastButtonOn, BUT1);
  currentButtonLaser1 = debounce(lastButtonLaser1, BUT2);
  currentButtonLaser2 = debounce(lastButtonLaser2, BUT3);
  if (lastButtonOn == LOW && currentButtonOn == HIGH) //Если нажатие
  {
    ledOn = !ledOn; //Инверсия состояния светодиода
  }
    lastButtonOn = currentButtonOn;
    digitalWrite(LED, ledOn); //Изменить статус состояния светодиода 
    
  if (ledOn == true) //Если светодиод вкл, то...
  {
    stepper1.runSpeed();//Отсылка на функцию двигателя
  } 
  else
  {
    stepper1.disableOutputs(); //Снять напряжение с обмотки двигателя
  }

  if(digitalRead(BUT2) == LOW && flag1 == 0)      
    {                                              
      digitalWrite(OUT1, !digitalRead(OUT1));
      flag1 = 1;
    }
  
  if(digitalRead(BUT2) == HIGH && flag1 == 1)
    {
      flag1 = 0;
    }  


  if(digitalRead(BUT3) == LOW && flag2 == 0)      
    {                                              
      digitalWrite(OUT2, !digitalRead(OUT2));
      flag2 = 1;
    }
  
  if(digitalRead(BUT3) == HIGH && flag2 == 1)
    {
      flag2 = 0;
    } 
}

 

AKi
Offline
Зарегистрирован: 28.09.2018

Выяснил, что причина кроется в проверке состояния кнопок в этом месте кода:

 

void loop() //Цикл
51
	{
52
	  currentButtonOn = debounce(lastButtonOn, BUT1);
53
	  currentButtonLaser1 = debounce(lastButtonLaser1, BUT2);
54
	  currentButtonLaser2 = debounce(lastButtonLaser2, BUT3);

Если отключить 53 и 54 строки, то двигатель вращается с нужной скоростью, если проверка включена, то скорость двигателя - очень маленькая. Почему так происходит я разобраться пока что не могу.

sadman41
Offline
Зарегистрирован: 19.10.2016

Как подключены кнопки к плате (схема)?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AKi пишет:

Если отключить 53 и 54 строки, то двигатель вращается с нужной скоростью, если проверка включена, то скорость двигателя - очень маленькая. Почему так происходит я разобраться пока что не могу.

А заглянуть внутрь функции debounce() и обратить внимание на 44 строку, конечно, не судьба.

vvadim
Offline
Зарегистрирован: 23.05.2012

AKi пишет:

Написал код. Всё работает как надо, но двигатель вращается со скоростью меньше рассчётной и если изменять скорость вращения двигателя в программе - ничего не меняется по факту. Не могу понять причину.

 

AccelStepper сама по себе тормознутая, а вы в код постоянно задержку бросаете.

на форуме стотыщ примеров как работать с кнопками без делеев.

AKi
Offline
Зарегистрирован: 28.09.2018

Логично, да. Когда кодил среди ночи - уже не понимал это.
Спасибо за ответы!