Far interagire Gambas con Arduino
(Guida a cura del membro Ste86 del forum www.gambas-it.org)
Arduino è un programmatore per microcontrollori ATmega 328 che vuole fornire una piattaforma di sviluppo per prototipizzare sistemi elettronici in modo pratico, divertente e veloce. Un suo vantaggio è una larga utenza, può quindi vantare molta documentazione e vaste comunità.
L'Arduino va collegato tramite una porta USB. All'inizio ho spiegato che nei sistemi UNIX l'hardware viene visto e gestito come un file. Nel momento in cui viene collegato l'Arduino verrà quindi automaticamente creato un file ad hoc nella cartella “/dev” che contiene i preziosi file di sistema. Solitamente tale file viene nominato “ttyACM0”. A mia esperienza ho notato che tra un computer e l'altro la differenza nel nome di tale file, sta nel variare l' ultimo carattere, cioè la cifra, che nel mio caso è 0. Per cui se avete difficoltà a dichiarare il nome del file che controlla Arduino basta che provate a incrementare a tentavi il valore di tale cifra che per esempio potrà essere “ttyACM1” oppure “ttyACM2” e così via...... . Nel nostro esempio va dichiarato il percorso e il nome del file di sistema con cui il programma fa riferimento ad Arduino. Questo parametro va dichiarato nella textbox denominata “txtport” che si trova alinterno della form (in “figura5” è cerchiata in blu). Una volta avviato il programma se per esempio il nostro file si chiama ttyACM0 al suo interno dovremo ogni volta digitare “/dev/ttyACM0”. Personalmente trovo scomodo che ad ogni avvio del programma vada dichiarato il percorso e il nome del file all'interno di “txtport”. Quindi per semplificarci la vita rendiamo automatico tutto questo. Per ovviare questo problema si deve intervenire sul codice del programma nella classe “Button1_Click()” apportando modifiche sulla riga “Sport.PortName = TxtPort.Text”.
Il codice originale si presenterà cosi:
PUBLIC SUB Button1_Click() IF Sport.Status = Net.Active THEN CLOSE Sport Button1.Text = "Open" ELSE ' Line parameters Sport.PortName = TxtPort.Text Sport.Speed = CmbSpeed.Text Sport.Parity = CmbParity.Index Sport.DataBits = CmbData.Text Sport.StopBits = CmbStop.Text ' keep DTR on Sport.FlowControl = ComboBox1.Index Sport.Open() Check_Status() TextArea1.Text = "Port Opened : " & Sport.PortName & " Settings : " & Sport.Speed & "," & Sport.Parity & "," & Sport.DataBits & "," & Sport.StopBits & Chr(13) & Chr(10) Button1.Text = "Close" END IF Button1_Click() END
Ecco il codice con inserite le modifiche da apportare, segnate in rosso, nella classe Button1_Click() :
PUBLIC SUB Button1_Click() DIM port AS String port = "/dev/ttyACM0" IF Sport.Status = Net.Active THEN CLOSE Sport Button1.Text = "Open" ELSE ' Line parameters Sport.PortName = port Sport.Speed = CmbSpeed.Text Sport.Parity = CmbParity.Index Sport.DataBits = CmbData.Text Sport.StopBits = CmbStop.Text ' keep DTR on Sport.FlowControl = ComboBox1.Index Sport.Open() Check_Status() TextArea1.Text = "Port Opened : " & Sport.PortName & " Settings : " & Sport.Speed & "," & Sport.Parity & "," & Sport.DataBits & "," & Sport.StopBits & Chr(13) & Chr(10) Button1.Text = "Close" END IF END
Ora eseguiamo il programma, ma non preoccupatevi se nella TxtPort vedrete ancora scritto una cosa del tipo /dev/ttyS0 l'importante è che sia dichiarata correttamente all'interno del codice. Con questo metodo possiamo ora definire tutti i parametri come ad esempio Sport.Speed, Sport.Parity, Sport.DataBits, Sport.StopBits, ecc ecc..
Una altra classe che secondo me ha importanza rilevante è la Form_Open() perché all'interno di essa viene specificato che valore deve aver il baud rate della porta utilizzata. Essa si presenta cosi:
PUBLIC SUB Form_Open() cmbSpeed.Index = cmbSpeed.Find("19200") END
Da WIKIPEDIA: “Il baud rate indica il numero di transizioni al secondo che avvengono sulla linea; il bps indica, come dice il nome, quanti bit al secondo sono trasmessi lungo la linea”.
Nella comunicazione seriale questo valore deve essere uguale per chi riceve e per chi trasmette i dati.
Solitamente Arduino lo si imposta a 9600 e dunque anche il nostro progetto deve essere impostato con lo stesso valore. Possiamo rendere automatico anche questo senza dover andare ad agire nella textbox situata nella form come cerchiato in giallo nella “figura5”.
Ecco il codice con la modifica segnata in rosso:
PUBLIC SUB Form_Open() cmbSpeed.Index = cmbSpeed.Find("9600") END
Siamo arrivati ora al momento di fare qualcosa di pratico dalla situazione che abbiamo ora. L'esempio SerialPort come l'abbiamo impostato farà scrivere in una TextBox il testo
“ciao a tutti”
grazie ad un segnale seriale di Arduino che parte alla pressione di un pulsante su esso. Ecco il codice per Arduino per ottenere questo:
const int buttonPin8 = 8; int buttonState8 = 0; void setup() { Serial.begin(9600); pinMode(buttonPin8, INPUT); } void loop() { buttonState8 = digitalRead(buttonPin8); if (buttonState8 == HIGH) { delay (250); Serial.print ("ciao a tutti"); } }
Questo, invece, è il codice per Gambas con le modifiche in rosso. La struttura della form deve essere quella dell'esempio SerialPort raffigurata in “figura5”:
' Gambas class file PUBLIC SUB Form_Close() IF Sport.Status = Net.Active THEN CLOSE Sport END PUBLIC SUB Check_Status() ChkDSR.Value = Sport.DSR ChkDTR.Value = Sport.DTR ChkCTS.Value = Sport.CTS ChkRTS.Value = Sport.RTS ChkDCD.Value = Sport.DCD ChkRNG.Value = Sport.RNG END PUBLIC SUB Button1_Click() DIM port AS String port = "/dev/ttyACM0" IF Sport.Status = Net.Active THEN CLOSE Sport Button1.Text = "Open" ELSE ' Line parameters Sport.PortName = port Sport.Speed = CmbSpeed.Text Sport.Parity = CmbParity.Index Sport.DataBits = CmbData.Text Sport.StopBits = CmbStop.Text ' keep DTR on Sport.FlowControl = ComboBox1.Index Sport.Open() Check_Status() TextArea1.Text = Chr(13) & Chr(10) Button1.Text = "Close" END IF END PUBLIC SUB SPort_Read() DIM s AS String READ #Sport, s, Lof(Sport) TextArea1.Text = TextArea1.Text & s END PUBLIC SUB SPort_RNGChange(iVal AS Boolean) ChkRng.Value = iVal END PUBLIC SUB SPort_DTRChange(iVal AS Boolean) ChkDTR.Value = iVal END PUBLIC SUB SPort_DSRChange(iVal AS Boolean) ChkDSR.Value = iVal END PUBLIC SUB SPort_CTSChange(iVal AS Boolean) ChkCTS.Value = iVal END PUBLIC SUB SPort_DCDChange(iVal AS Boolean) ChkDCD.Value = iVal END PUBLIC SUB SPort_RTSChange(iVal AS Boolean) ChkRTS.Value = iVal END PUBLIC SUB Button2_Click() IF Sport.Status = Net.Inactive THEN Message("Open port first!") ELSE ' WRITE #Sport,TxtSend.Text & Chr(13) & Chr(10), txtSend.Length + 2 PRINT #Sport, txtSend.Text; Chr$(13); Chr$(10); END IF END PUBLIC SUB ChkDTR_Click() Sport.DTR = ChkDTR.Value Check_Status END PUBLIC SUB ChkRTS_Click() Sport.RTS = ChkRTS.Value Check_Status END PUBLIC SUB ComboBox1_Click() Sport.FlowControl = ComboBox1.Index END PUBLIC SUB Form_Open() cmbSpeed.Index = cmbSpeed.Find("9600") END
Con questo è tutto. Spero di essere stato esauriente. Buon divertimento!!
Ste86