La seconda parte del CtrlJ pen sketch continua dal precedente articolo in cui hai letto la descrizione dello sketch fino alla funziona setup()
in questo articolo andrai avanti leggendo la definizione delle funzioni successive e le logiche di funzionamento della CtrlJ pen.
Il video del menu di configurazione
inizia dal video in cui si vede come si alternano i menu in fase di configurazione:
così da capire come orientarti tra le differenti schermate del menu.
Lo sketch
Lo sketch che puoi leggere è completo, come nel precedente articolo, anche se la descrizione parte dalla linea 071:
#include <Arduino.h> #include <U8g2lib.h> #ifdef U8X8_HAVE_HW_SPI #include <SPI.h> #endif #ifdef U8X8_HAVE_HW_I2C #include <Wire.h> #endif #define Bt1 MISO //11 #define Bt2 MOSI //12 #define Bt3 SCK //13 #define A 14 #define B 9 #define C 10 #define D 11 int TOTAL_OF_STEPS_PER_REV=512; int NUMBER_OF_STEPS_PER_REV=512; int NUMBER_OF_STEPS_PER_PRESS=256; int MICROSECOND_STEP_DELAY=1000; int OLD_MICROSECOND_STEP_DELAY=MICROSECOND_STEP_DELAY; int TOTAL_STEPS=55; int STEPS_EXECUTED=0; boolean arrowPos = false; // Button Press Count unsigned long keyPrevMillis = 0; const unsigned long keySampleIntervalMs = 25000; byte longKeyPressCountMax = 6; byte longKeyPressCount = 0; byte prevKeyState = HIGH; // button is active low // Mode byte mode = 0; // 0 - normal; 1 - menu boolean isFirstPage = true; U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // Adafruit Feather ESP8266/32u4 Boards + FeatherWing OLED void u8g2_prepare(void) { u8g2.setFont(u8g2_font_6x10_tf); u8g2.setFontRefHeightExtendedText(); u8g2.setDrawColor(1); u8g2.setFontPosTop(); u8g2.setFontDirection(0); } void setup() { Serial.begin(15200); pinMode(Bt1,INPUT_PULLUP); pinMode(Bt2,INPUT_PULLUP); pinMode(Bt3,INPUT_PULLUP); pinMode(A,OUTPUT); pinMode(B,OUTPUT); pinMode(C,OUTPUT); pinMode(D,OUTPUT); u8g2.begin(); u8g2.clearBuffer(); u8g2_prepare(); homePage(); u8g2.sendBuffer(); delay(500); } void loop() { draw(); Serial.print( digitalRead(Bt1) ); Serial.print("\t"); Serial.print( digitalRead(Bt2) ); Serial.print("\t"); Serial.print( digitalRead(Bt3) ); Serial.print("\n"); // Settings button pressed if (millis() - keyPrevMillis >= keySampleIntervalMs) { keyPrevMillis = millis(); byte currKeyState = digitalRead(Bt3); if ((prevKeyState == HIGH) && (currKeyState == LOW)) { keyPress(); } else if ((prevKeyState == LOW) && (currKeyState == HIGH)) { keyRelease(); } else if (currKeyState == LOW) { longKeyPressCount++; } prevKeyState = currKeyState; } } void shortKeyPress() { Serial.println("short"); if ( isFirstPage ) { OLD_MICROSECOND_STEP_DELAY=MICROSECOND_STEP_DELAY; MICROSECOND_STEP_DELAY=900; int i=0; while (i<NUMBER_OF_STEPS_PER_REV*10) { if ( digitalRead(Bt3) == LOW ) { break; }; backwardStep(); i++; } STEPS_EXECUTED -= (NUMBER_OF_STEPS_PER_REV/(NUMBER_OF_STEPS_PER_PRESS-i)); MICROSECOND_STEP_DELAY=OLD_MICROSECOND_STEP_DELAY; } } void longKeyPress() { Serial.println("long"); mode=1; } void keyPress() { Serial.println("key press"); longKeyPressCount = 0; } void keyRelease() { Serial.println("key release"); if (longKeyPressCount >= longKeyPressCountMax) { longKeyPress(); } else { shortKeyPress();} } void draw(void) { u8g2.clearBuffer(); u8g2_prepare(); switch (mode) { case 0: fPage(); break; case 1: m1Page(); break; case 2: m2Page(); break; case 3: m3Page(); break; } u8g2.sendBuffer(); delay(200); } void homePage() { u8g2.setFont(u8g2_font_9x15_tf); u8g2.drawStr( 0, 0, "Solder paste"); u8g2.drawStr( 0, 20, "dispenser v1"); } void fPage() { isFirstPage=true; char str[30]; int i=0; sprintf(str, "Steps for rev.: %d", NUMBER_OF_STEPS_PER_REV); u8g2.drawStr( 0, 0, str); u8g2.drawFrame(0,12,110,7); u8g2.drawBox((STEPS_EXECUTED*(110/TOTAL_STEPS)),12,110-(STEPS_EXECUTED*(110/TOTAL_STEPS)),7); u8g2.drawStr( 0, 24, "Settings: "); u8g2.drawFrame(58,28,15,4); u8g2.drawFrame(84,28,15,4); u8g2.drawFrame(113,28,15,4); u8g2.drawBox(62,21,7,8); u8g2.drawBox(88,21,7,8); u8g2.drawBox(117,24,7,5); if ( digitalRead(Bt1) == LOW ) { while (i<NUMBER_OF_STEPS_PER_PRESS) { if ( digitalRead(Bt3) == LOW ) { break; }; forwardStep(); i++; } STEPS_EXECUTED += (NUMBER_OF_STEPS_PER_REV/(NUMBER_OF_STEPS_PER_PRESS-i)); } if ( digitalRead(Bt2) == LOW ) { while (i<NUMBER_OF_STEPS_PER_PRESS) { if ( digitalRead(Bt3) == LOW ) { break; }; backwardStep(); i++; } STEPS_EXECUTED -= (NUMBER_OF_STEPS_PER_REV/(NUMBER_OF_STEPS_PER_PRESS-i)); } if (STEPS_EXECUTED > TOTAL_STEPS || STEPS_EXECUTED < 0) STEPS_EXECUTED=0; arrowPos=!arrowPos; if (arrowPos) { /* Up */ u8g2.drawBox(120,9,2,6); u8g2.drawTriangle(118,15,124,15,121,18); } else { /* Down */ u8g2.drawBox(120,12,2,6); u8g2.drawTriangle(118,18,124,18,121,21); } } void menuButton() { u8g2.drawStr( 0, 12, "Down"); u8g2.drawStr( 32, 12, "Up"); u8g2.drawStr( 54, 12, "Confirm"); u8g2.drawFrame( 4,28,15,4); u8g2.drawFrame(30,28,15,4); u8g2.drawFrame(72,28,15,4); u8g2.drawBox( 8,21,7,8); u8g2.drawBox(34,21,7,8); u8g2.drawBox(76,24,7,5); } void m1Page() { isFirstPage=false; char str[30]; sprintf(str, "Steps per rev.: %d", NUMBER_OF_STEPS_PER_REV); u8g2.drawStr( 0, 0, str); menuButton(); if ( (digitalRead(Bt1) == LOW ) && NUMBER_OF_STEPS_PER_REV < TOTAL_OF_STEPS_PER_REV) NUMBER_OF_STEPS_PER_REV += 10; if ( (digitalRead(Bt2) == LOW ) && NUMBER_OF_STEPS_PER_REV > 0 ) NUMBER_OF_STEPS_PER_REV--; if ( digitalRead(Bt3) == LOW ) mode = 2; } void m2Page() { isFirstPage=false; char str[30]; sprintf(str, "Steps per press: %d", NUMBER_OF_STEPS_PER_PRESS); u8g2.drawStr( 0, 0, str); menuButton(); if ( (digitalRead(Bt1) == LOW ) && NUMBER_OF_STEPS_PER_PRESS < NUMBER_OF_STEPS_PER_REV) NUMBER_OF_STEPS_PER_PRESS += 10; if ( (digitalRead(Bt2) == LOW ) && NUMBER_OF_STEPS_PER_PRESS > 0 ) NUMBER_OF_STEPS_PER_PRESS--; if ( digitalRead(Bt3) == LOW ) mode = 3; } void m3Page() { isFirstPage=false; char str[30]; sprintf(str, "Delay per fases: %d", MICROSECOND_STEP_DELAY); u8g2.drawStr( 0, 0, str); menuButton(); if ( (digitalRead(Bt1) == LOW ) && MICROSECOND_STEP_DELAY < 3000) MICROSECOND_STEP_DELAY += 10; if ( (digitalRead(Bt2) == LOW ) && MICROSECOND_STEP_DELAY > 0 ) MICROSECOND_STEP_DELAY--; if ( digitalRead(Bt3) == LOW ) mode = 0; } void forwardStep(){ Serial.println( "forwardStep" ); write(1,0,0,1); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,0,0,1); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,0,1,1); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,0,1,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,1,1,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,1,0,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(1,1,0,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(1,0,0,0); delayMicroseconds(MICROSECOND_STEP_DELAY); } void backwardStep(){ Serial.println( "backwardStep" ); write(1,0,0,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(1,1,0,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,1,0,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,1,1,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,0,1,0); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,0,1,1); delayMicroseconds(MICROSECOND_STEP_DELAY); write(0,0,0,1); delayMicroseconds(MICROSECOND_STEP_DELAY); write(1,0,0,1); delayMicroseconds(MICROSECOND_STEP_DELAY); } void write(int a,int b,int c,int d){ digitalWrite(A,a); digitalWrite(B,b); digitalWrite(C,c); digitalWrite(D,d); }
partiamo subito dalla funzione loop() la cui prima linea 072: richiama la funzione draw() che ti serve per visualizzare le informazioni sul display;
linee 074-079: scrivi sulla seriale il valore letto, in modalità digitale, dei tre pulsanti;
le linee 082-091: servono a controllare la pressione del terzo pulsante e discriminare per quanto tempo viene premuto.
Se tieni premuto il pulsante per oltre 2,5 secondi entri nella modalità menu;
Osservando nel dettaglio il codice di queste linee vedrai che le prime due linee 083-084 servono a memorizzare il valore di millis() attuale e lo stato di pressione del pulsante;
alla linea 086: verifichi se c’è stato un cambio di stato nella pressione del pulsante da HIGH a LOW ed in tal caso richiami la funzione keyPress();
la linea 087: se il cambio di stato passa da LOW a HIGH richiami la funzione keyRelease;
linea 088: se il valore del pulsante è semplicemente LOW, e non c’è cambio di stato, incrementi il valore di longKeyPressCount;
le righe del blocco 082-091 terminano con la memorizzazione del valore di stato del pulsante;
Funzione shortKeyPress()
Passiamo alla descrizione della funzione shortKeyPress() che sarà richiamata quando lo sketch si accorge che la pressione del terzo pulsante è avvenuta per meno di 2,5 secondi:
void shortKeyPress() { Serial.println("short"); if ( isFirstPage ) { OLD_MICROSECOND_STEP_DELAY=MICROSECOND_STEP_DELAY; MICROSECOND_STEP_DELAY=900; int i=0; while (i<NUMBER_OF_STEPS_PER_REV*10) { if ( digitalRead(Bt3) == LOW ) { break; }; backwardStep(); i++; } STEPS_EXECUTED -= (NUMBER_OF_STEPS_PER_REV/(NUMBER_OF_STEPS_PER_PRESS-i)); MICROSECOND_STEP_DELAY=OLD_MICROSECOND_STEP_DELAY; } }
saltando la linea 095 che serve solo per avvisarti sul monitor seriale che sei arrivato nella funzione;
linea 097: valuti se sei nella prima pagina da visualizzare;
le linee 098-100: imposti i valori delle variabili che utilizzerai nelle righe successive;
linea 101: inizi un ciclo di 10 rivoluzioni per il numero di step per rivoluzione all’interno di ciascun passaggio di while esegui la funzione di backwardStep() che fa arretrare il pistone e che puoi fermare in qualunque momento cliccando sul terzo pulsante stesso come descritto alla linea 102;
le linee 106-107: ti servono a calcolare il numero di step eseguiti per visualizzarli sul display OLED;
Notice
non sono contentissimo del calcolo che viene eseguito e nei prossimi mesi modificherò lo sketch per renderlo più affidabile
Questa funzione, come avrai compreso, serve a far arretrare il pistone per inserire la nuova siringa.
Funzione longKeyPress()
la funzione longKeyPress() è davvero semplice e viene invocata, come vedrai, quando hai premuto il terzo pulsante per più di 2,5 secondi:
void longKeyPress() { Serial.println("long"); mode=1; }
l’unica cosa che la funziona esegue è impostare il valore di mode a “1” che ti serve per indicare al CtrlJ pen sketch di entrare nella modalità “menu”.
Funzione keyPress()
Hai già letto di questa funzione alla linea 086 dove viene richiamata al cambio di stato della pressione del pulsante da HIGH a LOW:
void keyPress() { Serial.println("key press"); longKeyPressCount = 0; }
in cui la linea 114 reimposta a 0 il valore della variabile longKeyPressCount.
Funzione keyRelease()
Anche in questo caso la funzione è molto semplice e viene richiamata dalla linea 087:
void keyRelease() { Serial.println("key release"); if (longKeyPressCount >= longKeyPressCountMax) { longKeyPress(); } else { shortKeyPress();} }
le sole due linee valutano il valore raggiunto dalla longKeyPressCount e quando quest’ultimo supera il valore impostato nella longKeyPressCountMax richiama la longKeyPress() o la shortKeyPress()che abbiamo già analizzato nelle linee precedenti di questo articolo.
Nei prossimi articoli leggerai le successive funzioni necessarie per visualizzare le informazioni sul display OLED.