CtrlJ pen sketch ti mostra come sia possibile realizzare e personalizzare l’algoritmo o firmware del progetto.
Per capire bene lo sketch è bene che tu abbia letto e compreso i precedenti articoli dedicati al progetto stesso:
- CtrlJ pen – penna automatica controllo fluidi
- CtrlJ pen elettronica
- CtrlJ pen montaggio eletronica
dividerò questo articolo in parti per rendere più semplice la comprensione.
In particolare nel primo articolo hai letto delle
Funzioni principali:
- controllo del flusso di uscita;
- controllo della retroazione;
- reset della corsa;
- variazione dei parametri di configurazione.
e delle
Funzioni accessorie:
- visualizzazione grafica dello stantuffo;
- menu delle impostazioni;
- memorizzazione delle impostazioni.
e saranno quelle che andrai a definire nello sketch arduino.
Come sai la presenza di un display grafico OLED 0.91″ 128×32 semplifica la visualizzazione delle informazioni e delle impostazioni:
e ti aiuta anche per fornire istruzioni a chi utilizza il progetto sia in fase di configurazione che di utilizzo.
Video relativo al menu e le impostazioni
guardando il video vedrai come si alternano le schermate di configurazione del menu e ti sarà più facile comprendere lo sketch:
per entrare nella modalità di configurazione dovrai tenere premuto per 2 secondi il terzo tasto dalla penna.
In un prossimo articolo vedremo i settaggi passo-passo della CtrlJ pen sketch.
Passiamo adesso allo sketch.
CtrlJ pen sketch
CtrlJ pen sketch è il firmware che dovrai caricare sul micro pro beetle per controllare la penna e l’erogazione dei fluidi:
#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);
}
le prime due linee includono le librerie necessarie al controllo e funzionamento del display OLED.
le linee 004-009: definiscono quale libreria di comunicazione includere in funzione della modalità di connessione del display che desideri utilizzare, nel progetto CtrlJ pen sketch il display OLED è connesso in modalità IIC;
linee 011-013: definisci i pin a cui sono connessi i bottoni di controllo. Nota che il pin è definito mediante la costante che ne definisce la funzione per esempio il pin 11 è MISO come puoi vedere nello schema:
la definizione dei pin di controllo del motore 28BYJ-48 avviene alle linee 015-018 in cui ciascuno dei pin è definito con una lettera: A,B,C e D e corrisponde allo schema dei collegamenti:
nelle linee 020-027: definisci le variabili in cui memorizzerai i valori relativi alla configurazione della penna:
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;
iniziando dalla prima:
TOTAL_OF_STEPS_PER_REV: rappresenta il numero totali di passi necessari al motore per compiere un giro completo dell’albero di 360°;
NUMBER_OF_STEPS_PER_REV: è il numero di passi che vuoi impostare per ogni rotazione;
NUMBER_OF_STEPS_PER_PRESS: è il numero di passi che saranno eseguiti alla pressione del tasto di avanzamento o retroazione;
MICROSECOND_STEP_DELAY: il tempo di delay in microsecondi tra un passo ed il successivo;
OLD_MICROSECOND_STEP_DELAY: è un valore di storage per memorizzare il valore precedentemente impostato e di default parte come MICROSECOND_STEP_DELAY;
TOTAL_STEPS: il numero totale di giri che il motore può compiere dalla posizione più arretrata del pistone alla posizione in cui il pistone è a finecorsa;
STEPS_EXECUTED: memorizza il valore dei passi eseguiti durante l’utilizzo della CtrlJ pen;
arrowPos: serve a gestire la visualizzazione grafica della freccia che ti invita a premere il terzo tasto;
Gestione dei bottoni
la gestione dei bottoni richiede l’uso di alcune variabili e costanti:
// 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
la prima variabile keyPrevMillis serve a memorizzare il valore in millis() dal quale iniziare a contare il tempo che passa;
linea 031: intervallo di tempo, in millisecondi, di cui tener conto;
la linea 032: quanti intervalli di tempo, definiti nella precedente costante, devono trascorrere prima di considerare la pressione una “lunga” pressione, in questo esempio 6 x 25000 = 150 000 = 2,5 sec;
linea 033: la variabile longKeyPressCount ti serve per mantenere il conteggio degli intervalli da 25000 millisecondi mentre essi vengono contati;
infine, per la parte di gestione dei pulsanti, la variabile: prevKeyState memorizza lo stato della precedente pressione del pulsante;
CtrlJ pen sketch – config e display
Il menu di configurazione del CtrlJ pen sketch e la gestione del display OLED richiedono alcune funzioni, iniziamo dalle impostazioni:
// 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);
}
le linee 036-038: definiscono la variabile mode che varia per indicarti se sei in fase di configurazione oppure no e la isFirstPage che ti serve per capire quando stai visualizzando la prima pagina;
la linea 040: imposta e inizializza il display in modalità IIC con la libreria u8glib2;
la funzione u8g2_prepare, come dice il nome stesso, serve a definire le caratteristiche principali ( tipo di font, dimensione, colore principale, direzione del font ) dei font che utilizzerai con il display;
Funzione Setup
la funzione setup della CtrlJ pen sketch come sai è una funzione di inizializzazione di tutte le parti principali del codice arduino:
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);
}
e la userai per impostare le principali impostazioni quali la modalità di utilizzo dei pin e della modalità display.
Le linee 053-060: impostano la modalità INPUT_PULLUP per i pin relativi ai tre bottoni e OUTPUT per i pin di controllo del driver stepper del 28BYJ-48;
la linea 062: inizializza la libreria u8g2 che gestirà il display grafico OLED;
linee 064-065: pulisci il display dalle precedenti impostazioni e richiamoi la funzione u8g2_prepare vista nel paragrafo precedente;
linea 066: richiama la funzione HomePage() che, come immagini, imposta e disegna la prima pagina o main page visualizzata sul display;
linea 067: usando il metodo sendBuffer() della libreria u8g2 invii le impostazioni al display;
per questa prima parte dell’articolo CtrlJ pen sketch hai visto molte delle linee necessarie allo sketch stesso per funzionare.
Nei prossimi articoli entreremo nel dettaglio delle funzioni di loop() e di gestione della penna.





Il blog mauroalfieri.it ed i suoi contenuti sono distribuiti con Licenza