Light Follower
Microcontrollore AtTiny85, multiplexer analogico CD4052, fotoresistenze, arduino, visualbasic .net e PC. (Progetto scolastico)
Di seguito si illustra il progetto di una breakout board che permette di interfacciare tre fotoresistori con il mondo esterno utilizzando il protocollo di comunicazione I2C. La funzione principale della scheda e restituire in gradi sessagesimali la direzione della luce.
Un microcontrollore AtTiny85 che gestisce i calcoli e la comunicazione I2C.
Viene usato un multiplexer analogico CD4052 per gestire le misure analogiche dei tre fotoresistori.
E’ stata inoltre sviluppata un interfaccia grafica in grado di svolgere un accurato collaudo del dispositivo, questa permette di monitorare in tempo reale la variazione dei valori dei fotoresistori e attraverso una rappresentazione grafica la posizione nello spazio della fonte luminosa.
Indice
- Introduzione
- Schema a Blocchi
- Schema elettrico
- Parti del progetto
- PCB
- Codice Sorgente AtTiny85
- Collaudo
- Componenti
- Immagini
- Conclusioni
Introduzione
Lo scopo del progetto e’ realizzare una breakout board in grado di acquisire le tensioni di tre fotoresistori, svolgere delle funzioni e restituire tali valori tramite il protocollo di comunicazione I2C.
Il progetto ha le seguenti specifiche:
- Deve poter comunicare con altri dispositivi tramite il protocollo I2C.
- Deve effettuare misurazioni su tre fotoresistori.
- Deve prevedere le seguenti funzioni:
- Invio della direzione della fonte luminosa in gradi sessagesimali.
- Invio dell’intensita’ luminosa compresa tra 0 e 255 per ogni fotoresistore.
- Possibilita’ di cambiare indirizzo I2C della scheda, tale indirizzo non deve essere perso qualora venga tolta l’alimentazione.
Schema a blocchi
Schema elettrico
Clicca sull’immagine per ingrandirla
Parti del Progetto
AtTiny85
E’ stato usato un microcontrollore AtTiny85 della ATMEL per controllare la scheda di breakout.
Questo microcontrollore e’ programmabile nel linguaggio di Arduino e viene usato Arduino stesso per caricarvi il programma.
Sono stati usati i pin PB0 e PB2, rispettivamente SDA e SCL, per la connessione I2C. Il pin PB4 contenente un ADC a 10 bit effettua misure analogiche dalleuscita del multiplexer analogico, mentre i pin PB3 e PB1 comandano i 2 ingressi di selezione del multiplexer.
Multiplexer Analogico
Si devono effettuare tre misure analogiche(una per fotoresistore), anche se l’AtTiny85 possiede tre ADC, uno, il pin PB5, non può essere utilizzato perchè questo pin svolge di norma la funzione di reset, necessaria se si carica il programma tramite Arduino, quindi è stato preso un multiplexer analogico CD4052.
I pin X0, X1 e X2 sono collegati ai fotoresistori, l’uscita comune X è collegata ad una resistenza di pull-up da 10k ed ad l’ADC2(pin PB4) dell’AtTiny85. Tutti gli altri pin sono connessi a massa, escluso VDD che è connesso a 5V.
Calcolo Angolo
I fotoresistori sono da 200kΩ, e a turno vengono connessi alla resistenza da 10kΩ per formare un partitore di tensione. Le loro facce sono posizionate a 120° l’una rispetto all’altra.
Questo permette di considerare i fotoresistori come dei vettori in un piano cartesiano.
Questi partono dall’origine ed hanno angolo fisso (ovvero 90°, -30° e -150°) ma modulo variabile da 0 a 255, più la luce è intensa più questo è grande.
Per prima cosa si calcolano le componenti X ed Y dei vettori:
Gli angoli sono espressi in radianti.
Dopo di che vengono sommate le componenti:
Per ottenere in gradi si svolge l’arcotangente della pendenza (Y/X) del vettore è la si moltiplica per il fattore 57.32.
In questo modo si è ottenuta la pendenza di una retta, quindi si deve svolgere un ultimo passaggio per ricavare in quale quadrante è contenuto il vettore:
- 1° quadrante: X>0 e Y>0: Angolo=|a-360|
- 2° quadrante: X>0 e Y
- 3° quadrante: X0: Angolo=|a-180|
- 4° quadrante: X
PCB
Clicca sulle immagini per ingrandirle
Nel top è presente il piano di massa, mentre nel bottom il piano di VCC.
Codice Sorgente AtTiny85
// SLAVE AtTiny CODICE // IVANCICH STEFANO 4EA // LIGHT FOLLOWER con AtTiny85, MUX analogico e fotoresistori // Ultima modifica: 03/03/2014 ////////////// INCLUSIONE LIBRERIE //////////////////////// #include <TinyWireS.h> #include <EEPROM.h> ///////////// DICHIARAZIONE PIN /////////////////////////// const int A=3; // Pin 2 AtTiny const int B=1; // Pin 6 AtTiny /* B pin 9 IC MUX A pin 10 IC MUX INH pin 6 IC MUX INH | B | A | 0 | 0 | 0 | 0 0 | 0 | 1 | 1 0 | 1 | 0 | 2 0 | 1 | 1 | 3 1 | X | X | none */ //////////// DICHIARAZIONE VARIABILI ///////////////////// const int pausa=100; // Tempo di pausa usato tra un operazione e l'altra const byte memIndirizzo=0x10; // Indirizzo della memoria EEPROM interna che contiene l'indirizzo del dispositivo per la comunicazione I2C byte indirizzoSlave; // Contiene l'indirizzo del dispositivo per la comunicazione I2C byte byteRcvd, byteRcvd2; // Conterranno i valori ricevuti dalla comunicazione I2C int numero; // Conterrà il valore della misura dell'ADC int luminosita[3]; // Vettore contenente i valori di luminosità di ciascun fotoresistore int gradi; // Contiene il valore dell'angolo della direzione della fonte luminosa int j; // Variabile usata come contatore //////////// IMPOSTAZIONI //////////////////////////////// void setup() { pinMode(A, OUTPUT); // Impostato come OUTPUT pinMode(B, OUTPUT); // Impostato come OUTPUT indirizzoSlave=EEPROM.read(memIndirizzo); // Legge l'indirizzo di memoria memIndirizzo dove è contenuto l'indirizzo I2C del dispositivo if(indirizzoSlave==255)indirizzoSlave=63; // Se l'indirizzo è 255 lo porta a 63, che è il massimo valore inviabile else indirizzoSlave=indirizzoSlave; TinyWireS.begin(indirizzoSlave); // Attiva il bus I2C, come Slave TinyWireS.onRequest(richiesta); // In caso di richiesta di dati dal bus I2C viene richiamata la funzione "richiesta" TinyWireS.onReceive(riceviNumeri); // In caso di ricezione di dati dal bus I2C viene richiamata la funzione "riceviNumeri" } /////////// FUNZIONE PRINCIPALE ////////////////////////// void loop() { // Fotoresistore SX: digitalWrite(B, LOW); // Imposta i piedini di selezione dell multiplexer a 00 digitalWrite(A, LOW); // quindi verra selezionato l'ingresso 0 luminosita[2]=misura(); // Assegna il valore della luminosita corrispondente delay(pausa); // Fotoresistore DAVANTI: digitalWrite(B, LOW); // Imposta i piedini di selezione dell multiplexer a 10 digitalWrite(A, HIGH); // quindi verra selezionato l'ingresso 2 luminosita[0]=misura(); // Assegna il valore della luminosita corrispondente delay(pausa); // Fotoresistore DX: digitalWrite(B, HIGH); // Imposta i piedini di selezione dell multiplexer a 01 digitalWrite(A, LOW); // quindi verra selezionato l'ingresso 1 luminosita[1]=misura(); // Assegna il valore della luminosita corrispondente delay(pausa); // Calcolo componenti X e Y di ogni vettore: float vetX[3],vetY[3]; // Array che conterranno i valori delle componenti x e y dei vettori associati alle fotoresistenze vetX[0]=cos(1.57)*luminosita[0]; // 90° fotoresistore davanti vetX[1]=cos(-0.52)*luminosita[1]; // -30° fotoresistore a destra vetX[2]=cos(-2.62)*luminosita[2]; // -150° fotoresistore a sininstra vetY[0]=sin(1.57)*luminosita[0]; // 90° fotoresistore davanti vetY[1]=sin(-0.52)*luminosita[1]; // -30° fotoresistore a destra vetY[2]=sin(-2.62)*luminosita[2]; // -150° fotoresistore a sininstra // Somma dei vettori: float X=vetX[0]+vetX[1]+vetX[2]; // Somma componenti X float Y=vetY[0]+vetY[1]+vetY[2]; // Somma componenti Y // Calcolo gradi float arco=atan(Y/X)*57.32; // Arcotangente della pendeza del vettore trovato(Y/X) convertita in gradi if(X>0&&Y>0)gradi=abs(arco-360); // 1° Quadrante if(X>0&&Y<0)gradi=abs(arco); // 2° Quadrante if(X<0&&Y>0)gradi=abs(arco-180); // 3° Quadrante if(X<0&&Y<0)gradi=180-arco; // 4° Quadrante } /////////// FUNZIONI BUS I2C ////////////////////////// void richiesta(){ // Funzione richiamata in caso di richiesta di dati dal bus I2C switch (byteRcvd) { // Seleziona l'opzione corrispondente al 1° valore riceuto in precedenza case 0x01: direzioneLuce(); break; case 0x02: TinyWireS.send(luminosita[0]); // Invia il valore del 1° fotoresistore(quello davanti) break; case 0x03: TinyWireS.send(luminosita[1]); // Invia il valore del 2° fotoresistore(quello a destra) break; case 0x04: TinyWireS.send(luminosita[2]); // Invia il valore del 3° fotoresistore(quello a sinistra) break; } } void riceviNumeri(uint8_t howMany){ // Funzione richiamata in caso di ricezione di dati dal bus I2C if(TinyWireS.available()>1){ // Se c'è piu di un dato nella coda FIFO byteRcvd = TinyWireS.receive(); // Legge il primo dato if(byteRcvd==5){ // Se uguale a 5(5° opzione che serve a cambiare l'indirizzo dello slave) byteRcvd2= TinyWireS.receive(); // Legge il secondo dato nella coda FIFO EEPROM.write(memIndirizzo,byteRcvd2); //Salva il nuovo indirizzo tws_delay(10); // Aspetta il tempo necessario a scrivere l'indirizzo setup(); // Riavvia il dispositivo } } else byteRcvd = TinyWireS.receive(); // Altrimenti legge solamente il dato ricevuto } //////////////// FUNZIONI DEL DISPOSITIVO ///////////////////// byte misura(){ numero=analogRead(2); // Misura con l'ADC del pin3 la tensione numero/=4; // Porta il range di valori da 0-1023 a 0-255 byte valore=(byte)(255-numero); // Nega il valore misurato, in quanto si vuole che all'aumentare dlla luminosita aumenti il valore del numero return valore; // Restituisce il valore alla funzione chiamante } void direzioneLuce(){ // Divisione del numero in 2 byte: byte vetGradi[2]; if(gradi>255){ // Se il numero è piu grande di 255 vetGradi[1]=(byte)(gradi-255); vetGradi[0]=(byte)255; } else{ vetGradi[1]=(byte)0; vetGradi[0]=(byte)gradi; } // Invio dei 2 byte: TinyWireS.send(vetGradi[j]); j++; if(j==2)j=0; delay(pausa); }
Collaudo
Per il collaudo di questa scheda è stato creato un software apposito in Visual Basic e uno sketch per Arduino che comunica tra il PC e la scheda di breakout.
Arduino
// IVANCICH STEFANO 4EA // MASTER ARDUINO CODICE // Ultima modifica: 05/03/2014 ////////////// INCLUSIONE LIBRERIE //////////////////////// #include <Wire.h> //////////// DICHIARAZIONE VARIABILI ///////////////////// int indirizzoSlave; // indirizzo dello slave int option=0; // Opzione ricevuta dal serial bus int NuovoindirizzoSlave=0; // Nuovo indirizzo dello slave byte slaveConnected=0,completed=1,completed2=0; // Variabili usate come flag //////////// IMPOSTAZIONI //////////////////////////////// void setup() { Wire.begin(); // Attiva il bus I2C; il dispositivo è predisposto come master Serial.begin(9600); // Attiva il bus seriale per la connessione col pc } /////////// FUNZIONE PRINCIPALE ////////////////////////// void loop() { // Imposta lo slave con cui comunicare: if(slaveConnected==0&&Serial.available()){ // Se lo slave non è stato connesso e ci sono dati nel serial bus: indirizzoSlave=Serial.parseInt(); // Legge il dato dal serial bus e lo usa come indirizzo slave Serial.println("Slave collegato"); // Scrive sul serial bus "Slave collegato" slaveConnected=1; // Segna il flag slaveConnected a 1-->Slave connesso completed=0; // Segna il flag completed a 0-->Prima operaziones sullo slave non effettuata } // Acquisice l'opzione if(completed==0&&Serial.available()){ // Se non sono state fatte operazioni sullo slave e ci sono dati nel serial bus: option = Serial.parseInt(); switch(option){ case 1: Serial.println(luminosita(1)); break; case 2: Serial.println(luminosita(2)); break; case 3: Serial.println(luminosita(3)); break; case 4: Serial.println(angolo()); break; case 5: // Cambia indirizzo completed=1; // Segna la prima operazione come completata completed2=1; // Segna la seconda operazione come completata break; case 6: // Scollego slave completed=1; // Segna la prima come operazione completata slaveConnected=0; // Segna lo slave come sconnesso Serial.println("Slave Scollegato"); indirizzoSlave=Serial.parseInt(); // Usata perche è presente un carattere indesiderato break; } } // Opzione cambio indirizzo: if(completed2==1 && Serial.available()){ // Se la seconda operazione è completata NuovoindirizzoSlave=Serial.parseInt(); // Legge dal serial bus un dato e lo assegna a NuovoindirizzoSlave cambioIndirizzo(NuovoindirizzoSlave); // Richiama la funzione cambio indirizzo e passa il parametro NuovoindirizzoSlave Serial.print("Scritto: ");Serial.println(NuovoindirizzoSlave); // Scrive sul serial bus il valore dell'indirizzo scritto sulla eeprom completed2=0; // Segna la prima operazione come non completata completed=0; // Segna la seconda operazione come non completata indirizzoSlave=NuovoindirizzoSlave; // Imposta il nuovo indirizzo dello slave } } //////////////// FUNZIONI DEL DISPOSITIVO ///////////////////// int luminosita(int n){ if(n<1||n>3) return 0; // Se il parametro ricevuto è diverso da 1, 2 o 3 ritorna uno 0 // Imposta l'opzione: Wire.beginTransmission(indirizzoSlave); byte opzione=n+1; // Perchè l'opzione 1 è l'angolo Wire.write(opzione); Wire.endTransmission(); // Invia l'opzione al bus I2C // Chiede un byte: Wire.requestFrom(indirizzoSlave,1); while(Wire.available()){ // Se c'è almeno un byte nel FIFO esegue il ciclo return (int)Wire.read(); // Legge il dato dal bus I2C } } int angolo(){ // Imposta l'opzione: Wire.beginTransmission(indirizzoSlave); byte opzione=1; Wire.write(opzione); Wire.endTransmission(); // Chiede 2 byte: int a=0,i=0; Wire.requestFrom(indirizzoSlave,2); while(Wire.available()){ // Se c'è almeno un byte nel FIFO esegue il ciclo a+=(int)Wire.read(); // Riceve 2 byte la cui somma da un numero compreso tra 0 e 359 } return a; // Ritorna l'angolo ricevuto dallo slave } void cambioIndirizzo(int address){ Wire.beginTransmission(indirizzoSlave); Wire.write(5); Wire.write(address); Wire.endTransmission(); // Invia l'opzione 5 e il nuvo indirizzo dello slave da impostare al bus I2C }
Arduino preleva dal serial bus l’indirizzo dello slave a cui si deve connettere e solo successivamente preleva l’opzione scelta dall’utente(1, 2, 3, 4, 5 o 6).
A ciascuno opzione corrisponde una funzione:
- Luminosità del primo fotoresistore
- Luminosità del secondo fotoresistore
- Luminosità del terzo fotoresistore
- Angolo della direzione della luce
- Cambio dell’indirizzo del dispositivo
- Sconnessione dello slave
Per ciascuna opzione Arduino scriverà sul serial bus i valori ricevuti dal dispositivo o messaggi riguardanti lo stato di connessione del dispositivo al bus I2C. Questi possono essere visti dal serial monitor dell’Arduino o dall’interfaccia grafica sul pc.
Visual Basic .net
Il codice scritto in Visual Basic possiede un parte in ambiente grafico ed una in codice vero e proprio.
Ambiente Grafico:
Clicca sull’immagine per ingrandirla.
Codice:
Public Class Form1 Dim porteDisponibili As Array 'Arrey che conterrà la lista delle porte COM disponibili Dim disegno As Graphics 'Oggetto che gestira elementi di tipo grafico Dim DatoRicevuto As String 'Variabile che conterrà la stringa ricevuta dalla comunicazione seriale Private Sub Form1_Load() Handles MyBase.Load SerialPort1.Close() 'Chiude la porta seriale se era già aperta porteDisponibili = IO.Ports.SerialPort.GetPortNames() 'Mette nell'array le porte seriali disponibili ComboBoxPort.Items.AddRange(porteDisponibili) ' Mette nella ComboBox(lista) le porte seriali disponibili End Sub Private Sub disegna() 'Funzione richiamata per rappresentare graficamente la provenienza della fonte luminosa disegno = Panel1.CreateGraphics() 'All'oggetto disegno assegna come rappresentazione l'oggetto panel1 Panel1.Refresh() 'Cancella il contenuto del panel1 per non appesantire il programma disegno.FillRectangle(Brushes.Black, 0, 0, 250, 250) 'Disegna sulla classe disegno(panel1) un rettangolo nero pieno che parte dal punto 0,0 e grande 250,250 pixel disegno.DrawEllipse(Pens.Orange, 0, 0, 250, 250) 'Disegna sulla classe disegno(panel1) una ellisse a forma di cerchio arancione che parte dal punto 0,0 e grande 250,250 pixel disegno.DrawEllipse(Pens.Orange, 42, 42, 167, 167) 'Disegna sulla classe disegno(panel1) una ellisse a forma di cerchio arancione che parte dal punto 42,42 e grande 167,167 pixel disegno.DrawLine(Pens.Orange, 125, 250, 125, 0) 'Disegna sulla classe disegno(panel1) una linea di colore arancione, che parte dalle cordinate 125,250(centro basso del cerchio) e va fino alle cordinate 125,0(centro alto del cerchio) disegno.DrawLine(Pens.Orange, 0, 125, 250, 125) 'Disegna sulla classe disegno(panel1) una linea di colore arancione, che parte dalle cordinate 0,200(centro a sinistra del cerchio) e va fino alle cordinate 250,125(centro a destra del cerchio) disegno.DrawLine(Pens.Orange, 63, 17, 188, 233) 'Disegna sulla classe disegno(panel1) una linea di colore arancione, che parte dalle cordinate 63,17(150°) e va fino alle cordinate 188,233(330°) disegno.DrawLine(Pens.Orange, 63, 233, 188, 17) 'Disegna sulla classe disegno(panel1) una linea di colore arancione, che parte dalle cordinate 63,233(210°) e va fino alle cordinate 188,233(30°) disegno.DrawLine(Pens.Orange, 17, 63, 233, 188) 'Disegna sulla classe disegno(panel1) una linea di colore arancione, che parte dalle cordinate 17,63(120°) e va fino alle cordinate 373,188(300°) disegno.DrawLine(Pens.Orange, 233, 63, 17, 188) 'Disegna sulla classe disegno(panel1) una linea di colore arancione, che parte dalle cordinate 233,63(60°) e va fino alle cordinate 17,188(230°) disegno.FillEllipse(Brushes.Orange, 105, 105, 40, 40) 'Disegna sulla classe disegno(panel1) una ellisse piena a forma di cerchio arancione che parte dal punto 105,105(centro del disegno) e grande 40,40 pixel Dim x, y As Integer 'Variabili utilizzate come cordinate della provenienza della fonte luminosa Dim angolo As Double 'Angolo della fonte luminosa angolo = DatoRicevuto / 57.32 'Angolo ricevuto in gradi, convertito in radianti x = 125 * Math.Cos(angolo) + 125 'Calcola cordinata X y = 125 * Math.Sin(angolo) + 125 'Calcola cordinata Y disegno.FillEllipse(Brushes.White, x - 20, y - 20, 40, 40) 'Disegna sulla classe disegno(panel1) una ellisse piena a forma di cerchio bianco che parte dal punto x-20,y-20 e grande 40,40 pixel End Sub Private Sub Timer1_Tick() Handles Timer1.Tick 'Funzione eseguita ad ogni intervallo di tempo prestabilito(Timer1.interval) On Error Resume Next 'Se accadono errori in una istruzione, la salta per evitare che il programma crashi SerialPort1.WriteLine("1") 'Scrive sulla porta seriale "1"(Opzione 1) DatoRicevuto = SerialPort1.ReadLine 'Mette nella variabile DatoRicevuto il dato letto dal serial bus LabelLum1.Text = DatoRicevuto 'Il testo del label LabelLum1 diventa il contenuto della variabile DatoRicevuto SerialPort1.WriteLine("2") 'Scrive sulla porta seriale "2"(Opzione 2) DatoRicevuto = SerialPort1.ReadLine 'Mette nella variabile DatoRicevuto il dato letto dal serial bus LabelLum2.Text = DatoRicevuto 'Il testo del label LabelLum2 diventa il contenuto della variabile DatoRicevuto SerialPort1.WriteLine("3") 'Scrive sulla porta seriale "3"(Opzione 3) DatoRicevuto = SerialPort1.ReadLine 'Mette nella variabile DatoRicevuto il dato letto dal serial bus LabelLum3.Text = DatoRicevuto 'Il testo del label LabelLum3 diventa il contenuto della variabile DatoRicevuto SerialPort1.WriteLine("4") 'Scrive sulla porta seriale "4"(Opzione 4) DatoRicevuto = SerialPort1.ReadLine 'Mette nella variabile DatoRicevuto il dato letto dal serial bus LabelDirection.Text = DatoRicevuto 'Il testo del label LabelDirection diventa il contenuto della variabile DatoRicevuto disegna() 'Richiama la funzione disegna per rapppresentare graficamente i dati appena ricevuti End Sub Private Sub ButtonConnectSerialPort_Click() Handles ButtonConnectSerialPort.Click 'Funzione eseguita quando si clicca sul bottone ButtonConnectSerialPort On Error Resume Next 'Se accadono errori in una istruzione, la salta per evitare che il programma crashi If ButtonConnectSerialPort.Text = "Connect Port" Then 'Se il testo del bottone ConnectSerialPort è "Connect Port": SerialPort1.PortName = ComboBoxPort.Text 'Assegna al portname la porta COM del ComboBoxPort selozionata SerialPort1.Open() 'Apre la porta seriale ButtonConnectSerialPort.Text = "Disconnect Port" 'La scritta sul bottone connetti diventa "Disconnect Port" ComboBoxPort.Enabled = False 'La ComboBoxPort non può essere più selezionata ButtonConnectSlave.Enabled = True 'Abilita il bottone ConnectSlave ButtonStart.Text = "Start" 'La scritta sul bottone Start diventa "Start" Else SerialPort1.Close() 'Chiude la porta seriale ButtonConnectSerialPort.Text = "Connect Port" 'La scritta sul bottone connetti diventa "Connect Port" ComboBoxPort.Enabled = True 'La ComboBoxPort può essere di nuovo selezionata ButtonConnectSlave.Text = "Connect Slave" 'La scritta sul bottone connetti diventa "Connect Slave" ButtonConnectSlave.Enabled = False 'Disbilita il bottone ConnectSlave ButtonStart.Enabled = False 'Disbilita il bottone Start ButtonStart.Text = "Start" 'La scritta sul bottone Start diventa "Start" ButtonChangeAddress.Enabled = False 'Disbilita il bottone ChangeAddress Timer1.Enabled = False 'Disabilita il timer (lo spengo) End If End Sub Private Sub ButtonConnectSlave_Click() Handles ButtonConnectSlave.Click 'Funzione eseguita quando si clicca sul bottone ButtonConnectSlave On Error Resume Next 'Se accadono errori in una istruzione, la salta per evitare che il programma crashi If ButtonConnectSlave.Text = "Connect Slave" Then 'Se il testo del bottone ConnectSlave è "Connect Slave" ButtonConnectSlave.Text = "Disconnect Slave" 'La scritta sul bottone connetti diventa "Disconnect Slave" ButtonStart.Enabled = True 'Abilita il bottone Start ButtonStart.Text = "Start" 'La scritta sul bottone Start diventa "Start" SerialPort1.WriteLine(TextSlave.Text) 'Scrive sulla porta seriale l'indirizzo contenuto nella TextSlave DatoRicevuto = SerialPort1.ReadLine 'Mette nella variabile DatoRicevuto il dato letto dal serial bus TextData.Text = DatoRicevuto 'Mette nella TextData il dato ricevuto dal serial bus, per mostrarlo all'utente(Ci si aspetta "Slave Collegato") Else ButtonConnectSlave.Text = "Connect Slave" 'La scritta sul bottone connetti diventa "Connect Slave" ButtonStart.Enabled = False 'Disbilita il bottone Start ButtonStart.Text = "Start" 'La scritta sul bottone Start diventa "Start" ButtonChangeAddress.Enabled = False 'Disbilita il bottone ChangeAddress SerialPort1.WriteLine("6") 'Scrive sulla porta seriala "6"(Opzione che disconnette lo slave) DatoRicevuto = SerialPort1.ReadLine 'Mette nella variabile DatoRicevuto il dato letto dal serial bus TextData.Text = DatoRicevuto 'Mette nella TextData il dato ricevuto dal serial bus, per mostrarlo all'utente(Ci si aspetta "Slave Scollegato") Timer1.Enabled = False 'Disabilita il timer (lo spengo) End If End Sub Private Sub ButtonStart_Click() Handles ButtonStart.Click 'Funzione eseguita quando si clicca sul bottone ButtonStart On Error Resume Next 'Se accadono errori in una istruzione, la salta per evitare che il programma crashi If ButtonStart.Text = "Start" Then 'Se il testo del bottone Start è "Start" ButtonStart.Text = "Stop" 'La scritta sul bottone Start diventa "Stop" ButtonChangeAddress.Enabled = True 'Abilita il bottone ChangeAddress Timer1.Enabled = True 'Abilita il timer Else ButtonStart.Text = "Start" 'La scritta sul bottone Start diventa "Start" ButtonChangeAddress.Enabled = False 'Disbilita il bottone ChangeAddress Timer1.Enabled = False 'Disabilita il timer (lo spengo) End If End Sub Private Sub ButtonChangeAddress_Click() Handles ButtonChangeAddress.Click 'Funzione eseguita quando si clicca sul bottone ButtonChangeAddress On Error Resume Next 'Se accadono errori in una istruzione, la salta per evitare che il programma crashi Timer1.Enabled = False 'Disabilita il timer (lo spengo) SerialPort1.WriteLine("5") 'Scrive sulla porta seriala "5"(Opzione che consente di cambiare l'indirizzo dello slave) SerialPort1.WriteLine(TextSlave.Text) 'Scrive sulla porta seriale l'indirizzo contenuto nella TextSlave DatoRicevuto = SerialPort1.ReadLine 'Mette nella variabile DatoRicevuto il dato letto dal serial bus TextData.Text = DatoRicevuto 'Mette nella TextData il dato ricevuto dal serial bus, per mostrarlo all'utente(Ci si aspetta "Slave Scollegato") Timer1.Enabled = True 'Abilita il timer End Sub Private Sub ButtonExit_Click() Handles ButtonExit.Click 'Funzione eseguita quando si clicca sul bottone ButtonExit On Error Resume Next 'Se accadono errori in una istruzione, la salta per evitare che il programma crashi SerialPort1.WriteLine("6") 'Scrive sulla porta seriala "6"(Opzione che disconnette lo slave) SerialPort1.Close() 'Chiude la porta seriale se era già aperta Me.Close() 'Chiude l'intero programma End Sub End Class
Lo svolgimento del programma è il seguente:
Si sceglie la porta seriale dell’Arduino dalla ComboBoxPort e la si connette cliccando sul bottone ConnectPort.
Si digita l’indirizzo del dispositivo sulla TextSlave e lo si connette cliccando sul bottone ConnectSlave.
Si clicca sul bottone Start che fa partire il timer1.
Il timer invia a ripetizione la sequenza 1-2-3-4 sul serial bus e legge la risposta dell’Arduino che contiene i valori delle 3 luminosità dei fotoresistori e l’angolo della direzione della luce, successivamente viene richiamata la funzione disegna() che si occupa di rappresentare graficamente sull’oggetto panel1 la posizione della fonte luminosa.
Cliccando sul bottone ChangeAddress viene inviato il valore del nuovo indirizzo all’Arduino, che poi si occuperà di cambiarlo.
Componenti utilizzati
- AtTiny85
- CD4052 Multiplexer analogico
- 3 Fotoresistori da 200kΩ
- Resistore 10kΩ
- Basetta presensibilizzata a doppia faccia
- 30 piedini a tulipano
- 4 piedini maschio piegati
- Arduino UNO
- Cavetti breadboard
Immagini Varie
Conclusioni
Per realizzare questo progetto sono state affrontate tutte le specifiche una per una su una breadboard, successivamente è stato realizzato il PCB per ottenere misure più affidabili e veloci, ed infine sono state unite per formare il progetto completo.