#include <SD.h>
#include <Stepper.h>
#include "button.h"
#define CSPin 10 //управляющий контакт для SD карты
#define pin_start_btn 5 //контакт кнопки старта алгоритма с карты
#define pin_alarm_stop_btn 2 //контакт кнопки аварийной остановки
const int stepsPerRevolution = 200; //количество шагов на оборот
const int motor_speed = 200;
const char* file_name = "move.txt";
bool in_action = false; //флаг - двигатель в процессе работы
unsigned int line_num = 0; //номер строки работы дв игателя
unsigned int steps_num = 0; //количество шагов
int8_t steps_direction = 1; //направление
unsigned int steps_delay = 0; //пауза после выполнения
File move_file;
File root;
Button btn_start(pin_start_btn); //кнопка старт
Stepper myStepper(stepsPerRevolution, 6, 7, 8, 9); //управление выводами 8 - 11
void setup()
{
Serial.begin(115200);
Serial.print("Initializing SD card... ");
if (!SD.begin(CSPin)) //Если ошибка инициализации, то блокирование работы
{
Serial.println("Card initialization failed!");
while (1);
}
Serial.println("initialization done.");
Serial.println("Files in the card:"); //считывание имен всех файлов на карте
root = SD.open("/");
printDirectory(root); //вывод всех имен файлов в директории
Serial.println("");
pinMode(pin_alarm_stop_btn, INPUT_PULLUP); // подтягивающий резистор на входе прерывания
attachInterrupt(0, alarm_stop, FALLING); //разрешение внешнего прерывания (вывод 2 Arduino UNO)
}
void loop()
{
check_start_button();
step_algorithm(); //выполнить следующий шаг алгоритма (строка с заданием на перемещение)
}
//функция чтения имен файлов
void printDirectory(File dir)
{
while (1)
{
File entry = dir.openNextFile(); //переход к следующему файлу
if (! entry) //выход, если больше нет файлов
{
break;
}
Serial.print(entry.name()); //вывод имени
if (entry.isDirectory()) //если это директория, то ее размера нет
{
Serial.println("/");
} else
{
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
//проверка нажатия кнопки - если нажата и двигатель не в процессе работы - начать работу
void check_start_button()
{
if (btn_start.readButton() && (!in_action))
{
start_algorithm();
}
}
//начать работу двигателя
void start_algorithm()
{
Serial.println("start move");
//много ли времени занимает процесс считывания с карты?
//с точки зрение скорости работы - лучше считать все данные сразу в промежуточный буфер и забирать данные уже из буфера?
// или можно считывать последовательно по одной строке с карты?
//пока оставлю последовательное считывание по одной строке
//открыть файл для чтения
move_file = SD.open(file_name); //открыть файл с алгоритмом работы
if (!move_file) //если файл не открыт
{
Serial.println("file open error!");
return;
}
in_action = true;
line_num = 0;
}
void step_algorithm() //выполнить следующий шаг алгоритм (строка с заданием на перемещение)
{
if (!in_action) {return;}//если не был дан старт выполнения алгоритма работы - выход
Serial.print("start line = ");
Serial.println(line_num);
bool last;
if (!read_next_string(last))
{
Serial.print("Error in the file - line ");
Serial.println(line_num);
stop_algorith();
return;
};
move_string(); //выполнить следующую строку алгоритма движения
if (last)
{
stop_algorith();
Serial.println("last string");
}
}
//считать следующую строку алгоритма движения
bool read_next_string(bool& last)
{
//считать количество шагов
steps_num = 0; //количество шагов
String inString = "0";
char temp_char = 1;
while (move_file.available() && (temp_char >0))
{
temp_char = move_file.read();
if (isDigit(temp_char))
{
inString += temp_char;
}
else
{
if ((temp_char == ' ') || (temp_char == '\t')) //пробел или табуляция - конец ввода количества шагов
{
steps_num = inString.toInt();
temp_char = 0;
}
else //любые другие символы недопустимы
{
return false;
}
}
}
//считать направление
steps_direction = 0; //направление
temp_char = move_file.read();
if (temp_char == '0')
{
steps_direction = 1;
}
else if (temp_char == '1')
{
steps_direction = -1;
}
else //любые другие символы на этом месте недопустимы
{
return false;
}
//считать следующий разделительный знак - пробел или табуляция
temp_char = move_file.read();
if (!((temp_char == ' ') || (temp_char == '\t'))) //пробел или табуляция
{
return false;
}
//считать величину задержки
steps_delay = 0; //пауза
inString = "0";
temp_char = 1;
while (move_file.available() && (temp_char >0))
{
temp_char = move_file.read();
if (isDigit(temp_char))
{
inString += temp_char;
}
else
{
if (temp_char == '\r') //знак перевода строки - конец ввода паузы
{
steps_delay = inString.toInt();
temp_char = move_file.read();
if (temp_char != '\n')
{
return false;
}
temp_char = 0;
}
else //любые другие символы недопустимы
{
return false;
}
}
}
//флаг конца файла
last = !move_file.available();
return true;
}
void move_string() //выполнить следующую строку алгоритма движения
{
Serial.print("Move next line ");
Serial.println(line_num);
Serial.print("steps num = ");
Serial.println(steps_num);
Serial.print("steps dir = ");
Serial.println(steps_direction);
Serial.print("steps delay = ");
Serial.println(steps_delay);
myStepper.setSpeed(motor_speed); //установка нового значения скорости
//раздробить перемещение, чтобы иметь возможность в любой момент остановить двигатель
for (int i = 0; i < steps_num; ++i)
{
myStepper.step(steps_direction * 1); // выполнить заданное перемещение
}
for (int i = 0; i < steps_delay; ++i)
{
delay(1);
}
//delay(steps_delay);
line_num++;
}
void alarm_stop()
{
Serial.println("alarm stop");
stop_algorith();
}
void stop_algorith()
{
steps_num = 0; //количество шагов
steps_delay = 0; //пауза после выполнения
in_action = false;
move_file.close();
}