Управление сделал через энкодер, экран цветной 128*160 точек TFT_ILI9163C с кардридером для SD карт.
Делюсь тем что получилось.
Пока все на проводах: Слева на право: Arduino Pro Mini с моей прошивкой, Arduino Pro Mini с прошивкой GRBL, Энкодер, экран с SD картой.
Вид на экран сзади: После загрузки: Главное меню по кнопке энкодера: Меню ручного перемещения(MANUAL): Меню выбора файла(FILES): Экран исполнения выбранного файла: Экран настроек(SETUP): Немного видео исполнения файла(простите за вертикальное видео):
https://www.youtube.com/watch?v=T3A3izTTTrg
Пока все что успел накидать.
Еще по контроллеру - прошивка несмотря на мои утрамбовывания занимает 28 950 байт из 30 720 байт доступных - до бишь почти под завязку.
(Обшибся - на работе была старая версия: тот что ниже занимает 30 626 байт (99%) памяти устройства. Всего доступно 30 720 байт. )
Что есть в прошивке :
1. До вызова меню прошивка работает как обычный RS232 терминал и читает все что приходит на порт.
2. Пункт меню MANUAL - ручное перемещение по осям - работает так - выбираете энкодером ось - и крутите его вправо + влево - , чем дальше от центра шкалы тем больше подача,
при выходе за максимум подача сбрасывается до нуля для защиты, при нажатии на энкодер подача сбрасывается и вы возвращаетесь в выбор оси.
3. Пункт меню FILES - на экран выводятся все файлы которые есть на флешке без разбивки на каталоги. Энкодером выбираете нужный файл и попадаете в его выполнение - изначально выполнение на паузе.
тут 4 пункта - выполнение >, пошаговое выполнение |>, пауза || и стоп(выход). При выполнении автоматически контролируется максимальная подача (задается в настройках).
4. Пункт меню UNLOCK - разблокировка GRBL путем посылки $X.
5. Пункт меню SETUP - настройки контроллера: максимальная подача, автозапуск файла, остановка по ошибке, авторазблокировка.
6. Пункт меню RESTART GRBL - сброс GRBL путем подачи сигнала на ногу reset ведомого контроллера.
7. Пункт меню EXIT - возврат в режим терминала.
Исходники прошивки:
Код: Выделить всё
#include <avr/pgmspace.h>
#include <EEPROMex.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#define __160_RED_PCB__
#include <TFT_ILI9163C.h>
#include <SD.h>
// Color definitions
#define BLACK 0x0000
#define BLUE 0xF800
#define RED 0x001F
#define GREEN 0x07E0
#define CYAN 0xFFE0
#define MAGENTA 0xF81F
#define YELLOW 0x07FF
#define WHITE 0xFFFF
#define _cp437 false
#define __CS 6
#define __RST 7
#define __DC 8 //a0
#define __LED 9
#define MAX_DISPLAY_LINES 15
#define MAX_DISPLAY_FILES 14
#define __SDCS 10
#define MENU_DELAY 150
#define GRBL_RES_PIN 5
#define CHAR_HEIGHT 8
#define CHAR_WIDTH 6
#define CHAR_STOP 0x80 // 128 stop
#define CHAR_PLAY 0x81 // 129 play
#define CHAR_PAUSE 0x82 // 130 pause
#define CHAR_ARIGHT 0x83 // 131 ->
#define CHAR_ALEFT 0x84 // 132 <-
#define CHAR_AUP 0x85 // 133 up
#define CHAR_ADOWN 0x86 // 134 down
#define CHAR_MARK 0x87 // 135 mark
#define CHAR_STEP 0x88 // 136 step
#define CHAR_DRILL 0x89 // 137 drill
#define CHAR_ZLEFT 0x8A // 138 zero left
#define CHAR_ZRIGHT 0x8B // 139 zero right
#define CHAR_SLE 0x8C // 140 scale left empty
#define CHAR_SRE 0x8D // 141 scale right empty
#define CHAR_SCE 0x8E // 142 scale center empty
#define CHAR_SLF 0x8F // 143 scale left full
#define CHAR_SRF 0x90 // 144 scale right full
#define CHAR_SCF 0x91 // 145 scale center full
#define CHAR_EPLAY 0x92 // 146 play empty
#define EXEC_PAUSE 0x0 // sleep
#define EXEC_PLAY 0x1 // send commands without pause
#define EXEC_STEP 0x2 // execute step by step
#define EXEC_EXIT 0x20 // exit from execute
//#define CONFIG_MAX 30 //
#define EEPROM_FEED 0
#define EEPROM_START 8
#define EEPROM_PAUSE 9
#define EEPROM_UNLOCK 10
#define DEFAULT_FEED 1000
#define FEED_MAX 1250
TFT_ILI9163C tft = TFT_ILI9163C(__CS, __DC, __RST);
File root;
bool MENU_KEY, OK_KEY, UP_KEY, DOWN_KEY, LOOP_TEMP = false;
int8_t filecount, pp_menu, skip_page, skip, exec_mode, readcnt;
long current_line;
String fname;
char buff[80];
//String buff
long feed_dig = 0;
long feed_safe = 0;
const char acc0[] PROGMEM = "0 F0\0";
const char acc1[] PROGMEM = "0.01 F100\0";
const char acc2[] PROGMEM = "0.02 F100\0";
const char acc3[] PROGMEM = "0.03 F100\0";
const char acc4[] PROGMEM = "0.04 F100\0";
const char acc5[] PROGMEM = "0.05 F200\0";
const char acc6[] PROGMEM = "0.06 F200\0";
const char acc7[] PROGMEM = "0.07 F200\0";
const char acc8[] PROGMEM = "0.08 F200\0";
const char acc9[] PROGMEM = "0.09 F200\0";
const char acc10[] PROGMEM = "0.1 F400\0";
const char acc11[] PROGMEM = "0.2 F400\0";
const char acc12[] PROGMEM = "0.3 F400\0";
const char acc13[] PROGMEM = "0.4 F400\0";
const char acc14[] PROGMEM = "0.5 F400\0";
const char acc15[] PROGMEM = "1 F600\0";
const char acc16[] PROGMEM = "2 F600\0";
const char acc17[] PROGMEM = "3 F600\0";
const char acc18[] PROGMEM = "4 F600\0";
const char acc19[] PROGMEM = "5 F600\0";
const char acc20[] PROGMEM = "0 F1\0";
const char * const acc_table[] PROGMEM = {acc0, acc1, acc2, acc3, acc4, acc5, acc6, acc7, acc8, acc9, acc10, acc11, acc12, acc13, acc14, acc15, acc16, acc17, acc18, acc19, acc20 };
const char empty_line[] PROGMEM = " \n\0";
const char trail[] PROGMEM = " \0";
const char zero[] PROGMEM = " 0 \0";
const char init_error[] PROGMEM = "Init SD failed!\0";
const char text_manual[] PROGMEM = " MANUAL\0";
const char text_files[] PROGMEM = " FILES\0";
const char text_unlock[] PROGMEM = " UNLOCK\0";
const char text_setup[] PROGMEM = " SETUP\0";
const char text_reset[] PROGMEM = " RESET\0";
const char text_exit[] PROGMEM = " EXIT\0";
const char text_home[] PROGMEM = " HOME\0";
const char text_feedmax[] PROGMEM = " FEED Max(mm/min):\0";
const char text_autostart[] PROGMEM = " AUTO START:\0";
const char text_pauseerr[] PROGMEM = " PAUSE ON ERROR:\0";
const char text_autounlk[] PROGMEM = " AUTO UNLOCK:\0";
const char text_done[] PROGMEM = "DONE\0";
const char text_next[] PROGMEM = " >>>\0";
const char text_line[] PROGMEM = "Line:\0";
const char text_stepsize[] PROGMEM = " STEP SIZE:\0";
const char cmd_unlock[] PROGMEM = "$X\n\0";
//const char cmd_position[] PROGMEM = "?\n\0";
//const char cmd_cyclestart[] PROGMEM = "~\n\0";
//const char cmd_feedhold[] PROGMEM = "!\n\0";
const char cmd_reset[] PROGMEM = {0x18, '\n', '\0'};
const char cmd_upz[] PROGMEM = "G0Z10F500\0";
const char cmd_zeroxy[] PROGMEM = "G1X0Y0F500\0";
const char cmd_absolute[] PROGMEM = "G90\0";
const char cmd_incremental[] PROGMEM = "G91\0";
const char cmd_seek[] PROGMEM = "G0\0";
const char cmd_linear[] PROGMEM = "G1\0";
/*
const char cfg0[] PROGMEM = "$0=\0";
const char cfg1[] PROGMEM = "$1=\0";
const char cfg2[] PROGMEM = "$2=\0";
const char cfg3[] PROGMEM = "$3=\0";
const char cfg4[] PROGMEM = "$4=\0";
const char cfg5[] PROGMEM = "$5=\0";
const char cfg6[] PROGMEM = "$6=\0";
const char cfg7[] PROGMEM = "$10=\0";
const char cfg8[] PROGMEM = "$11=\0";
const char cfg9[] PROGMEM = "$12=\0";
const char cfg10[] PROGMEM = "$13=\0";
const char cfg11[] PROGMEM = "$20=\0";
const char cfg12[] PROGMEM = "$21=\0";
const char cfg13[] PROGMEM = "$22=\0";
const char cfg14[] PROGMEM = "$23=\0";
const char cfg15[] PROGMEM = "$24=\0";
const char cfg16[] PROGMEM = "$25=\0";
const char cfg17[] PROGMEM = "$26=\0";
const char cfg18[] PROGMEM = "$27=\0";
const char cfg19[] PROGMEM = "$100=\0";
const char cfg20[] PROGMEM = "$101=\0";
const char cfg21[] PROGMEM = "$102=\0";
const char cfg22[] PROGMEM = "$110=\0";
const char cfg23[] PROGMEM = "$111=\0";
const char cfg24[] PROGMEM = "$112=\0";
const char cfg25[] PROGMEM = "$120=\0";
const char cfg26[] PROGMEM = "$121=\0";
const char cfg27[] PROGMEM = "$122=\0";
const char cfg28[] PROGMEM = "$130=\0";
const char cfg29[] PROGMEM = "$131=\0";
const char cfg30[] PROGMEM = "$132=\0";
const char * const cfg_table[] PROGMEM = {cfg0, cfg1, cfg2, cfg3, cfg4, cfg5, cfg6, cfg7, cfg8, cfg9, cfg10, cfg11, cfg12, cfg13, cfg14, cfg15, cfg16, cfg17, cfg18, cfg19, cfg20, cfg21, cfg22, cfg23, cfg24, cfg25, cfg26, cfg27, cfg28, cfg29, cfg30};
*/
const char axis0[] PROGMEM = " X\0";
const char axis1[] PROGMEM = " Y\0";
const char axis2[] PROGMEM = " Z\0";
const char axis3[] PROGMEM = " F\0";
const char * const axis_label[] PROGMEM = {axis0, axis1, axis2, axis3};
/*
//joystick defines
#define joyPinX 1 // X pin
#define joyPinY 0 // Y pin
#define joyPinZ A3 // Z pin
int xmin = 000; // X minimum value
int xmax = 1024; // X maximum value
int ymin = 000; // Y minimum value
int ymax = 1024; // Y maximum value
int xzero = 0; // the first X value (don't touch the joystick at startup!)
int yzero = 0; // the first Y value
int segs = 10; // number of intervalls to consider par half direction
double zerohold = 4; // number of intervalls to consider as "zero position"
int x = 0;
int y = 0;
static boolean joyClick = false;
*/
//encoder defines
#define encoder0PinA 2
#define encoder0PinB 3
#define encoder0PinC 4
int8_t encoder0Pos = 1; // a counter for the dial
int8_t lastReportedPos = 1; // change management
static boolean rotating = false; // debounce management
// interrupt service routine vars
boolean A_set = false;
boolean B_set = false;
static boolean encClick = false;
//assistatnt procedures
void printSerialString(char *string) { //print to serial from progmem
while (pgm_read_byte(string) != '\0') {
Serial.write(pgm_read_byte_near(string));
string++;
}
}
void printTFTString(char *string) { //print to lcd from progmem
while (pgm_read_byte(string) != '\0') {
tft.write(pgm_read_byte_near(string));
string++;
}
}
void str_print(char s, byte size) //print to lcd cursor for menu choice
{
unsigned char x;
tft.setTextSize(size);
for (x = 0; x <= MAX_DISPLAY_LINES; x++) {
tft.setCursor(0, x * (size * CHAR_HEIGHT));
tft.write(32);
};
tft.setCursor(0, s * (size * CHAR_HEIGHT)); //MAX_DISPLAY_LINES
tft.setTextColor(YELLOW, BLACK);
tft.write(CHAR_PLAY);
tft.setTextColor(WHITE, BLACK);
tft.setTextSize(1);
}
void gauge(int8_t x, int8_t y, int8_t width, int8_t pos, int8_t scale) { //print gauge to display
tft.setCursor(x, y);
pos = pos / scale;
for (int8_t wdt = 0; wdt <= width; wdt++) {
int8_t center = (width / 2);
int8_t rpos = pos + center;
if (pos < (0 - center)) {
pos = 0 - center;
};
if (pos > center) {
pos = center;
};
if (rpos < 0) {
rpos = 0;
}
if (rpos > width) {
rpos = width;
}
if ((wdt == 0) && (rpos > 0)) {
tft.write(CHAR_SLE);
} else if ((wdt == 0) && (rpos == 0)) {
tft.write(CHAR_SLF);
} else if ((wdt == width) && (rpos < width)) {
tft.write(CHAR_SRE);
} else if ((wdt == width) && (rpos == width)) {
tft.write(CHAR_SRF);
} else if (wdt == center) {
tft.write(CHAR_SCF);
} else {
if (pos > 0) {
if (wdt < center) {
tft.write(CHAR_SCE);
} else if ((wdt > center) && (wdt <= rpos)) {
tft.write(CHAR_SCF);
} else if (wdt > rpos) {
tft.write(CHAR_SCE);
};
} else if (pos < 0) {
if (wdt > center) {
tft.write(CHAR_SCE);
} else if ((wdt < center) && (wdt >= rpos)) {
tft.write(CHAR_SCF);
} else if (wdt < rpos) {
tft.write(CHAR_SCE);
};
} else tft.write(CHAR_SCE);
}
}
}
//menu procedures
void main_screen(void) //
{
tft.setTextSize(2);
tft.setCursor(0, 0);
tft.setTextColor(WHITE, BLACK);
printTFTString((char*)text_manual);
tft.println();
printTFTString((char*)text_files);
tft.println();
printTFTString((char*)text_unlock);
tft.println();
printTFTString((char*)text_setup);
tft.println();
printTFTString((char*)text_reset);
tft.println();
printTFTString((char*)text_exit);
tft.setTextSize(1);
}
void main_menu(void) //
{
tft.clearScreen();
Serial.flush();
MENU_KEY = false;
main_screen();
pp_menu = 0;
lastReportedPos = encoder0Pos = 0;
str_print(pp_menu, 2);
do {
read_keys();
if (UP_KEY) {
if (pp_menu > 0) {
pp_menu--;
} else {
pp_menu = 5;
}
str_print(pp_menu, 2);
};
if (DOWN_KEY) {
if (pp_menu < 5) {
pp_menu++;
} else {
pp_menu = 0;
}
str_print(pp_menu, 2);
};
if (OK_KEY) {
if (pp_menu == 0) manual_menu();
if (pp_menu == 1) files_menu();
if (pp_menu == 2) {
current_line = 0;
printSerialString((char*)cmd_unlock);
break;
}
if (pp_menu == 3) {
setup_menu();
}
if (pp_menu == 4) {
//tft.clearScreen();
current_line = 0;
digitalWrite(GRBL_RES_PIN, HIGH);
delay(200);
digitalWrite(GRBL_RES_PIN, LOW);
break;
}
if (pp_menu == 5) {
Serial.flush();
break;
}
};
delay(MENU_DELAY);
} while (!MENU_KEY);
tft.clearScreen();
MENU_KEY = false;
current_line = 0;
};
void setup_screen(void) {
tft.setTextSize(1);
tft.setCursor(0, 0);
tft.setTextColor(WHITE, BLACK);
printTFTString((char*)text_feedmax);
tft.println(EEPROM.readInt(EEPROM_FEED));
printTFTString((char*)text_autostart);
tft.println(EEPROM.read(EEPROM_START));
printTFTString((char*)text_pauseerr);
tft.println(EEPROM.read(EEPROM_PAUSE));
printTFTString((char*)text_autounlk);
tft.println(EEPROM.read(EEPROM_UNLOCK));
printTFTString((char*)text_exit);
tft.setTextSize(1);
}
/*
#define CHAR_HEIGHT 8
#define CHAR_WIDTH 6
#define EEPROM_FEED 0
#define EEPROM_START 8
#define EEPROM_UNLOCK 9
*/
void setup_param(int8_t param) {
unsigned int temp, min, max = 0;
tft.setTextColor(GREEN, BLACK);
if (param == 0) {
temp = EEPROM.readInt(EEPROM_FEED);
min = 0; max = FEED_MAX;
} else if (param == 1) {
temp = EEPROM.read(EEPROM_START);
min = 0; max = 1;
} else if (param == 2) {
temp = EEPROM.read(EEPROM_PAUSE);
min = 0; max = 1;
} else if (param == 3) {
temp = EEPROM.read(EEPROM_UNLOCK);
min = 0; max = 1;
}
do {
if (param == 0) {
tft.setCursor(18 * CHAR_WIDTH, 0 * CHAR_HEIGHT);
} else if (param == 1) {
tft.setCursor(12 * CHAR_WIDTH, 1 * CHAR_HEIGHT);
} else if (param == 2) {
tft.setCursor(16 * CHAR_WIDTH, 2 * CHAR_HEIGHT);
} else if (param == 3) {
tft.setCursor(13 * CHAR_WIDTH, 3 * CHAR_HEIGHT);
}
tft.print(temp);
printTFTString((char*)trail);
printTFTString((char*)trail);
tft.println();
if (param == 0) {
if (encoder0Pos > 4)encoder0Pos = 4;
if (encoder0Pos < -4)encoder0Pos = -4;
if ((encoder0Pos > 1) || (encoder0Pos < 1)) {
temp += encoder0Pos * 5;
} else {
temp += encoder0Pos;
}
} else if (param == 1) {
if (encoder0Pos > 1)encoder0Pos = 1;
if (encoder0Pos < 0)encoder0Pos = 0;
temp = encoder0Pos;
} else if (param == 2) {
if (encoder0Pos > 1)encoder0Pos = 1;
if (encoder0Pos < 0)encoder0Pos = 0;
temp = encoder0Pos;
} else if (param == 3) {
if (encoder0Pos > 1)encoder0Pos = 1;
if (encoder0Pos < 0)encoder0Pos = 0;
temp = encoder0Pos;
}
delay(MENU_DELAY * 2);
encRead(); if (encClick) break;
} while (true);
if (param == 0) {
EEPROM.updateInt(EEPROM_FEED, temp);
} else if (param == 1) {
EEPROM.update(EEPROM_START, (byte)temp);
} else if (param == 2) {
EEPROM.update(EEPROM_PAUSE, (byte)temp);
} else if (param == 3) {
EEPROM.update(EEPROM_UNLOCK, (byte)temp);
}
}
void setup_menu(void) {
tft.clearScreen();
Serial.flush();
setup_screen();
pp_menu = 0;
lastReportedPos = encoder0Pos = 0;
str_print(pp_menu, 1);
do {
read_keys();
if (UP_KEY) {
if (pp_menu > 0) {
pp_menu--;
} else {
pp_menu = 4;
}
str_print(pp_menu, 1);
};
if (DOWN_KEY) {
if (pp_menu < 4) {
pp_menu++;
} else {
pp_menu = 0;
}
str_print(pp_menu, 1);
};
if (OK_KEY) {
if (pp_menu == 0) setup_param(0);
if (pp_menu == 1) setup_param(1);
if (pp_menu == 2) setup_param(2);
if (pp_menu == 3) setup_param(3);
if (pp_menu == 4) {
break;
}
setup_screen();
str_print(pp_menu, 1);
};
delay(MENU_DELAY);
} while (true);
tft.clearScreen();
main_screen();
pp_menu = 0;
str_print(pp_menu, 2);
}
void manual_screen() {
tft.setCursor(0, 0 * CHAR_HEIGHT);
tft.setTextColor(RED, BLACK);
printTFTString((char*)pgm_read_word(&(axis_label[0])));
gauge(12, 0 * CHAR_HEIGHT, 20, 0, 2);
printTFTString((char*)zero);
tft.setCursor(0, 1 * CHAR_HEIGHT);
tft.setTextColor(GREEN, BLACK);
printTFTString((char*)pgm_read_word(&(axis_label[1])));
gauge(12, 1 * CHAR_HEIGHT, 20, 0, 2);
printTFTString((char*)zero);
tft.setCursor(0, 2 * CHAR_HEIGHT);
tft.setTextColor(BLUE, BLACK);
printTFTString((char*)pgm_read_word(&(axis_label[2])));
gauge(12, 2 * CHAR_HEIGHT, 20, 0, 2);
printTFTString((char*)zero);
tft.setCursor(0, 3 * CHAR_HEIGHT);
tft.setTextColor(WHITE, BLACK);
printTFTString((char*)text_home);
tft.setCursor(0, 4 * CHAR_HEIGHT);
tft.setTextColor(WHITE, BLACK);
printTFTString((char*)text_reset);
tft.setCursor(0, 5 * CHAR_HEIGHT);
tft.setTextColor(WHITE, BLACK);
printTFTString((char*)text_exit);
}
void go_home(void){
printSerialString((char*)cmd_absolute);
Serial.write(0x0A);
printSerialString((char*)cmd_upz);
Serial.write(0x0A);
printSerialString((char*)cmd_zeroxy);
Serial.write(0x0A);
}
void move_menu(char axis) {
printSerialString((char*)cmd_incremental);
Serial.write(0x0A);
do {
tft.setCursor(0, axis * CHAR_HEIGHT);
if (axis == 0) {
tft.setTextColor(RED, BLACK);
} else if (axis == 1) {
tft.setTextColor(GREEN, BLACK);
} else if (axis == 2) {
tft.setTextColor(BLUE, BLACK);
}
printTFTString((char*)pgm_read_word(&(axis_label[axis])));
if (encoder0Pos > 20)encoder0Pos = 20;
if (encoder0Pos < -20)encoder0Pos = -20;
if (lastReportedPos > 20)lastReportedPos = 20;
if (lastReportedPos < -20)lastReportedPos = -20;
gauge(12, axis * CHAR_HEIGHT, 20, lastReportedPos, 2);
tft.setTextColor(YELLOW, BLACK);
printTFTString((char*)trail);
tft.print(abs(lastReportedPos));
printTFTString((char*)trail);
tft.setCursor(10, 50);
printTFTString((char*)text_stepsize);
if (lastReportedPos != 0) {
printSerialString((char*)cmd_linear);
printSerialString((char*)pgm_read_word(&(axis_label[axis])));
}
if (lastReportedPos < 0) {
tft.write(0x2D);
if (lastReportedPos != 0) Serial.write(0x2D);
}
if (lastReportedPos != 0) {
char pos = abs(lastReportedPos);
printSerialString((char*)pgm_read_word(&(acc_table[pos])));
Serial.write(0x0A);
printTFTString((char*)pgm_read_word(&(acc_table[pos])));
}
printTFTString((char*)empty_line);
if (lastReportedPos != 0) {
while (true) {
if (Serial.available()) break;
encRead(); if (encClick) break;
}
if (Serial.available()) {
memset(buff, 0, sizeof(buff));
readcnt = Serial.readBytesUntil(0x0A, buff, sizeof(buff));
if (readcnt > 0) {
for (int8_t pe = 0; pe < sizeof(buff); pe++) {
if ((buff[pe] == 0x0D) || (buff[pe] == 0x0A)) {
buff[pe] = 0x00;
break;
}
}
encRead(); if (encClick) break;
//if(Serial.peek()==0x0A) Serial.read();
//buff[readcnt] = 0;
//tft.setTextColor(YELLOW, BLACK);
/*if (strncmp(buff, "ok", 2)) {
tft.setTextColor(GREEN, BLACK);
tft.print(buff);
}*/
if (strncmp(buff, "error", 5) == 0) {
tft.setCursor(0, 60);
printTFTString((char*)empty_line);
tft.setCursor(0, 60);
tft.setTextColor(RED, BLACK);
tft.print(buff);
}
}
}
}
//delay(MENU_DELAY);
encRead(); if (encClick) break;
} while (true);
encClick = false;
encoder0Pos = lastReportedPos = 0;
delay(MENU_DELAY);
}
void manual_menu(void) {
tft.clearScreen();
Serial.flush();
manual_screen();
pp_menu = 0;
lastReportedPos = encoder0Pos = 0;
str_print(pp_menu, 1);
do {
read_keys();
if (UP_KEY) {
if (pp_menu > 0) {
pp_menu--;
} else {
pp_menu = 5;
}
str_print(pp_menu, 1);
};
if (DOWN_KEY) {
if (pp_menu < 5) {
pp_menu++;
} else {
pp_menu = 0;
}
str_print(pp_menu, 1);
};
if (OK_KEY) {
if (pp_menu == 0) {
move_menu(0);
delay(MENU_DELAY);
}
if (pp_menu == 1) {
move_menu(1);
delay(MENU_DELAY);
}
if (pp_menu == 2) {
move_menu(2);
delay(MENU_DELAY);
}
if (pp_menu == 3) {
go_home();
delay(MENU_DELAY);
}
if (pp_menu == 4) {
printSerialString((char*)cmd_reset);
Serial.write(0x0A);
delay(MENU_DELAY);
}
if (pp_menu == 5) break;
manual_screen();
str_print(pp_menu, 1);
};
delay(MENU_DELAY);
} while (true);
tft.clearScreen();
main_screen();
pp_menu = 0;
str_print(pp_menu, 2);
}
void exec_screen(void) {
tft.setTextSize(1);
tft.setCursor(0, 0);
tft.setTextColor(GREEN, BLACK);
printTFTString((char*)text_line);
tft.setCursor(30, 0);
tft.println(current_line);
tft.setTextColor(CYAN, BLACK);
tft.setCursor(70, 0 * CHAR_HEIGHT);
tft.write(0x46);
/*tft.setCursor(70, 0 * CHAR_HEIGHT);
tft.setTextColor(CYAN, BLACK);
tft.write(0x58);
tft.setCursor(110, 0 * CHAR_HEIGHT);
tft.setTextColor(MAGENTA, BLACK);
tft.write(0x59);
tft.setCursor(70, 1 * CHAR_HEIGHT);
tft.setTextColor(YELLOW, BLACK);
tft.write(0x5A);
tft.setCursor(110, 1 * CHAR_HEIGHT);
tft.setTextColor(WHITE, BLACK);
tft.write(0x46);*/
tft.setCursor(0, 0);
}
void buttons_screen(void) {
tft.setTextSize(1);
tft.setCursor(30, 0);
tft.setTextColor(GREEN, BLACK);
tft.println(current_line);
tft.setTextSize(2);
tft.setTextColor(GREEN, BLACK);
/*play button*/
tft.setCursor(0, 1 * CHAR_HEIGHT);//MAX_DISPLAY_LINES
if (exec_mode == EXEC_PAUSE) tft.setTextColor(BLUE, BLACK);
if (exec_mode == EXEC_PLAY) tft.setTextColor(RED, BLACK);
if (exec_mode == EXEC_STEP) tft.setTextColor(BLUE, BLACK);
if ((pp_menu == 0) && (skip_page > 2)) tft.setTextColor(YELLOW, BLACK);
tft.write(CHAR_PLAY);
/*step button*/
tft.setCursor(CHAR_WIDTH * 2, 1 * CHAR_HEIGHT);//MAX_DISPLAY_LINES
if (exec_mode == EXEC_PAUSE) tft.setTextColor(BLUE, BLACK);
if (exec_mode == EXEC_PLAY) tft.setTextColor(BLUE, BLACK);
if (exec_mode == EXEC_STEP) tft.setTextColor(RED, BLACK);
if ((pp_menu == 1) && (skip_page > 2)) tft.setTextColor(YELLOW, BLACK);
tft.write(CHAR_STEP);
/*pause button*/
tft.setCursor(CHAR_WIDTH * 4, 1 * CHAR_HEIGHT); //MAX_DISPLAY_LINES
if (exec_mode == EXEC_PAUSE) tft.setTextColor(RED, BLACK); else tft.setTextColor(BLUE, BLACK);
if (exec_mode == EXEC_PLAY) tft.setTextColor(BLUE, BLACK);
if (exec_mode == EXEC_STEP) tft.setTextColor(BLUE, BLACK);
if ((pp_menu == 2) && (skip_page > 2)) tft.setTextColor(YELLOW, BLACK);
tft.write(CHAR_PAUSE);
/*stop button*/
tft.setCursor(CHAR_WIDTH * 6, 1 * CHAR_HEIGHT); //MAX_DISPLAY_LINES
if (exec_mode == EXEC_PAUSE) tft.setTextColor(BLUE, BLACK);
if (exec_mode == EXEC_PLAY) tft.setTextColor(BLUE, BLACK);
if (exec_mode == EXEC_STEP) tft.setTextColor(BLUE, BLACK);
if ((pp_menu == 3) && (skip_page > 2)) tft.setTextColor(YELLOW, BLACK);
tft.write(CHAR_STOP);
}
/*
const char cmd_cyclestart[] PROGMEM = "~\0x0A\0";
const char cmd_feedhold[] PROGMEM = "!\0x0A\0";
*/
void process_keys(void) {
read_keys();
/* if (exec_mode == EXEC_PLAY) {
if (UP_KEY) {
if (execSpeed > 0) {
execSpeed = execSpeed - 10;
} else {
execSpeed = 100;
}
};
if (DOWN_KEY) {
if (execSpeed < 100 ) {
execSpeed = execSpeed + 10;
} else {
execSpeed = 0;
}
};
};*/
if ((exec_mode == EXEC_PLAY) && (OK_KEY == true)) {
exec_mode = EXEC_PAUSE;
}
if ((exec_mode == EXEC_PAUSE) || (exec_mode == EXEC_STEP)) {
skip_page = 0;
OK_KEY = false;
//if (current_line > 0) printSerialString((char*)cmd_feedhold);
do {
read_keys();
if (UP_KEY) {
if (pp_menu > 0) {
pp_menu--;
} else {
pp_menu = 3;
}
};
if (DOWN_KEY) {
if (pp_menu < 3) {
pp_menu++;
} else {
pp_menu = 0;
}
};
if (OK_KEY) {
OK_KEY = encClick = false;
break;
}
buttons_screen();
delay(MENU_DELAY);
skip_page++;
if (skip_page > 3)skip_page = 0;
} while (true);
if (pp_menu == 0) {
exec_mode = EXEC_PLAY;
/*if (current_line > 0) {
printSerialString((char*)cmd_cyclestart);
while (Serial.available() > 0) {
memset(buff, 0, sizeof(buff));
readcnt = Serial.readBytesUntil(0x0A, buff, sizeof(buff));
if (readcnt > 0) {
buff[readcnt] = 0;
if ((strncmp(buff, "ok", 2) == 0)) break;
}
}
}*/
}
if (pp_menu == 1) {
exec_mode = EXEC_STEP;
/*if (current_line > 0) {
/*printSerialString((char*)cmd_cyclestart);
while (Serial.available() > 0) {
memset(buff, 0, sizeof(buff));
readcnt = Serial.readBytesUntil(0x0A, buff, sizeof(buff));
if (readcnt > 0) {
buff[readcnt] = 0;
if ((strncmp(buff, "ok", 2) == 0)) break;
}
}
}*/
}
if (pp_menu == 2) exec_mode = EXEC_PAUSE;
if (pp_menu == 3) {
//printSerialString((char*)cmd_reset);
exec_mode = EXEC_EXIT;
}
delay(MENU_DELAY);
OK_KEY = encClick = false;
buttons_screen();
}
update_pos();
}
void update_pos(void) {
tft.setTextSize(1);
tft.setCursor(78, 0 * CHAR_HEIGHT);
tft.setTextColor(WHITE, BLACK);
tft.print(feed_dig);
printTFTString((char*)trail);
/* tft.print(execSpeed);
tft.print(F("% "));*/
}
void execute_file(String &fname) {
current_line = skip = skip_page = 0;
int8_t pos_start = 0;
int8_t pos_end = 0;
char feed[10];
char temp[40];
feed_dig = feed_safe;
if (EEPROM.read(EEPROM_START) == 1) {
exec_mode = EXEC_PLAY;
} else if (EEPROM.read(EEPROM_START) == 0) {
exec_mode = EXEC_PAUSE;
}
/*Serial.print(F("F"));
Serial.print(feed_dig);
Serial.write(0x0A);
while (Serial.available() > 0) {
Serial.readBytesUntil(0x0A, buff, sizeof(buff));
}
delay(100);*/
Serial.flush();
pp_menu = 0;
exec_screen();
buttons_screen();
process_keys();
File text = SD.open(fname, O_READ);
if (text) {
while (text.available()) {
process_keys();
if (exec_mode == EXEC_EXIT) {
text.close();
exit;
}
current_line++;
memset(buff, 0, sizeof(buff));
readcnt = text.readBytesUntil(0x0A, buff, sizeof(buff));
if (readcnt > 0) {
buff[readcnt] = 0;
pos_start = 0;
for (int8_t pe = 0; pe < sizeof(buff); pe++) {
if ((buff[pe] == 0x46)) {
pos_start = pe;
break;
}
}
if (pos_start > 0) {
for (int8_t pe = pos_start + 1; pe < sizeof(buff); pe++) {
if ((buff[pe] > 0x39) || (buff[pe] == 0)) {
pos_end = pe;
break;
}
}
strncpy(feed, buff + pos_start + 1, pos_end - pos_start);
feed_dig = strtol(feed, 0, 0);
if (feed_dig > feed_safe) feed_dig = feed_safe;
//feed_dig = (feed_dig * execSpeed) / 100;
ltoa(feed_dig, feed, 10);
for (int8_t pe = 0; pe < 10; pe++) {
if (feed[pe] == 0) {
pos_end = pe - 1;
break;
}
}
strncpy(buff + pos_start + 1, feed, pos_end);
}
for (int8_t pe = 0; pe < sizeof(buff); pe++) {
/*if ((buff[pe]>0x00)&&((buff[pe]!=0x0D)||(buff[pe]!=0x0A))){
if (((buff[pe]<0x20)||(buff[pe]>0x5A))) buff[pe]=0x20;
}*/
if (buff[pe] == 0x0D) {
buff[pe] = 0x0A;
buff[pe + 1] = 0x00;
break;
}
if (buff[pe] == 0x0A) {
buff[pe + 1] = 0x00;
break;
}
}
Serial.print(buff);
Serial.flush();
memset(temp, 0, sizeof(temp));
strncpy(temp, buff, sizeof(temp));
for (int8_t pe = 0; pe < sizeof(temp); pe++) {
if ((temp[pe] == 0x0D) || (temp[pe] == 0x0A)) {
temp[pe] = 0x00;
break;
}
}
if (exec_mode == EXEC_STEP) {
tft.setTextSize(1);
tft.setCursor(0, (skip + 3)* CHAR_HEIGHT);
printTFTString((char*)empty_line); tft.println();
printTFTString((char*)empty_line); tft.println();
//tft.println(F(" "));
//tft.println(F(" "));
/*tft.setCursor(0, (skip + 4)* CHAR_HEIGHT);
tft.println(F(" "));*/
tft.setCursor(0, (skip + 3)* CHAR_HEIGHT);
tft.setTextColor(YELLOW, BLACK);
//tft.print(F("-"));
tft.print(buff);
skip++;
}
Serial.flush();
}
while (Serial.available() == 0) {
encRead(); if ((encClick) && (exec_mode == EXEC_PLAY)) {
pp_menu = 2;
exec_mode = EXEC_PAUSE;
process_keys();
}
if (exec_mode == EXEC_EXIT) break;
//if (Serial.available() > 0) break;
}
while (Serial.available() > 0) {
memset(buff, 0, sizeof(buff));
readcnt = Serial.readBytesUntil(0x0A, buff, sizeof(buff));
if (readcnt > 0) {
buff[readcnt] = 0;
if (strncmp(buff, "error", 5) == 0) {
delay(10);
Serial.flush();
tft.setTextSize(1);
tft.setCursor(0, (skip + 3)* CHAR_HEIGHT);
printTFTString((char*)empty_line); //tft.println();
printTFTString((char*)empty_line); //tft.println();
printTFTString((char*)empty_line); //tft.println();
//tft.println(F(" "));
//tft.println(F(" "));
tft.setCursor(0, (skip + 3)* CHAR_HEIGHT);
tft.setTextColor(RED, BLACK);
tft.print(current_line);
printTFTString((char*)trail);
tft.println(temp);
tft.print(buff);
memset(temp, 0, sizeof(temp));
if (EEPROM.read(EEPROM_PAUSE) == 1) exec_mode = EXEC_PAUSE;
skip++;
//break;
}
/*if (exec_mode == EXEC_STEP) {
skip++;
}*/
if ((strncmp(buff, "ok", 2) == 0)) {
//tft.setTextColor(GREEN, BLACK);
//(Serial.available()==0)
delay(10);
Serial.flush();
//break;
}
}
encRead();
if ((encClick) && (exec_mode == EXEC_PLAY)) {
pp_menu = 2;
exec_mode = EXEC_PAUSE;
OK_KEY = encClick = false;
process_keys();
}
//if (Serial.available()==0)break;
if (exec_mode == EXEC_EXIT) break;
}
/*if (skip_page == 0) {
Serial.print(F("?"));
Serial.write(0x0A);
memset(buff, 0, sizeof(buff));
while (Serial.available() > 0) {
readcnt = Serial.readBytesUntil(0x0A, buff, sizeof(buff));
if (readcnt > 0) {
buff[readcnt] = 0;
tft.setCursor(0, 3 * CHAR_HEIGHT);
tft.println(buff);
}
}
}*/
//skip++;
//skip_page++;
exec_screen();
if (skip > (MAX_DISPLAY_LINES - 5))skip = 0;
//if (skip_page > 10)skip_page = 0;
}
}
text.close();
}
boolean init_card(void) {
if (root) root.close();
if (!SD.begin(__SDCS)) {
printTFTString((char*)init_error);
digitalWrite(__SDCS, LOW);
delay(MENU_DELAY * 4);
digitalWrite(__SDCS, HIGH);
tft.clearScreen();
return false;
}
root = SD.open("/");
if (!root) {
printTFTString((char*)init_error);
delay(MENU_DELAY * 4);
tft.clearScreen();
return false;
}
root.rewindDirectory();
tft.clearScreen();
return true;
}
void printDirectory(File dir, String &file, bool getfile) {
while (filecount < MAX_DISPLAY_FILES) {
File entry = dir.openNextFile(O_READ);
if (!entry) {
entry.close();
break;
}
if (entry.isDirectory()) {
printDirectory(entry, file, getfile);
} else {
if ((getfile) && (skip == 0)) {
file = entry.name();
break;
}
if (skip == 0) {
filecount++;
printTFTString((char*)trail);
tft.print(entry.name());
tft.println();
};
if (skip > 0) skip--;
}
entry.close();
}
}
void list(void) {
skip = skip_page * MAX_DISPLAY_FILES;
tft.clearScreen();
tft.setCursor(0, 0);
filecount = 0;
root.rewindDirectory();
printDirectory(root, fname, false);
tft.setTextColor(GREEN, BLACK);
if (filecount == MAX_DISPLAY_FILES) {
printTFTString((char*)text_next);
} else {
printTFTString((char*)text_exit);
}
tft.setTextColor(WHITE, BLACK);
pp_menu = 0;
str_print(pp_menu, 1);
}
void files_menu(void) {
skip_page = skip = 0;
if (init_card()) {
list();
} else {
MENU_KEY = true;
}
do {
read_keys();
if (UP_KEY) {
if (pp_menu > 0) {
pp_menu--;
} else {
pp_menu = filecount;
}
str_print(pp_menu, 1);
};
if (DOWN_KEY) {
if (pp_menu < filecount) {
pp_menu++;
} else {
pp_menu = 0;
}
str_print(pp_menu, 1);
};
if (OK_KEY) {
if (pp_menu < filecount) {
root.rewindDirectory();
skip = (skip_page * MAX_DISPLAY_FILES) + pp_menu;
filecount = 0;
fname = "";
printDirectory(root, fname, true);
tft.clearScreen();
tft.setCursor(0, 0);
execute_file(fname);
tft.clearScreen();
go_home();
tft.setTextSize(5);
do {
encRead();
tft.setCursor(22, 45);
tft.setTextColor(GREEN, BLACK);
printTFTString((char*)text_done);
} while (!encClick);
tft.setTextSize(0);
break;
}
if ((filecount == MAX_DISPLAY_FILES) && (pp_menu == filecount)) {
skip_page++;
} else {
break;
}
list();
};
delay(MENU_DELAY);
} while (!MENU_KEY);
tft.clearScreen();
filecount = skip_page = skip = 0;
main_screen();
pp_menu = 1;
str_print(pp_menu, 2);
};
void rotEncoder() {
rotating = true;
}
void setup() {
Serial.begin(115200);
Serial.setTimeout(1);
while (!Serial) {
}
EEPROM.setMaxAllowedWrites(2048);
pinMode(__SDCS, OUTPUT);
digitalWrite(__SDCS, HIGH);
pinMode(__LED, OUTPUT);
digitalWrite(__LED, HIGH);
tft.begin();
//tft.colorSpace(1);
tft.setRotation(1);
tft.fillScreen(BLACK);
tft.setTextWrap(false);
tft.setTextColor(WHITE, BLACK);
tft.setCursor(0, 0);
/*
yzero = analogRead(joyPinY);
xzero = analogRead(joyPinX);
pinMode(joyPinZ, INPUT_PULLUP);
*/
pinMode(encoder0PinA, INPUT);
digitalWrite(encoder0PinA, HIGH); // подключить подтягивающий резистор
pinMode(encoder0PinB, INPUT);
digitalWrite(encoder0PinB, HIGH); // подключить подтягивающий резистор
pinMode(encoder0PinC, INPUT_PULLUP);
attachInterrupt(0, doEncoderA, CHANGE); // настроить прерывание interrupt 0 на pin 2
attachInterrupt(1, doEncoderB, CHANGE); // настроить прерывание interrupt 0 на pin 3
lastReportedPos = encoder0Pos = 0;
// The internal 1.1V reference provides for better
// resolution from the LM35, and is also more stable
// when powered from either a battery or USB...
//analogReference(INTERNAL);
pinMode(GRBL_RES_PIN, OUTPUT);
digitalWrite(GRBL_RES_PIN, HIGH);
delay(200);
digitalWrite(GRBL_RES_PIN, LOW);
//tft.defineScrollArea(8,152);
current_line = skip = 0;
tft.setTextColor(GREEN, BLACK);
feed_safe = EEPROM.readInt(EEPROM_FEED);
if (feed_safe > FEED_MAX) {
feed_safe = FEED_MAX;
EEPROM.updateInt(EEPROM_FEED, FEED_MAX);
}
}
/*
void joy_read() {
joyClick = (digitalRead(joyPinZ) == HIGH ? false : true);
int value = 0; // variable to hold the actual reading
value = analogRead(joyPinX);
// push limits
if (value < xmin) xmin = value;
else if (value > xmax) xmax = value;
// start at zero
x = 0;
// divide lower half
int seg = (xzero - xmin) / (segs + zerohold);
// find what segment we are in
for (int i = 0; i < segs + 1; i++)
{
if (value >= xzero - ((segs - i) + zerohold)*seg) x = i;
}
// devide upper part
seg = (xmax - xzero) / (segs + zerohold);
// find what segment we are in
for (int i = segs + 1; i < 2 * segs + 1; i++)
{
if (value >= xzero + ((i - segs - 1) + zerohold)*seg) x = i;
}
// make X range from [-10,10] instead of [0,20]
x -= segs;
// invert X
x = -x;
//delay (10);
// the same as before but with "Y" :-)
value = analogRead(joyPinY);
if (value < ymin) ymin = value;
else if (value > ymax) ymax = value;
y = 0;
seg = (yzero - ymin) / (segs + 1);
for (int i = 0; i < segs + 1; i++)
{
if (value >= yzero - ((segs - i) + 1)*seg) y = i;
}
seg = (ymax - yzero) / (segs + zerohold);
for (int i = segs + 1; i < 2 * segs + 1; i++)
{
if (value >= yzero + ((i - segs - 1) + zerohold)*seg) y = i;
}
y -= segs;
}
*/
void doEncoderA() {
// debounce
if ( rotating ) delay (1); // wait a little until the bouncing is done
// Test transition, did things really change?
if ( digitalRead(encoder0PinA) != A_set ) { // debounce once more
A_set = !A_set;
// adjust counter + if A leads B
if ( A_set && !B_set ) encoder0Pos++;
//if (encoder0Pos > encoder0Max) encoder0Pos = encoder0Min+1;
rotating = false; // no more debouncing until loop() hits again
}
}
// Interrupt on B changing state
void doEncoderB() {
if ( rotating ) delay (1);
if ( digitalRead(encoder0PinB) != B_set ) {
B_set = !B_set;
// adjust counter - 1 if B leads A
if ( B_set && !A_set ) encoder0Pos --;
//if (encoder0Pos<=encoder0Min) encoder0Pos = encoder0Max;
rotating = false;
}
}
void encRead() {
encClick = (digitalRead(encoder0PinC) == HIGH ? false : true);
if (encoder0Pos != lastReportedPos) lastReportedPos = encoder0Pos;
}
void read_keys(void) {
if (encoder0Pos == 0) {
UP_KEY = false;
DOWN_KEY = false;
}
encRead();
OK_KEY = encClick;
if (encoder0Pos > 0) {
DOWN_KEY = true;
encoder0Pos = lastReportedPos = 0;
} else if (encoder0Pos < 0) {
UP_KEY = true;
encoder0Pos = lastReportedPos = 0;
}
}
void loop() {
if (Serial.available()) {
memset(buff, 0, sizeof(buff));
readcnt = Serial.readBytesUntil(0x0A, buff, sizeof(buff));
if (readcnt > 0) {
buff[readcnt] = 0;
//tft.setCursor(0, (MAX_DISPLAY_LINES+current_line) * CHAR_HEIGHT);
tft.setTextColor(YELLOW, BLACK);
tft.setCursor(0, current_line * CHAR_HEIGHT);
printTFTString((char*)empty_line); tft.println();
//tft.println(F(" "));
tft.setCursor(0, current_line * CHAR_HEIGHT);
if (strncmp(buff, "ok", 2) == 0) {
tft.setTextColor(GREEN, BLACK);
}
if (strncmp(buff, "error", 5) == 0) {
tft.setTextColor(RED, BLACK);
}
tft.println(buff);
current_line++;
if (current_line > MAX_DISPLAY_LINES)current_line = 0;
Serial.flush();
if ((strncmp(buff, "['$", 3) == 0) && (EEPROM.read(EEPROM_UNLOCK) == 1)) {
printSerialString((char*)cmd_unlock);
delay(10);
}
}
}
encRead();
if (encClick) main_menu();
}
Обновил архив проекта.
Изменения:
В меню MANUAL добавилось два пункта:
HOME - идем "домой" по абсолютным координатам X0 Y0 Z10
RESET - софт сброс GRBL
В главном меню RESET - так и остался железным сбросом ардуины с GRBL
После завершения выполнения программы идем "домой" по абсолютным координатам X0 Y0 Z10
27.02.2017
Обновление проекта - собрал все в кучу
Архив с исходниками и библиотеками: [/b]
Для изменения ориентации экрана в прошивку ST7735 добавил константу:
Код: Выделить всё
/*-----------------*/
#define DISPLAY_ROT 1 // display rotation - 1 - SD slot down, 3 - SD slot up
/*-----------------*/