Общение через Монитор Порта с Ардуино

Armata
Offline
Зарегистрирован: 04.03.2018

Здравствуйте друзья.Пробую написать скетч,хочу управлять шаговиком через монитор порта.

Если с библиотекой и работой с ней уже разобрался то с монитором порта всё туго...А дело в том что хочу сделать такое себе меню с несколькими вариантами работы.Но ничего не получается.Помогите понять что сделал не так?

КОД:

#include <Arduino.h>

//Параметры двигателя 
#define MOTOR_STEPS 200
#define RPM 120
#define DIR 8
#define STEP 9

//Инициализация параметров драйвера
#include "DRV8825.h"
#define MODE0 10
#define MODE1 11
#define MODE2 12
DRV8825 stepper(MOTOR_STEPS, DIR, STEP, MODE0, MODE1, MODE2);

//Переменные
int Mode = 0;
int Impulses = 0;
int Speed = 0;
int Angle1 = 0;
int Angle2 = 0;

void setup() {
    Serial.begin(115200);
    stepper.begin(RPM);
    stepper.enable();
    Serial.println("Выберите режим 1-4:"); 
    doMode();
}

void loop() {
    doMode();   
}

void doMode(){
  if (Serial.available() > 0) {  //если есть доступные данные
    Mode = Serial.parseInt();  // считываем байт
    Serial.print("Выбран режим: ");   // отсылаем то, что получили
    Serial.println(Mode);}
    else if (Mode > 4){
       Mode = 0;
       Serial.println("Выбран несуществующий режим!");
    }
    
  switch (Mode){
  
//Логика режима 1:
    case 1:
          Serial.println("Количество шагов и направлеие(для влево введите количество шагов со знаком -(минус): ");
          if (Serial.available()) {  //если есть доступные данные
            
           Impulses = Serial.parseInt();
             Serial.print("Количество шагов и направлеие:");
             Serial.println(Impulses);
          if (Serial.available()) {  //если есть доступные данные
            Serial.print("Установите скорость: ");
           Speed = Serial.parseInt();
             Serial.print("Cкорость:");
             Serial.println(Speed);}}
          break;  
          
//Логика режима 2:
     case 2:
      
          Serial.println("Установите скорость: ");
          if (Serial.available() > 0) {  //если есть доступные данные
          Speed = Serial.parseInt();
          Serial.print("Cкорость:");
          Serial.println(Speed);}
          stepper.setMicrostep(4);  // Set microstep mode to 1:1
          stepper.rotate(Impulses); 
          break; 

  

Вся проблема в том что после выбора например 1 режима начинается цикличная прокрутка фразы "Количество шагов и направлеие(для влево введите количество шагов со знаком -(минус): " и всё,не реагирует больше.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

А какая работа ожидалось?

Armata
Offline
Зарегистрирован: 04.03.2018

Нужно чтобы после выбора режима 1:

Напечатало "Количество шагов и направлеие(для влево введите количество шагов со знаком -(минус):     

затем я ввел значение допустим 300   

Напечатало "Установите скорость: "                  

ввел значение допустим 100,отправил 

и шаговик повернулся на заданые параметры.

после чего вышел и ждёт какой режим выберут.

Второй по аналогии.

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

А автор кода чо говорит?

Armata
Offline
Зарегистрирован: 04.03.2018

Так я сам его писал.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Где вы в свиче выпрыгиваете из case 1 или крутите мотор?

Armata
Offline
Зарегистрирован: 04.03.2018

Дописал 

//Логика режима 1:
    case 1:
          
          Serial.println("Количество шагов и направлеие(для влево введите количество шагов со знаком -(минус): ");
          if (Serial.available()) {                             // Если есть доступные данные
            Impulses = Serial.parseInt();                       // Считываем 
             Serial.print("Количество шагов и направлеие: ");   // Отсылаем то, что получили
             Serial.println(Impulses);
             Serial.print("Установите скорость: ");
          if (Serial.available()) {                             // Если есть доступные данные
            Speed = Serial.parseInt();                          // Считываем 
             Serial.print("Cкорость:");                         // Отсылаем то, что получили
             Serial.println(Speed);}}
             //Отрабатываем все введённые данные на шаговике
             stepper.begin(Speed);                              // Со скоростью 
             stepper.setMicrostep(1);                           // С шагом
             stepper.rotate(Impulses/1.8);                      // Количеством импульсов
             break;

 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

А "после чего вышел" где? Mode не меняется и на следующем лупе опять попадаете в case 1.

Armata
Offline
Зарегистрирован: 04.03.2018

По ходу туплю но не мойму как сдклать событие после которого он выйдет.Сейчас получается что если выбрать режим пишет"Ввести количество импульсов" но если ввести то он опять выбирает Mode.

#include <Arduino.h>

//Параметры двигателя 
 #define MOTOR_STEPS 200
 #define RPM
 #define DIR 8
 #define STEP 9
 
//Инициализация параметров драйвера
 #include "DRV8825.h"
 #define MODE0 10
 #define MODE1 11
 #define MODE2 12
 DRV8825 stepper(MOTOR_STEPS, DIR, STEP, MODE0, MODE1, MODE2);
 
//Переменные
 int Mode = 0;
 int Impulses = 0;
 int Speed = 0;
 int Angle1 = 0;
 int Angle2 = 0;

void setup() {
    Serial.begin(115200);
    stepper.enable();
    Serial.println("Выберите режим 1-4:"); 
 }

void loop() {
      doMode(); 
}

void doMode(){
    if (Serial.available() > 0) {                               // Если есть доступные данные
       Mode = Serial.parseInt();                                // Считываем 
        Serial.print("Выбран режим: ");                         // Отсылаем то, что получили
        Serial.println(Mode);}             
    else if (Mode > 4){                                         // Если выбран несуществующий режим то присваеваем режиму 0
       Mode = 0;
        Serial.println("Выбран несуществующий режим!");
    }
    
  switch (Mode){
  
//Логика режима 1:
    case 1:
          
          Serial.println("Количество шагов и направлеие(для влево введите количество шагов со знаком -(минус): ");
          if (Serial.available()) {                             // Если есть доступные данные
            Impulses = Serial.parseInt();                       // Считываем 
             Serial.print("Количество шагов и направлеие: ");   // Отсылаем то, что получили
             Serial.println(Impulses);
             Serial.print("Установите скорость: ");
          if (Serial.available()) {                             // Если есть доступные данные
            Speed = Serial.parseInt();                          // Считываем 
             Serial.print("Cкорость:");                         // Отсылаем то, что получили
             Serial.println(Speed);}}  
             //Отрабатываем все введённые данные на шаговике
             stepper.begin(Speed);                              // Со скоростью 
             stepper.setMicrostep(1);                           // С шагом
             stepper.rotate(Impulses/1.8);                      // Количеством импульсов
             break;  
          
//Логика режима 2:
     case 2:
      
          Serial.println("Установите скорость: ");
          if (Serial.available() > 0) {                         // Если есть доступные данные
          Speed = Serial.parseInt();                            // Считываем 
          Serial.print("Cкорость:");                            // Отсылаем то, что получили
          Serial.println(Speed);}
          //Отрабатываем все введённые данные на шаговике
          stepper.begin(Speed);                                 // Со скоростью
          stepper.setMicrostep(2);                              // С шагом
          stepper.rotate(Impulses);                             // Количеством импульсов
          break;   
 }

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Ваша проблема в том, что вы не понимаете, что такое асинхронность и неблокирующая работа. Пример простой: вы напечатали в Serial приглашение, и ТУТ ЖЕ проверяете, что там в приёмном буфере. Очевидно, что в этот момент там может быть - ничего.

Смотрите, какая история: давайте представим, что у нас есть флажки, скажем, 3 штуки разных цветов - как светофор. И, понимая, какой  флажок сейчас поднят - мы знаем, что должны делать. Я вам сейчас ниже напишу логику в псевдокоде, чтобы было понятно, как это работает, а вы попытаетесь разобраться, ок?


typedef enum
{
	WAIT_MODE, // ждём выбора режима
	WAIT_PARAM1, // ждём ввода параметра 1
	WAIT_PARAM2, // ждём ввода параметра 2
	WAIT_PARAM3, // ждём ввода параметра 3
	WAIT_STEPPER_DONE, // ждём, когда шаговик закончит шагать
} MachineState;

MachineState state = WAIT_MODE;

typedef enum
{
	ModeUnknown,
	Mode1,
	Mode2,
	Mode3,
	Mode4
	
} WorkMode;

WorkMode mode = ModeUnknown;

void setup()
{
	Serial.begin(9600);
	Serial.println(F("Введите режим: [1-4]"));
}

void loop()
{
	switch(state)
	{
		case WAIT_MODE: // ждём выбора режима
		{
			// тут ждём выбора режима, для простоты - просто Serial.parseInt
			mode = (WorkMode) Serial.parseInt();
			if(mode != ModeUnknown)
			{
				switch(mode)
				{
					case ModeUnknown: break;
					
					case Mode1:
					{
						Serial.println(F("Режим 1, введите скорость:"));
					}
					break;
					
					case Mode2:
					{
						Serial.println(F("Режим 2, введите направление:"));
					}
					break;
					
					case Mode3:
					{
						Serial.println(F("Режим 3, введите высоту:"));
					}
					break;
					
					case Mode4:
					{
						Serial.println(F("Режим 5, введите время:"));
					}
					break;
						

				}
				
				state = WAIT_PARAM1; // переключаемся на другую ветку
			}
		}
		break; // WAIT_MODE
		
		case WAIT_PARAM1:
		{
			// тут ждём ввода первого параметра. Кол-во параметров может быть разным, в зависимости от режима
			int input = Serial.parseInt();
			if(input)
			{
				switch(mode)
				{
					case ModeUnknown: break;
					
					case Mode1:
					{
						// в первом режиме сразу запускаем шаговик
						stepper.run(input);
						state = WAIT_STEPPER_DONE;
					}
					break;
					
					case Mode2:
					{
						// во втором режиме - просим ввести ещё чего-нибудь
						Serial.println(F("Введите второй параметр:"));
						state = WAIT_PARAM2;
					}
					break;
					
					// ... и т.п.
				} // switch
			}
		}
		break; // WAIT_PARAM1
		
		//...
		
		case WAIT_STEPPER_DONE:
		{
			// ждём, пока движок закончит работу, игнорируем весь ввод в Serial
			while(Serial.available()) Serial.read();
			
			if(stepper.done())
			{
				Serial.println(F("ВЫПОЛНИЛИ!"));
				state = WAIT_MODE; // переключаемся на ожидание ввода режима
				Serial.println(F("Введите режим: [1-4]"));
			}
		}
		break; // WAIT_STEPPER_DONE
		
	} // switch
	
	// обновняем состояние шагового, если надо
	stepper.update();
}

Это простой конечный автомат, писанный буквально в лоб. В тот или иной момент - выполняется одна ветка кода, при этом состояние системы (например, введённый режим работы) - известны в переменных. Достаточно чуть-чуть дописать - и будет прошивка, выполняющая то, что вам нужно.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

А как сделали событие по которому входит?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Armata пишет:

Вся проблема в том что после выбора например 1 режима начинается цикличная прокрутка фразы "Количество шагов и направлеие(для влево введите количество шагов со знаком -(минус): " и всё,не реагирует больше.

Код неполный, потому если не поможет, то публикуйте полный, так программы не смотрят.

На первый взгляд, вы не доедаете Serial (если конечно, они не решены в полном коде). Кроме того, у Вас странная логика.

Вот давайте смотреть.

Про недоедание. После функций типа parseInt во входном буфере остаются символы перевода каретки и возврата строки. Их надо вычитать.

И про логику. См. Ваши строки 49-50 (и много пободных). Вот Вы напечатали текст, проверили есть ли там чего в буфере (а там нет, т.к. юзер ещё не успел ничего ввести) и летите дальше ... ещё раз печатать текст и снова проверять. 

Вот так она у Вас и работает.

Наверное в этом месте нужно было не проверять и бежать сломя голову, а ждать пока юзер введёт. Или уж если не ждать, а заниматься своими делами, то не печатать приглашение каждый раз, а просто периодически посматривать "не ввёл ли".

Разберитесь с сериалом БЕЗ МОТОРОВ НА КРОХОТНОМ ПРИМЕРЕ - НЕ ВАЛИТЕ ВСЁ КУЧУ!

Вот смотрите.

void setup(void) {
	Serial.begin(115200);
}

void loop(void) {
  doMode();
}

void doMode(void) {
	Serial.println("Вводи mode:");
	while(! Serial.available()); // Ждём пока юзер введёт
	int mode = Serial.parseInt();
	Serial.print("mode= ");
	Serial.println(mode);
	while(Serial.available()) Serial.read(); // доедаем
}

Попробуйте убрать доедание и посмотреть, что будет. Попробуйте вместо ожидания вставить Вашу проверку и опять же посмотрите.

И всегда так поступайте - отлаживайтесь по отдельности, не валите всё в кучу. Ешьте слона по частям.

Armata
Offline
Зарегистрирован: 04.03.2018

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

Armata
Offline
Зарегистрирован: 04.03.2018

Спасибо вам,попробую разобраться.

Messiah
Offline
Зарегистрирован: 10.11.2018

Добрый вечер. Читать данные из порта в loop() это плохая идея. Вот как я в своем первом аппаратном решении реализовывал нечто подобное:

void serialEvent() {

  mydelay = Serial.parseInt();
  Serial.print("READ INT ");
  Serial.println(mydelay, DEC);
  if (mydelay==0)
  {
     stopped = true;
     digitalWrite(pinpulseen, LOW);
  } else
  {
    stopped = false;
    digitalWrite(pinpulseen, HIGH);
  } 

Куда запоминать место нахождения в меню или лучше просто одному символу алфавита задать одно действие без перевода в число - решать Вам.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Messiah пишет:

Читать данные из порта в loop() это плохая идея. 

Да ну? А не подскажешь ли, откуда вызывается serialEvent, внутри которой ты пишешь свой код? Даю наколку: она вызывается прямо ну вот совсем рядышком с вызовом loop, и, ВНЕЗАПНО, перед её вызовом проверяется, есть ли что-то в приемном буфере соответствующего UART. Т.е. код, написанный внутри serialEvent, АНАЛОГИЧЕН коду ниже, размещённому в loop:

if(Serial.available()) 
{ 
/* тут делаем, что надо, в приемном буфере UART что-то есть, определённо.
код, размещённый здесь, работает так же, как код, написанный внутри serialEvent. */  
}

Прежде чем выносить сомнительные утверждения - очень советую ознакомиться с исходниками Wiring, тем более, что они совершенно открыты и есть у каждого, у кого установлена Arduino IDE ;)

Armata
Offline
Зарегистрирован: 04.03.2018

Всем спасибо,вчера разобрался,я пихал всё и сразу а нужно было по степенно,теперь ясно)
Особенно наглядно это демонстрирует логика написаная DIYMan за что ему ОГРОМНАЯ благодарность!