Posts tagged Arduino
Arduino Ethernet Shield e messaggi su display LCD
0
Ecco finalmente un progetto con l’ethernet shield.
Lo avevo completato già qualche giorno fa, ma per mancanza di tempo non sono riuscito a fare il post.
Di cosa si tratta il progetto?
In poche, anzi pochissime parole, accedendo ad una pagina internet si possono inviare messaggi all’arduino che li mostrerà su un display lcd 20×4 collegato ad esso, in più tramite un radiobutton si può decidere se alla ricezione del messaggio debba suonare o no un cicalino che appunto ci avverte del nuovo messaggio.
Ecco uno screen della pagina internet:

Ed ecco uno screen del display lcd:

Passiamo al codice:
#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal.h>
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,0, 123);
EthernetServer server(81);
LiquidCrystal lcd(9,8,7,6,5,4);
String lettura = "";
String suona = "";
String riga1 = "";
String riga2 = "";
String riga3 = "";
String riga4 = "";
void setup(){
Ethernet.begin(mac, ip);
server.begin();
lcd.begin(20, 4);
Serial.begin(9600);
Serial.println("Avvio del programma");
lcd.setCursor(0,0),
lcd.print("Attesa...");
pinMode(3, OUTPUT);
}
void loop(){
EthernetClient client = server.available();
if(client){
while (client.connected()){
if (client.available()){
char c = client.read();
lettura.concat(c);
Serial.print(c);
if (c == '\n'){
if(lettura.indexOf("?") < 0){
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.println("<HTML>");
client.println("<HEAD>");
client.println("<TITLE>Messaggi su display LCD</TITLE>");
client.println("</HEAD>");
client.println("<BODY>");
client.println("<H1>Invia un messaggio:</H1>");
client.println("<form method=\"get\">");
client.println("<input type=\"text\" name=\"riga1\" maxlength=\"20\" autocomplete=off> <br>");
client.println("<input type=\"text\" name=\"riga2\" maxlength=\"20\" autocomplete=off> <br>");
client.println("<input type=\"text\" name=\"riga3\" maxlength=\"20\" autocomplete=off> <br>");
client.println("<input type=\"text\" name=\"riga4\" maxlength=\"20\" autocomplete=off> <br>");
client.println("Suona? Si<input type=radio name=\"suona\" value=\"1\"> No<input type=radio name=\"suona\" value=\"0\" checked> <br>");
client.println("<input type=\"submit\" value=\"Invia messaggio\">");
client.println("</form>");
client.println("</BODY>");
client.println("</HTML>");
}
else{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
client.println("<HTML>");
client.println("<HEAD>");
client.println("<TITLE>Messaggi su display LCD</TITLE>");
client.println("</HEAD>");
client.println("<BODY>");
//client.println("<META HTTP-EQUIV=\"REFRESH\" CONTENT=0; URL=/>");
client.println("<H1>Messaggio inviato con successo</H1>");
client.println("<a href=\"/\">Torna indietro</a>");
client.println("</BODY>");
client.println("</HTML>");
}
client.stop();
if(lettura.indexOf("?") > 0){
dividirighe();
mostradisplay();
if(suona == "1"){
new_message_alert();
}
}
lettura = "";
}
}
}
}
}
void dividirighe(){
//Sostituisci caratteri HTML
lettura.replace("+", " ");
lettura.replace("%21", "!");
lettura.replace("%3F", "?");
lettura.replace("%27", "'");
lettura.replace("%2C", ",");
lettura.replace("%3A", ":");
lettura.replace("%3B", ";");
lettura.replace("%28", "(");
lettura.replace("%29", ")");
lettura.replace("%2F", "/");
lettura.replace("%5C", "\\");
lettura.replace("%2B", "+");
lettura.replace("%3D", "=");
riga1 = lettura.substring(lettura.indexOf("riga1=")+6, lettura.indexOf("&riga2"));
delay(5);
riga2 = lettura.substring(lettura.indexOf("riga2=")+6, lettura.indexOf("&riga3"));
delay(5);
riga3 = lettura.substring(lettura.indexOf("riga3=")+6, lettura.indexOf("&riga4"));
delay(5);
riga4 = lettura.substring(lettura.indexOf("riga4=")+6, lettura.indexOf("&suona"));
delay(5);
suona = lettura.substring(lettura.indexOf("suona=")+6, lettura.indexOf("HTTP")-1);
delay(5);
Serial.println("---------------------------------------");
Serial.print("Riga1: ");
Serial.println(riga1);
Serial.print("Riga2: ");
Serial.println(riga2);
Serial.print("Riga3: ");
Serial.println(riga3);
Serial.print("Riga4: ");
Serial.println(riga4);
Serial.print("Suona: ");
Serial.println(suona);
Serial.println("---------------------------------------");
}
void mostradisplay(){
lcd.clear();
lcd.setCursor(0,0);
lcd.print(riga1);
lcd.setCursor(0,1);
lcd.print(riga2);
lcd.setCursor(0,2);
lcd.print(riga3);
lcd.setCursor(0,3);
lcd.print(riga4);
}
void new_message_alert(){
//Al pin 3 va inserito uno speaker
tone(3, 131,150);
delay(150);
tone(3, 147,150);
delay(150);
tone(3, 131,150);
delay(150);
tone(3, 147,150);
delay(150);
tone(3, 131,150);
delay(150);
tone(3, 147,250);
delay(250);
}
Le funzioni principali sono, ovviamente setup() e loop() che sono native per l’inizializzazione e il loop principale di arduino, dividirighe(), mostradisplay() e new_message_alert().
Dopo aver effettuato l’inclusione delle librerie e le inizializzazioni di quest’ultime siam passati alla dichiarazioni delle variabili per il programma e poi l’inizializzazione dell’ethernet shield, del display e dei pin (in questo caso viene dichiarato come pin di uscita il pin n° 3 che viene collegato ad un cicalino).
La prima parte di codice nel loop principale serve per ricevere le richieste dal browser, i caratteri vengono ricevuti ad uno ad uno quindi una variabile char si occupera di riceverli ed una stringa di concatenarli.
if(client){
while (client.connected()){
if (client.available()){
char c = client.read();
lettura.concat(c);
Serial.print(c);
}
}
}
Nel programma ho inserito il comando “Serial.print(c)” che mostra sul serial monitor i dati ricevuti per verificare il corretto funzionamento.
Ecco la stringa ricevuta per visualizzare il messaggio dell’immagine sopra:
GET /?riga1=Ecco&riga2=una&riga3=prova%21&riga4=&suona=1 HTTP/1.1
“GET” identifica il tipo di richiesta.
Successivamente si possono leggere i dati ognuno dopo il nome della variabile nella quale verranno successivamente immagazinate.
E per finere “HTTP/1.1″ indica il tipo di protocollo utilizzato.
Successivamente un banalissimo controllo cerca il carattere di fine riga per poter rispondere:
if (c == '\n'){
...
}
Un ulteriore controllo verifica la pagina di provenienza, ovvero, se il messaggio è già stato spedito restituisce una pagina con un messaggio di conferma altrimenti restituisce il modulo per l’invio del messaggio.
Passiamo alle altre funzioni; la prima è dividirighe().
dividirighe() si occupa di “elaborare” il messaggio ricevuto. I caratteri come lo spazio, il punto esclamativo/interrogativo, parentesi, punti, virgole vengono inviate tramite codice html non così come le visualizziamo, per questo la prima parte di questa funzione si occupa di sostituire il codice html nel corrispondente simbolo grafico:
//Sostituisci caratteri HTML
lettura.replace("+", " ");
lettura.replace("%21", "!");
lettura.replace("%3F", "?");
lettura.replace("%27", "'");
lettura.replace("%2C", ",");
lettura.replace("%3A", ":");
lettura.replace("%3B", ";");
lettura.replace("%28", "(");
lettura.replace("%29", ")");
lettura.replace("%2F", "/");
lettura.replace("%5C", "\\");
lettura.replace("%2B", "+");
lettura.replace("%3D", "=");
Successivamente ogni riga deve essere “presa” e inserita nella variabile che poi andrà scritta sul display, ecco come:
riga1 = lettura.substring(lettura.indexOf("riga1=")+6, lettura.indexOf("&riga2"));
delay(5);
riga2 = lettura.substring(lettura.indexOf("riga2=")+6, lettura.indexOf("&riga3"));
delay(5);
riga3 = lettura.substring(lettura.indexOf("riga3=")+6, lettura.indexOf("&riga4"));
delay(5);
riga4 = lettura.substring(lettura.indexOf("riga4=")+6, lettura.indexOf("&suona"));
delay(5);
suona = lettura.substring(lettura.indexOf("suona=")+6, lettura.indexOf("HTTP")-1);
delay(5);
E’ facile capire che l’ultima variabile contiene il valore di controllo per il cicalino, se il suo valore è “1″ il cicalino deve suonare altrimenti se il suo valore è “0″ non deve suonare.
Vengono inserite anche nella funzione dividirighe() alcune righe che mostrano sul serial monitor il risultato delle operazioni precedentemente svolte:
Serial.println("---------------------------------------");
Serial.print("Riga1: ");
Serial.println(riga1);
Serial.print("Riga2: ");
Serial.println(riga2);
Serial.print("Riga3: ");
Serial.println(riga3);
Serial.print("Riga4: ");
Serial.println(riga4);
Serial.print("Suona: ");
Serial.println(suona);
Serial.println("---------------------------------------");
Ed ecco cosa viene fuori sul serial monitor prendendo come esempio sempre la stessa immagine inserita a inizio post:
—————————————
Riga1: Ecco
Riga2: una
Riga3: prova!
Riga4:
Suona: 1
—————————————
Passiamo alla prossima funzione; mostradisplay().
void mostradisplay(){
lcd.clear();
lcd.setCursor(0,0);
lcd.print(riga1);
lcd.setCursor(0,1);
lcd.print(riga2);
lcd.setCursor(0,2);
lcd.print(riga3);
lcd.setCursor(0,3);
lcd.print(riga4);
}
Com’è facile capire questa funzione si occupa del display lcd, ovvero lo “pulisce” e mostra il contenuto delle stringhe che contengono il messaggio ricevuto.
E per finire l’ultima funzione; new_message_alert();
void new_message_alert(){
//Al pin 3 va inserito uno speaker
tone(3, 131,150);
delay(150);
tone(3, 147,150);
delay(150);
tone(3, 131,150);
delay(150);
tone(3, 147,150);
delay(150);
tone(3, 131,150);
delay(150);
tone(3, 147,250);
delay(250);
}
Questa si occupa semplicemente di generare delle frequenze sul piedino 3 (alla quale ricordo che va collegato un cicalino).
Concludo questo articolo dicendo che uno dei probabili prossimi progetti con l’ethernet shield potrebbe essere il controllo di posizione (asse x e y) di una ip-cam. Non posso però promettere niente. :D
P.S.
Ho dimenticato di aggiungere una cosa importante:
La pagina web è una pagina interna alla rete ove viene collegata l’ethernet shield.
Per potervi accedere anche esternamente è necessario inserire nel browser l’indirizzo ip esterno della rete, la porta scelta alla quale viene collegata l’ethernet shield e fare il port forwarding nelle configurazioni del router.
Per evitare di mostrare il proprio indirizzo ip si possono utilizzare servizi come NO-IP che permettono di assegnare un indirizzo statico ad un ip dinamico.
Banca dati, Arduino & EEPROM <-> PC
0
Nell’articolo precedente scrissi che avrei trattato come prossimo argomento l’Arduino Ethernet Shield, purtroppo a causa degli scioperi dei mezzi in tutta Italia, il pacco che mi sarebbe dovuto arrivare in tre giorni, è arrivato dopo ben due settimane (è arrivato proprio oggi!), così ho avuto modo di realizzare un piccolo progetto che avevo in mente già da parecchio tempo!
Una specie di banca dati, o registratore di cassa, insomma, qualcosa che mi ricordi quanti soldi ho nel salvadanaio, ricordandomi anche le date dei prelievi o depositi; Così è nato il programma “Banca Dati”.
Il programma consiste nel far comunicare il computer tramite linguaggio di programmazione C#, con l’arduino che scrive i dati da registrare/leggere su un EEPROM I2C (vedi articolo passato: Data Logger).
Ecco un screen dell’interfaccia grafica:

A prima vista può sembrare un programma molto semplice ma non è del tutto così, la parte più complicata è stata la divisione dei dati per poterli salvare sull’EEPROM.
Spiego in due parole com’è strutturata la memoria dell’EEPROM.
I primi due byte (0 e 1) sono dedicati alla variabile N° di dati in memoria, ovvero, questa variabile contiene il numero di dati salvati in memoria (lo stesso numero che compare sull’interfaccia grafica sulla parte destra sopra il pulsante “Cancella Dati”).
I seguenti byte sono divisi in righe da 7 Byte; dunque è facile calcolare il n° di record che si possono inserire ([32K - 2] / 6 = 5333) :
Byte 0: data_gg -> Il valore numerico del giorno.
Byte 1: data_mm -> Il valore numerico del mese.
Byte 2: data_yy -> Il valore numero dell’anno (vengono omesse le prime due cifre dell’anno).
Byte 3,4,5,6 -> Contengono i 4 byte che costituiscono un dato float.
Ecco il programma per l’arduino:
/*Si vuole realizzare una banca dati interfacciata al computer tramite comunicazione seriale (USB)
che permette di registrare dei record su un EEPROM I2C con la possibilità di ricevere e leggere i dati al computer.
*/
#include <Wire.h> //I2C library
//Funzioni che permettono di leggere/scrivere sull'EEPROM----------------------------------
void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
int rdata = data;
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.write(rdata);
Wire.endTransmission();
}
byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
byte rdata = 0xFF;
Wire.beginTransmission(deviceaddress);
Wire.write((int)(eeaddress >> 8)); // MSB
Wire.write((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,1);
if (Wire.available()) rdata = Wire.read();
return rdata;
}
//Fine funzioni che permettono di leggere/scrivere sull'EEPROM------------------------------
//Funzione per scomporre una variabile FLOAT in 4 Byte--------------------------------------
union SCOMP_FLOAT
{
float MyFloat; //Per scomporre una variabile float bisogna assegnare a S_FLOAT.MyFloat il valore desiderato
char byte_s[4]; //e recuperare i valore dai byte S_FLOAT.byte_s[n] dove n è il numero di byte che va da 0 a 3
}
S_FLOAT; //Processo inverso per ricomporre la variabile float
//Fine funzione di divisione float-----------------------------------------------------------
/* Unione e divisione Byte (per int)
somma = (b << 8) | a; Si uniscono MSB (b) ed LSB (a)
//Si divide
a = somma; LSB
b = somma >> 8; MSB
*/
//Variabili di data
byte data_gg = 0;
byte data_mm = 0;
byte data_yy = 0;
//Variabile per l'inserimento del valore
float soldi = 0;
float totale = 0;
//Primi 2 Byte dell'EEPROM che contengono il numero di dati
int datiscritti = 0;
byte datiscrittiLSB = 0;
byte datiscrittiMSB = 0;
int mode = 0; //Dato ricevuto dal pc per decidere se leggere o scrivere
int indirizzo = 2; //Indirizzo di EEPROM; Parte da due perchè i primi due BYTE sono per la memorizzazioni del N° scritture;
void setup()
{
Wire.begin();
Serial.begin(9600);
}
void loop(){
//Ricezione modalità: Lettura o scrittura--------
while (Serial.available() <= 0){
} // Attendi dato
int lettura = Serial.read();
if(lettura == 'w')
mode = 1;
else if (lettura == 'r')
mode = 0;
else if (lettura == 'e')
mode = 2;
//Fine ricezione modalità------------------------
//Fase di lettura--------------------------------
if (mode == 0){
erasevar(); //Chiama funzione di reinizializzazioni variabili
//Leggo il numero di dati scritti sull'EEPROM
datiscrittiMSB = i2c_eeprom_read_byte(0x50, 0);
delay(5);
datiscrittiLSB = i2c_eeprom_read_byte(0x50, 1);
delay(5);
datiscritti = (datiscrittiMSB << 8) | datiscrittiLSB;
//Fine lettura di n° dati scritti sull'EEPROM
Serial.println(datiscritti); //Invio numero dati sull'EEPROM
//Inizio lettura dei dati
for(int i = 1; i <= datiscritti; i++){
data_gg = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
data_mm = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
data_yy = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
S_FLOAT.byte_s[3] = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
S_FLOAT.byte_s[2] = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
S_FLOAT.byte_s[1] = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
S_FLOAT.byte_s[0] = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
soldi = S_FLOAT.MyFloat;
totale += soldi;
Serial.println(data_gg);
Serial.println(data_mm);
Serial.println(data_yy);
Serial.println(soldi);
}
//Fine lettura dei dati
Serial.println(totale);
}
//Fine fase di lettura---------------------------
//Fase di scrittura------------------------------
else if (mode == 1){
erasevar(); //Chiama funzione di reinizializzazioni variabili
//Leggo il numero di dati scritti sull'EEPROM
datiscrittiMSB = i2c_eeprom_read_byte(0x50, 0);
delay(5);
datiscrittiLSB = i2c_eeprom_read_byte(0x50, 1);
delay(5);
datiscritti = (datiscrittiMSB << 8) | datiscrittiLSB;
//Fine lettura di n° dati scritti sull'EEPROM
while (Serial.available() <= 0){
} // Attendi dato
//Ricevo i dati
data_gg = Serial.read();
delay(5); //Pausa di attesa dato
data_mm = Serial.read();
delay(5); //Pausa di attesa dato
data_yy = Serial.read();
delay(5); //Pausa di attesa dato
S_FLOAT.byte_s[0] = Serial.read();
delay(5); //Pausa di attesa dato
S_FLOAT.byte_s[1] = Serial.read();
delay(5); //Pausa di attesa dato
S_FLOAT.byte_s[2] = Serial.read();
delay(5); //Pausa di attesa dato
S_FLOAT.byte_s[3] = Serial.read();
delay(5);
//Fine ricezione dati
indirizzo = (datiscritti * 7) + 2; //Trovo l'indirizzo di partenza
//Li scrivo sull'EEPROM---------------------------------
i2c_eeprom_write_byte(0x50, indirizzo, data_gg);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, data_mm);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, data_yy);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, S_FLOAT.byte_s[3]);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, S_FLOAT.byte_s[2]);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, S_FLOAT.byte_s[1]);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, S_FLOAT.byte_s[0]);
delay(5);
indirizzo++;
//Fine scrittura dati---------------------------------
//Aggiorno la variabile datiscritti sull'EEPROM----------
datiscritti++;
datiscrittiLSB = datiscritti;
datiscrittiMSB = datiscritti >> 8;
i2c_eeprom_write_byte(0x50, 0, datiscrittiMSB);
delay(5);
i2c_eeprom_write_byte(0x50, 1, datiscrittiLSB);
delay(5);
//Fine aggiornamento variabile datiscritti---------------
}
//Fine fase di scrittura-------------------------
//Cancellamento dati------------------------------
else if (mode == 2){
i2c_eeprom_write_byte(0x50, 0, 0);
delay(5);
i2c_eeprom_write_byte(0x50, 1, 0);
delay(5);
}
//Fine cancellamento dati---------------------------
delay(25);
}
void erasevar(){
//Azzero variabili
indirizzo = 2; //Parte da due perchè i primi due BYTE sono per la memorizzazioni del N° scritture;
data_gg = 0;
data_mm = 0;
data_yy = 0;
soldi = 0;
totale = 0;
datiscritti = 0;
datiscrittiLSB = 0;
datiscrittiMSB = 0;
}
Ecco il link per il download del programma: http://www.fileserve.com/file/yGHyfyF/Banca dati.rar
Devo fare anche qualche piccola precisazione, gli elementi, una volta letti, non vengono ordinati per data ma semplicemente per ordine di inserimento, devo anche anche aggiungere che non ho inserito alcun tipo di controllo sui TextBox dunque eventi come l’inserimento di lettere al posto della data possono generare errori nel programma.
P.S.
Non mi è possibile rendere pubblici tutti i file di codice sorgente del programma in C#.
Ordinata Arduino Ethernet Shield
0
Dopo parecchio dall’apertura dell’ Arduino Store ho finalmente deciso di fare un acquisto su quest’ultimo!
E’ parecchio che non realizzo un progetto con l’Arduino dunque ho deciso di ordinare un Ethernet Shield al modico prezzo (non tanto poi) di 29,00€ + 9,00€ di spedizione + 7,77€ di IVA (21%, poveri noi!) per un totale di 45,77€.

Beh, qual’è il progetto vi starete chiedendo?
In poche parole questa Ethernet Shield mi permette di collegare il mio Arduino UNO alla rete LAN di casa e controllare quest’ultimo tramite una pagina web. Sembra una cosa banale invece e tutt’altro.
Basti pensare alla possibilità di poter inviare valori ad o da una pagina web che può essere visitata da un pc, un tablet o uno smartphone in qualsiasi punto del mondo (ovviamente creando un ponte fra la rete locale di casa e la rete esterna).
Il primo progetto sarà sicuramente una cosa banalissima, il controllo di uno o più led collegati all’Arduino.
Concludo il post dicendo che si aprono nuove strade, chissà cosa mi verrà in mente.
Alla prossima!
Manipolazione delle porte, ATMega328
0
Tutti gli articoli di programmazione che ho pubblicato fin ora sono stati in linguaggio ad alto livello, quale il C. Un linguaggio ad alto livello generalmente “aiuta” molto il programmatore che tramite funzioni può gestire tutto il processore senza badare ai registri e a tutto ciò che si trova “dentro” il processore.
A scuola utilizzando un processore della Scenix chiato SX28 (molto somigliante al processore dell’Arduino, ATMega328) ho imparato qualcosa del linguaggio basic per la programmazione.
Il basic non è un linguaggio ad alto livello e quindi per la gestione di parti come ad esempio impostare un pin di uscita come input/output oppure impostare il valore logico di un piedino è necessario conoscere il registro (e di conseguenza il bit) che controlla la direzione di quel pin (come detto prima in/out) e il valore.
Sia nello SX28 che nell’ATMega328 esistono tre PORT, ovvero 3 registri che si occupano della gestione dei pin.
Questi port per lo scenix sono: PORTA (registro a 4 bit), PORTB e PORTC (enrambi a 8 bit).
Mentre per l’ATMega328 sono: PORTD (che gestisce i pin digital da 0 a 7), PORTB (che gestisce i pin digitali da 8 a 13 e i pin del quarzo) e PORTC (che gestisce i pin analogici da 0 a 5).
Facciamo un esempio, per impostare come uscita il pin 0 legato al PORT B, nello Scenix si deve proseguire così:
label PIN PORTB.0 OUTPUT
E per scrivere un valore logico alto:
HIGH label
Mentre con l’arduino, in C:
label = 8; //Nell'ATMega328 il bit 0 del PORTB è collegato al pin digitale 8 pinMode(label, OUTPUT); //Imposto il pin come uscita digitalWrite(label, HIGH); /*Scrivo un valore alto sulla porta. Non è necessario specificare una label per il pin, avrei potuto anche inserire direttamente "8" */
Però è anche possibile scrivere comandi in stile basic:
DDRB = 0b00000001; 'Imposto come uscita il pin, ' è possibile anche scrivere in esadecimale: 0x01
PORTB = 0b00000001 'Scrivo un valore alto sul pin.
Il registro DDRB o Data Direction B è il registro che si occupa della gestione della “direzione” dei pin:
Zero (0) sta per input e Uno (1) sta per output.
Il registro PORTB invece si occupa del valore presente sui pin, è possibile sia leggerlo (nel caso un pin sia configurato come ingresso) che scriverlo (nel caso il pin sia configurato come output).
Di gran lunga è più facile operare in C, anche per il semplice motivo che se si dovesse operare con il basic si dovrebbero conoscere almeno le basi delle “matematica dei bit“.
Anche se programmare in basic ha i suoi vantaggi in quanto è più rapido e si possono svolgere funzioni che richiederebbero più linee di programmazione in C.
Light Blue Led
0
Sono passato oggi, dopo parecchio tempo, dal negozio di elettronica ed ho comprato un paio di led blue (caspita costano 0.90€ a pezzo) ed ho realizzato un altro progettino di led a scorrimento! Ecco il video:
Ecco un piccolo schemino:

Ed ecco il codice sorgente:
const int datapin = 3; //Pin di serial out
const int clockpin = 2; //Pin di clock
const int catodo = 5;
void setup(){
pinMode(datapin, OUTPUT);
pinMode(clockpin, OUTPUT);
pinMode(catodo, OUTPUT);
digitalWrite(catodo, HIGH);
}
byte numero = B00000001;
int indice = 0;
void loop(){
while (numero != 128){
shiftOut(datapin, clockpin, LSBFIRST, numero);
for(indice = 0; indice < 256; indice++){
analogWrite(catodo, indice);
delay(1);
}
for(indice = 256; indice > 0; indice--){
analogWrite(catodo, indice);
delay(1);
}
numero = numero << 1;
}
while (numero != 1){
shiftOut(datapin, clockpin, LSBFIRST, numero);
for(indice = 0; indice < 256; indice++){
analogWrite(catodo, indice);
delay(1);
}
for(indice = 256; indice > 0; indice--){
analogWrite(catodo, indice);
delay(1);
}
numero = numero >> 1;
}
}
Nello schema non si nota, ma la massa del regolatore di tensione (7805) e quella dell’arduino (che è alimentato tramite USB) devono essere collegate insieme.
Il transistor utilizzato è un TIP31 che supporta fino a 3A sul colletore.
Data Logger con Arduino ed EEPROM 24LC256
0
Ieri finalmente, dopo parecchio tempo, mi sono deciso a realizzare un progettino con il mio Arduino UNO, si tratta di un Data Logger:
un circuito che campiona un dato e lo salva su un E2PROM.
L’E2PROM in questione è la 24LC256 che ho ricevuto nel mio ultimo ordine dalla SparkFun Electronics, sfrutta un protocollo seriale quale l’i2c per comunicare con l’arduino; Non ho trovato una libreria per gestire le operazioni di scrittura e lettura, ma sul playground di arduino si può trovare un codice che presenta delle funzioni per scrivere e leggere sull’EEPROM: http://www.arduino.cc/playground/Code/I2CEEPROM.
L’E2PROM può memorizzare dati fino ad un massimo di 32Kbyte, ma non li sfrutteremo tutti.
In sostanza, si collega l’arduino al computer, si apre il monitor seriale e ci viene chiesto se leggere o scrivere (r\w) sull’eeprom, nel caso della scrittura il programma effettua delle letture analogiche sul pin A0 e ogni 10ms salva sulla eprom dei record formati da 3 dati: int N° Lettura, int Lettura e int Sec (millis() al momento della lettura).
Sappiamo che ogni int occupa 2 byte ed è per questo che divideremo ogni dato in due parti: MSB ed LSB.
Adesso sappiamo che ogni record occuperà 6 Byte sulla nostra memoria. Di seguito un immagine che mostra il concetto:

I collegamenti da effettuare sono scritti anche sulla pagina del playground arduino:
Arduino pin 4 to EEPROM pin 5
Arduino pin 5 to EEPROM pin 6
Arduino 5V to EEPROM pin 8
Arduino GND to EEPROM pin 1,2,3,4
Di seguito il codice sorgente:
#include <Wire.h> //I2C library
void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
int rdata = data;
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddress >> 8)); // MSB
Wire.send((int)(eeaddress & 0xFF)); // LSB
Wire.send(rdata);
Wire.endTransmission();
}
byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
byte rdata = 0xFF;
Wire.beginTransmission(deviceaddress);
Wire.send((int)(eeaddress >> 8)); // MSB
Wire.send((int)(eeaddress & 0xFF)); // LSB
Wire.endTransmission();
Wire.requestFrom(deviceaddress,1);
if (Wire.available()) rdata = Wire.receive();
return rdata;
}
/* Unione e disione Byte
somma = (b << 8) | a; Si uniscono MSB (b) ed LSB (a)
//Si divide
a = somma; LSB
b = somma >> 8; MSB
*/
int no_lettura = 0;
int lettura = 0;
int sec = 0;
byte no_letturaMSB = B00000000;
byte no_letturaLSB = B00000000;
byte letturaMSB = B00000000;
byte letturaLSB = B00000000;
byte secMSB = B00000000;
byte secLSB = B00000000;
int mode = 0; //0 = Leggi; 1 = Scrivi;
void setup()
{
Wire.begin(); // initialise the connection
Serial.begin(9600);
pinMode(A0, INPUT);
Serial.print("Avvio del programma");
}
long wait = 0;
int indirizzo = 0;
void loop()
{
chiedi();
if (mode == 1){
Serial.println("Inizio scrittura");
for(no_lettura = 0; no_lettura <= 30;){
//Se le letture sono inferiori a 30 deve continuare a scrivere l'eeprom
if (wait < millis()){
wait = millis() + 10;
//Divido i dati
sec = millis();
secLSB = sec;
secMSB = sec >> 8;
lettura = analogRead(A0);
letturaLSB = lettura;
letturaMSB = lettura >> 8;
no_letturaLSB = no_lettura;
no_letturaMSB = no_lettura >> 8;
//Scrivo sull'EEPROM; i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data )
i2c_eeprom_write_byte(0x50, indirizzo, no_letturaMSB);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, no_letturaLSB);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, letturaMSB);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, letturaLSB);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, secMSB);
delay(5);
indirizzo++;
i2c_eeprom_write_byte(0x50, indirizzo, secLSB);
delay(5);
indirizzo++;
Serial.print("\tLettura no: ");
Serial.print(no_lettura);
Serial.print("\tLettura: ");
Serial.print(lettura);
Serial.print("\tSec: ");
Serial.println(sec);
no_lettura++;
}
}
mode = 2;
}
else if(mode == 0){
//Se le letture sono 30 legge dall'eeprom
Serial.println("Inizio lettura");
//Reset variabili
indirizzo = 0;
no_letturaMSB = B00000000;
no_letturaLSB = B00000000;
letturaMSB = B00000000;
letturaLSB = B00000000;
secMSB = B00000000;
secLSB = B00000000;
delay(5);
//Leggo dall'EEPROM; i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress )
for(int i = 0; i <= 30; i++){
no_letturaMSB = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
no_letturaLSB = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
letturaMSB = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
letturaLSB = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
secMSB = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
secLSB = i2c_eeprom_read_byte(0x50, indirizzo);
delay(5);
indirizzo++;
no_lettura = (no_letturaMSB << 8) | no_letturaLSB;
lettura = (letturaMSB << 8) | letturaLSB;
sec = (secMSB << 8) | secLSB;
Serial.print("\tLettura no: ");
Serial.print(no_lettura);
Serial.print("\tLettura: ");
Serial.print(lettura);
Serial.print("\tSec: ");
Serial.println(sec);
}
mode = 2;
}
}
void chiedi() {
Serial.println("\n\nLeggi o Scrivi? (r\\w)");
while (Serial.available() <= 0){}
if(Serial.read() == 'w')
mode = 1;
else
mode = 0;
}
C’è un piccolo accorgimento da fare riguardante il dato Sec: ho già detto prima che quel dato in sostanza fa lo stamp dei millisecondi passati dall’accensione del microprocessore. La funzione millis() restituisce un dato long, ma noi immagazziniamo il valore in un int per questione di comodità, con un int possiamo raggiungere un valore massimo di (2^16) – 1 = 65535 che in secondi corrisponde a circa 65 secondi, dunque dopo 65 secondi la variabile sec va in overflow memorizzando il valore massimo (come detto prima 65535). Per risolvere si potrebbe, anzichè salvare i millisecondi trascorsi dall’accensione del microprocessore, i secondi:
sec = millis() / 1000;
Arduino & GLCD, grafico di lettura analogica
0
Come ho già detto nell’articolo precedente, ieri mi son finalmente arrivati i componenti che avevo ordinato dalla SparkFun Electronics, fra questi c’era un display grafico 128 x 64 (http://www.sparkfun.com/products/710).
Ho così realizzato un semplice programmino che effettua una lettura analogica sul pin A5 e mostra il risultato su un grafico. Tutto questo è stato possibile grazie alla libreria grafica KS0108 (http://www.arduino.cc/playground/Code/GLCDks0108).
Di seguito il video:
Come al solito il video non è dei migliori, prima o poi mi deciderò a comprare una videocamera come si deve.
Ecco il codice sorgente:
#include <ks0108.h> // library header
#include <ks0108_Arduino.h>
#include <Arial14.h> // font definition for 14 point Arial font.
#include "SystemFont5x7.h" // system font
void setup(){
GLCD.Init(NON_INVERTED);
GLCD.ClearScreen();
GLCD.SelectFont(System5x7);
pinMode(A5, INPUT);
splashscreen();
delay(1000);
drawaxis();
}
long wait = 0;
int x = 1; //Parte da uno perchè il primo pixel è occupato dall'asse orizzontale
int y = 0;
int ar = 0;
void loop(){
if(wait < millis()){
wait = millis() + 100;
ar = analogRead(A5);
y = map(ar, 0, 1023, 49, 0);
GLCD.SetDot(x,y,BLACK);
x++;
GLCD.FillRect(1,51,125,14, WHITE);
GLCD.GotoXY(1,61);
GLCD.Puts("Y: ");
GLCD.PrintNumber(y);
}
if (x > 127){
x = 1;
drawaxis();
}
}
void splashscreen(){
//SplashScreen iniziale
GLCD.DrawRoundRect(0,0,127,63,5,BLACK);
GLCD.GotoXY(30,2);
GLCD.Puts("Xfox's Blog");
GLCD.GotoXY(32,22);
GLCD.Puts("www.xfox.it");
}
void drawaxis(){
GLCD.ClearScreen();
GLCD.DrawVertLine(0,0,63,BLACK); //Disegno linea verticale
GLCD.DrawHoriLine(0,50,128,BLACK); //Disegno linea orizzontale
}
In totale vengono effettuate 126 letture (una ogni 100ms) prima che il grafico si resetti.
Si può notare che poco prima del pezzo ove viene comandato di scrivere il valore di Y c’è un comando che disegna un rettangolo bianco.
GLCD.FillRect(1,51,125,14, WHITE);
In sostanza ogni volta prima di riscrivere la stringa “Y: n” quella zona viene “imbiancata”, ovvero tutti i pixel vengono spenti per essere riscritti senza sovrascrivere la stringa scritta nel ciclo precedente.
Per quanto riguarda i collegamenti, sono molto semplici, basta seguire la guida della libreria KS0108 (http://www.arduino.cc/playground/Code/GLCDks0108) e il datasheet del display (http://www.sparkfun.com/datasheets/LCD/GDM12864H.pdf).
Secondo ordine dalla SparkFun Electronics
1Verso marzo avevo fatto il mio primo ordine sul sito della SparkFun Electronics per un totale di 108,40€ + 32€ di dogana (Ordine moduli xBee e varie), oggi ho effettuato il secondo per un totale di 76,45€ ordinando un display grafico LCD, qualche ATMega328 e ATtiny85, un padio di EEPROM I2C e altre cosuccie.
Ecco uno stamp dell’ordine:

Inizialmente ero partito con l’idea di ordinare semplicemente il display grafico ed il display 16×2 (dopo aver bruciato quello che ho già), ma si sa, la fame vien mangiando, allora gironzolando per il sito mi son detto, ma perchè non ordinare qualche ATMega328 (dato che uno costa circa 3€ mentre in italia costa circa 7€), poi ho visto anche questi ATtiny85 che sono dei piccoli microcontrollori prodotti dall’ATMel che costano davvero pochissimi e sono programmabili tramite la board e l’ide Arduino.
Sempre gironzolando ho trovato anche un piccolo telecomandino ad infrarossi che costa poco meno di 3€ e così mi sono detto, “Ma si! Prendiamo anche questo!” e di conseguenza anche i due ricevitori ad infrarossi!
Poi ho sempre desiderato creare una specie di barriera laser e così ho ordinato anche il modulo laser.
Per quanto riguarda le EEPROM, beh, fa sempre comodo averne qualcuna a portata di mano!
Ecco tutto, adesso non rimane che attendere per realizzare qualche nuovo progetto!
Arduino & C#, letture analogiche
3
Ultimamente ho rivisto alcuni programmini in processing che feci per far comunicare l’arduino al pc tramite porta seriale, l’interfaccia grafica si presentava un po scarna, ed io essendo un utente windows preferisco avere un interfaccia grafica in stile windows, così ho rispolverato un vecchio libro di C# (esattamente Visual C# 2005 Passo per Passo – John Sharp) e ho deciso di cominciare a lavorare un pochino.
Come primo programma ho realizzato un controllo per un servomotore, ma non è di questo che parleremo, come secondo progetto ho invece fatto qualcosa che riceva dati dall’arduino (si, perchè il controllo del servomotore si occupava semplicemente di inviare dati all’arduino), in poche parole, l’arduino invia tramite USB tre letture analogiche, il software in C# le interpreta e visualizza il valore su tre TextBox e su tre ProgressBar.
Ecco un’immagine:

Ed ecco il codice sorgente per l’arduino:
void setup(){
Serial.begin(9600);
pinMode(A0, INPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
}
void loop(){
if (Serial.available() > 0){
if(Serial.read() == '1'){
Serial.println(analogRead(A0));
Serial.println(analogRead(A1));
Serial.println(analogRead(A2));
}
}
}
Come si può notare è molto semplice, non è questa la parte difficile da comprendere. :)
Il software invia all’arduino il carattere “1″ ogni 250 ms che viene interpretato come richiesta dati.
Ecco il link per il download del programma da me realizzato: http://www.megaupload.com/?d=X9A2UW91
Controllo di un servomotore tramite tastiera PS2 con Arduino
0
Tramite la libreria “PS2KeyBoard” per arduino è possibile ricevere i dati da una comune tastiera per computer PS2, così tramite questa libreria ho fatto in modo di controllare un servomotore con i tasti direzionali.
Il link che porta al playground di arduino è il seguente: http://www.arduino.cc/playground/Main/PS2Keyboard, tuttavia per scaricare l’ultima versione della libreria è necessario seguire questo link: http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html.
I collegamenti da effettuare sono molto semplici e sono mostrati in un immagine nel precedente link, ma che riporto di seguito:

Se non disponete di un connettore, come nel mio caso, basta semplicemente comprare una prolunga PS2 (potrà costare al massimo 3€), tagliare la parte maschio del connettore, spellare i fili e verificarli tramite una resistenza e un multimetro.
Video:
Ecco il codice sorgente:
#include <PS2Keyboard.h>
#include <Servo.h>
const int DataPin = 4;
const int IRQpin = 3;
PS2Keyboard keyboard;
Servo servo;
int pos = 90;
int passo = 10;
long wait = 0;
void setup() {
delay(1000);
keyboard.begin(DataPin, IRQpin);
Serial.begin(9600);
Serial.println("Controllo Servo tramite tastiera PS2:");
servo.attach(5);
servo.write(pos);
}
void loop() {
if (keyboard.available()) {
// Leggo il valore ricevuto dalla tastiera
char c = keyboard.read();
// Controllo fra i tasti speciali (Es. BKSP, DEL, ESC)
if (c == PS2_LEFTARROW) {
Serial.print("[Left]");
pos -= passo;
}
else if (c == PS2_RIGHTARROW) {
Serial.print("[Right]");
pos += passo;
}
else if (c == PS2_UPARROW) {
Serial.print("[Up]");
passo += 10;
}
else if (c == PS2_DOWNARROW) {
Serial.print("[Down]");
passo -= 10;
}
else {
// Altrimenti mostro il carattere
Serial.print(c);
}
if (pos > 180)
pos = 180;
if(pos < 0)
pos = 0;
Serial.println();
Serial.println("--------------------------");
Serial.print("Posizione servo: ");
Serial.print(pos);
Serial.print("\tPasso: ");
Serial.println(passo);
Serial.println("--------------------------");
}
if (wait < millis()){
wait = millis() + 50;
servo.write(pos);
}
}
Come si può notare dal codice, tramite le frecce direzionali SU e GIU’ è possibile aumentare o decrementare (+10/-10) la variabile passo ovvero l’incremento/decremento che daremo alla variabile pos (posizione del servomotore) una volta premute le frecce direzionali DESTRA/SINISTRA.




