CtrlJ pen sketch – prima parte

CtrlJ pen sketch ti mostra come sia possibile realizzare e personalizzare l’algoritmo o firmware del progetto.

CtrlJ pen sketch and render esploso

Per capire bene lo sketch è bene che tu abbia letto e compreso i precedenti articoli dedicati al progetto stesso:

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:

CtrlJ pen montaggio elettronica

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:

CtrlJ pen schema micro buttons

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:

CtrlJ pen schema micro steppernelle 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.

  • Questo sito ed i suoi contenuti è fornito "così com'è" e Mauro Alfieri non rilascia alcuna dichiarazione o garanzia di alcun tipo, esplicita o implicita, riguardo alla completezza, accuratezza, affidabilità, idoneità o disponibilità del sito o delle informazioni, prodotti, servizi o grafiche correlate contenute sul sito per qualsiasi scopo.
  • Ti chiedo di leggere e rispettare il regolamento del sito prima di utilizzarlo
  • Ti chiedo di leggere i Termini e Condizioni d'uso del sito prima di utilizzarlo
  • In qualità di Affiliato Amazon io ricevo un guadagno dagli acquisti idonei qualora siano presenti link al suddetto sito.

Permalink link a questo articolo: https://www.mauroalfieri.it/elettronica/ctrlj-pen-sketch-prima-parte.html

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.