Documente Academic
Documente Profesional
Documente Cultură
ro
L9
Senzori Atmosferici
Presiune Atmosferica BMP085
Senzorul BMP085 este un senzor foarte precis produs de firma Bosch, capabil sa masoare
presiunea atmosferica si temperatura. Cum presiunea atmosferica variaza cu altitudinea, pe baza
presiunii atmosferice masurate se poate calcula si altitudinea (lucru foarte util la drone si alte dispozitive
zburatoare). Conectarea senzorului la Arduino se face prin I2C, astfel ca avem nevoie de doar doi pini
(in afara celor doi pini de alimentare). Pentru a citi valorile senzorului recomand o librarie open-source,
disponibila aici : http://www.robofun.ro/senzor_presiune_bmp085 (primul link, "Librarie Arduino").
Dupa instalarea librariei, codul sursa este extrem de simplu, ca mai jos.
Arduino 3.3 V
BMP085 VCC
Arduino GND
BMP085 GND
Arduino SDA
BMP085 SDA
Arduino SCL
BMP085 SCL
http://www.robofun.ro/forum
http://www.robofun.ro
L9
#include <Wire.h>
#include <BMP085.h>
BMP085 dps = BMP085();
long Temperature = 0, Pressure = 0, Altitude = 0;
void setup(void) {
Serial.begin(9600);
Wire.begin();
delay(1000);
dps.init();
delay(5000);
}
void loop(void) {
dps.getTemperature(&Temperature);
dps.getPressure(&Pressure);
dps.getAltitude(&Altitude);
Serial.print("Temp(C):");
Serial.print(Temperature);
Serial.print(" Alt(cm):");
Serial.print(Altitude);
Serial.print(" Pressure(Pa):");
Serial.println(Pressure);
Singurul lucru de remarcat aici este delay-ul de 5 secunde din setup, necesar pentru initializarea
senzorului.
http://www.robofun.ro/forum
http://www.robofun.ro
L9
Presiune Atmosferica MPL115A1
MPL115A1 este destul de similar cu BMP085. Difera modul de conectare cu Arduino (I2C in
cazul BMP085 si SPI in cazul MPL115A1). Conectarea se face folosind pinii SPI, ca mai jos.
Arduino 3.3 V
MPL115A1 VCC
Arduino GND
MPL115A1 GND
Arduino Digital 9
MPL115A1 SDN
Arduino Digital 10
MPL115A1 CSN
Arduino Digital 12
MPL115A1 SDO
Arduino Digital 11
MPL115A1 SDI
Arduino Digital 13
MPL115A1 SCK
http://www.robofun.ro/forum
http://www.robofun.ro
L9
Temperatura si Umiditate SHT15
SHT15 este un senzor care masoare presiunea si umiditatea mediului ambiant extrem de precis
(precizie de 0.3 C, si 2 % RH ). Conectarea la Arduino se face folosind doi pini digitali.
Arduino 5 V
SHT15 VCC
Arduino GND
SHT15 GND
Arduino Digital 9
SHT15 DATA
Arduino Digital 8
SHT15 SCK
Codul
sursa
integral
este
http://www.robofun.ro/senzor_temperatura_umiditate_sht15 .
disponibil
aici
http://www.robofun.ro/forum
http://www.robofun.ro
L9
Arduino 5 V
DHT22 VCC
Arduino GND
DHT22 GND
Arduino Digital 2
DHT22 PIN2
Rezistor 10K
conectat intre
DTH22 VCC si DHT22
PIN2
http://www.robofun.ro/forum
http://www.robofun.ro
L9
Serial.begin(9600);
Serial.println("DHT22 Library Demo");
}
void loop(void) {
DHT22_ERROR_t errorCode;
delay(2000);
Serial.print("Requesting data...");
errorCode = myDHT22.readData();
switch(errorCode)
{
case DHT_ERROR_NONE:
Serial.print("Got Data ");
Serial.print(myDHT22.getTemperatureC());
Serial.print("C ");
Serial.print(myDHT22.getHumidity());
Serial.println("%");
break;
case DHT_ERROR_CHECKSUM:
Serial.print("check sum error ");
Serial.print(myDHT22.getTemperatureC());
Serial.print("C ");
Serial.print(myDHT22.getHumidity());
Serial.println("%");
break;
case DHT_BUS_HUNG:
Serial.println("BUS Hung ");
break;
case DHT_ERROR_NOT_PRESENT:
Serial.println("Not Present ");
break;
case DHT_ERROR_ACK_TOO_LONG:
Serial.println("ACK time out ");
break;
case DHT_ERROR_SYNC_TIMEOUT:
Serial.println("Sync Timeout ");
break;
case DHT_ERROR_DATA_TIMEOUT:
Serial.println("Data Timeout ");
break;
case DHT_ERROR_TOOQUICK:
Serial.println("Polled to quick ");
break;
}
http://www.robofun.ro/forum
http://www.robofun.ro
L9
Temperatura TMP102
TMP102 este un senzor de temperatura care comunica pe I2C, cu o rezolutie de 0.0625 C si o
precizie de 0.5 C. Alimentarea se face la 3.3 V, iar conectarea la Arduino se face folosind pinii I2C.
Limitele sale sunt -25 C pana la 85 C, iar consumul este de-a dreptul impresionant 10 microAmperi !.
Arduino 3.3 V
TMP102 V+
Arduino GND
TMP102 GND
Arduino SDA
(Analog 4)
TMP102 SDA
Arduino SCL
(Analog 5)
TMP102 SCL
Arduino GND
TMP102 ADD0
#include <Wire.h>
int tmp102Address = 0x48;
void setup(){
Serial.begin(9600);
Wire.begin();
}
void loop(){
float celsius = getTemperature();
Serial.print("Celsius: ");
Serial.println(celsius);
float fahrenheit = (1.8 * celsius) + 32;
Serial.print("Fahrenheit: ");
http://www.robofun.ro/forum
http://www.robofun.ro
L9
Serial.println(fahrenheit);
delay(200);
}
float getTemperature(){
Wire.requestFrom(tmp102Address,2);
byte MSB = Wire.read();
byte LSB = Wire.read();
int TemperatureSum = ((MSB << 8) | LSB) >> 4;
float celsius = TemperatureSum*0.0625;
return celsius;
}
Senzorul TMP102 are 4 adrese distincte posibile, adresa curenta fiind selectata prin conectarea
pinului ADD0 la GND, 3.3 V, SDA sau respectiv SCL. Astfel, in exemplul de mai sus, pinul ADD0
este conectat la GND si atunci adresa senzorului este 0x48. Daca vom conecta pinul ADD0 la 3.3 V,
atunci adresa senzorului va deveni 0x49. Conectarea pinului ADD0 la pinul SDA va determina adresa
0x4A, iar conectarea la SCL va determina adresa 0x4B. Acest lucru este excelent pentru situatiile in care
avem nevoie de mai multi senzori conectati la acelasi Arduino. Putem astfel conecta pana la cel mult
patru senzori, toti conectati pe acelasi bus I2C. Pentru primul senzor, pinul ADD0 se conecteaza la
GND, pentru al doilea senzor, pinul ADD0 se conecteaza la 3.3V, pentru a treilea senzor, pinul ADD0
se conecteaza la SDA, iar pentru a al patrulea senzor, pinul ADD0 se conecteaza la pinul SCL. Toti
ceilalti pini se conecteaza exact ca mai sus.
In cod, vom avea patru adrese distincte, cate o adresa pentru fiecare senzor, ca mai jos.
#include <Wire.h>
int tmp102Address1
int tmp102Address2
int tmp102Address3
int tmp102Address4
=
=
=
=
0x48;
0x49;
0x4A;
0x4B;
void setup(){
Serial.begin(9600);
Wire.begin();
}
void loop(){
float celsius = getTemperature(tmp102Address1);
Serial.print("Celsius, Senzor 1: ");
Serial.println(celsius);
celsius = getTemperature(tmp102Address2);
Serial.print("Celsius, Senzor 2: ");
Serial.println(celsius);
celsius = getTemperature(tmp102Address3);
Serial.print("Celsius, Senzor 3: ");
Serial.println(celsius);
celsius = getTemperature(tmp102Address4);
http://www.robofun.ro/forum
http://www.robofun.ro
L9
http://www.robofun.ro/forum
http://www.robofun.ro
L9
Arduino 3.3 V
MLX90614 PIN2
Arduino GND
MLX90614 PIN1
MLX90614 PIN3
MLX90614 PIN4
Condensator 100nF
Conectat intre
MLX90614 PIN1 si
MLX90614 PIN2
Rezistor 4.7 K
Conectat intre
MLX90614 PIN3 si
Arduino 3.3V
Rezistor 4.7 K
Conectat intre
MLX90614 PIN4 si
Arduino 3.3V
Mai departe, vei avea nevoie sa iti instalezi in mediul tau de dezvoltare Arduino libraria
I2CMaster (disponibila ca download de pe pagina :
http://www.robofun.ro/senzor_infrarosu_MLX90614 ).
Codul sursa integral este disponibil mai jos.
#include <i2cmaster.h>
void setup(){
Serial.begin(9600);
i2c_init();
http://www.robofun.ro/forum
http://www.robofun.ro
L9
PORTC = (1 << PORTC4) | (1 << PORTC5);
}
void loop(){
int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;
i2c_start_wait(dev+I2C_WRITE);
i2c_write(0x07);
i2c_rep_start(dev+I2C_READ);
data_low = i2c_readAck();
data_high = i2c_readAck();
pec = i2c_readNak();
i2c_stop();
double tempFactor = 0.02;
double tempData = 0x0000;
int frac;
tempData = (double)(((data_high & 0x007F) << 8) + data_low);
tempData = (tempData * tempFactor)-0.01;
float celsius = tempData - 273.15;
float fahrenheit = (celsius*1.8) + 32;
Serial.print("Celsius: ");
Serial.println(celsius);
Serial.print("Fahrenheit: ");
Serial.println(fahrenheit);
delay(1000);
}
http://www.robofun.ro/forum
http://www.robofun.ro
L10
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Arduino 5 V
Pin1 Potentiometru
Arduino GND
Pin3 Potentiometru
Pin2 Potentiometru
VO (PIN3) LCD
Arduino GND
Arduino GND
RW (PIN5) LCD
Arduino 5 V
Arduino Digital 12
RS (PIN4) LCD
Arduino Digital 11
E (PIN6) LCD
Arduino Digital 5
D4 (PIN11) LCD
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Arduino Digital 4
D5 (PIN12) LCD
Arduino Digital 3
D6 (PIN13) LCD
Arduino Digital 2
D7 (PIN14) LCD
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup() {
lcd.begin(16, 2);
lcd.print("hello, world!");
}
void loop() {
lcd.setCursor(0, 1);
lcd.print(millis()/1000);
}
http://www.robofun.ro/forum
http://www.robofun.ro
L10
LCD 16 X 2 pe I2C, LCD 20 X 4 pe I2C
Ambele LCD-uri sunt LCD-urile obisnuite despre care am discutat mai sus,
carora li s-a atasat o placa suplimentara care comunica pe I2C cu Arduino si
seteaza cei 8 pini pentru controlul LCD-ului la valorile care trebuie astfel incat
pe LCD sa fie afisat text-ul care trebuie. In acest fel, intre Arduino si LCD sunt
necesare doar doua fire (SDA si SCL), in afara firului de GND si alimentare.
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Conexiunile la Arduino sunt ca in cele doua imagini de mai jos. Ultimii doi
pini din mufa lipita pe placa LCD-ului nu se folosesc. In rest, de la stanga la
dreapta, avem SDA (se conecteaza la pinul analogic 4 pe Arduino UNO sau la
pinul SDA pe Arduino Leonardo), SCL (se conecteaza la pinul analogic 5 pe
Arduino UNO sau la pinul SCL pe Arduino Leonardo), 5V (se conecteaza la pinul
5V pe Arduino, si pinul GND (se conecteaza la pinul GND).
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Arduino UNO
Arduino 5 V
LCD 5V
Arduino GND
LCD GND
Arduino Analog 4
LCD SDA
Arduino Analog 5
LCD SCL
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Arduino Leonardo
Arduino 5 V
LCD 5V
Arduino GND
LCD GND
Arduino SDA
LCD SDA
Arduino SCL
LCD SCL
http://www.robofun.ro/forum
http://www.robofun.ro
L10
http://www.robofun.ro/forum
http://www.robofun.ro
L10
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Porneste acum mediul de dezvoltare Arduino si incearca programul de
mai jos.
#include "Wire.h"
#include "LiquidCrystal.h"
LiquidCrystal lcd(0);
void setup() {
lcd.begin(20, 4);
lcd.setBacklight(HIGH);
lcd.print("hello, world
lcd.setCursor(0, 1);
lcd.print("hello, world
lcd.setCursor(0, 2);
lcd.print("hello, world
lcd.setCursor(0, 3);
lcd.print("hello, world
0 !");
1 !");
2 !");
3 !");
}
void loop() {
}
Daca LCD-ul tau nu arata ca mai sus, pe spatele placutei rosii vei gasi un
potentiometru de culoare albastra. Acest potentiometru stabileste contrastul
LCD-ului, si probabil ca s-a miscat in timpul transportului. Folosind o surubelnita
mica, un varf de cutit ascutit, foarfeca sau pila de unghii, roteste-l usor si
urmareste in acelasi timp textul pe LCD pana cand devine foarte clar.
Si partea frumoasa abia acum vine ! Cu acest tip de LCD, poti conecta
simultan pana la opt LCD-uri la acelasi Arduino, folosind aceeasi doi pini I2C.
Pentru aceasta, intoarce LCD-ul pe spate, si observa cei 3 jumperi pentru
http://www.robofun.ro/forum
http://www.robofun.ro
L10
setarea adresei I2C. In mod obisnuit, nici unul dintre acesti jumperi nu este
lipit, asa ca adresa shield-ului este zero (lucru pe care il vezi in cod la linia
LiquidCrystal lcd(0)). Fiecare LCD va trebuie sa aiba o adresa I2C diferita, asa
ca ceea ce ai de facut este sa folosesti un letcon si putin fludor pentru a
conecta unul sau mai multi jumperi impreuna. Adresele sunt in cod binar, astfel
ca folosind cei trei jumperi poti obtine exact opt adrese. Pentru a conecta un
jumper, incalzeste ambele pad-uri, apoi adauga fludor si intinde fludorul astfel
incat sa faca contact intre ambele pad-uri, ca mai jos.
world 0 !");
world 1 !");
world 2 !");
world 3 !");
lcd2.setBacklight(HIGH);
lcd2.print("LCD2, hello, world 0 !");
http://www.robofun.ro/forum
http://www.robofun.ro
L10
lcd2.setCursor(0,
lcd2.print("LCD2,
lcd2.setCursor(0,
lcd2.print("LCD2,
lcd2.setCursor(0,
lcd2.print("LCD2,
1);
hello, world 1 !");
2);
hello, world 2 !");
3);
hello, world 3 !");
lcd3.setBacklight(HIGH);
lcd3.print("LCD3, hello,
lcd3.setCursor(0, 1);
lcd3.print("LCD3, hello,
lcd3.setCursor(0, 2);
lcd3.print("LCD3, hello,
lcd3.setCursor(0, 3);
lcd3.print("LCD3, hello,
world 0 !");
world 1 !");
world 2 !");
world 3 !");
}
void loop() {
}
http://www.robofun.ro/forum
http://www.robofun.ro
L10
MP3 Player Shield
Shield-ul MP3 Player contine chip-ul VS1053b, capabil sa decodeze
stream-uri MP3, OGG Vorbis, AAC, WMA, MIDI, si de asemenea contine si un slot
de card microSD pentru incarcarea fisierelor audio. Shield-ul mai contine si un
conector pentru casti sau boxe audio, astfel ca in final, ceea ce obtii este un
player MP3 complet.
Ce ai tu de facut este sa citesti informatia stocata pe SD card si sa o
trimiti catre chip-ul MP3, atunci cand acesta o solicitia. Suna complicat in
teorie, dar din fericire exista deja mai multe librarii care fac asta in locul tau.
Cea mai interesanta este libraria disponibila ca download la adresa
http://www.robofun.ro/mp3_player_shield (link-ul "Librarie pentru Arduino").
Fisierul .zip pe care il descarci contine atat libraria MP3, cat si libraria pentru SD
card. Va trebui sa le copiezi pe ambele in directorul "libraries" din mediul tau de
dezvoltare Arduino. Codul sursa este relativ simplu de inteles, toata partea
complexa este ascunsa de librarie.
#include
#include
#include
#include
<SPI.h>
<SdFat.h>
<SdFatUtil.h>
<SFEMP3Shield.h>
SFEMP3Shield MP3player;
byte temp;
byte result;
char title[30];
char artist[30];
char album[30];
void setup() {
Serial.begin(115200);
result = MP3player.begin();
if(result != 0) {
Serial.print("Error code: ");
Serial.print(result);
Serial.println(" when trying to start MP3 player");
}
Serial.println("STARTED");
}
http://www.robofun.ro/forum
http://www.robofun.ro
L10
void loop() {
result = MP3player.playMP3("melodie1.mp3");
delay(3000);
if (MP3player.isPlaying()){
MP3player.stopTrack();
}
}
MP3 Trigger
MP3 Trigger este varianta mult imbunatatita a lui shield-ului MP3 Player
prezentat in sectiunea anterioara. Pe langa chip-ul capabil sa redea MP3-uri, SD
Card-ul deja prezent pe placa, MP3 Trigger-ul are in plus si un microcontroller
pre-programat. Astfel, numarul de pini necesari pentru interfatarea cu Arduino
scade drastic (doar doi pini sunt necesari) si in plus, MP3 Trigger-ul poate
functiona chiar si standalone, fara Arduino. Dat fiind ca este cel mai simplu, sa
incepem cu acest mod de functionare.
MP3 Trigger-ul ofera 18 pini, fiecare dintre ei declansand redarea melodiei
al carei nume incepe cu numarul asociat pinului. Astfel, spre exemplu, atunci
cand pinul 3 este conectat la pinul GND, este redata melodia al carei nume
incepe cu "003" (un exemplu de nume valid este "003 Avion cu Motor.mp3".). O
schema de conectare folosind butoane brick este mai jos. Am pus in schema
doar doua butoane, pentru exemplificare. Evident ca tu poti conecta cate ai
nevoie, maxim 18 butoane.
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Buton 1 VCC
Buton 1 OUT
Buton 2 VCC
Buton 2 OUT
Arduino 5V
Arduino GND
Arduino Digital 7
MP3 Trigger TX
Arduino Digital 8
MP3 Trigger RX
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Comanda: Start/Stop
Numar de bytes: 1
Byte de comanda: O
Functionare: Daca exista o melodie care este redata la momentul primirii
comenzii, se opreste redarea. Altfel, incepe redarea.
Comanda: Inainte
Numar de bytes: 1
Byte de comanda: F
Functionare : Urmatoarea melodie MP3 este redata.
Comanda: Inapoi
Numar de bytes: 1
Byte de comanda: R
Functionare: Melodia precedenta MP3 este redata.
Comanda: Trigger (binary)
Numar de bytes: 2
Byte de comanda: t
Byte de date: n = 1 to 255
Functionare: Daca exista, melodia cu numele NNNxxxx.MP3 este redata,
unde NNN is echivalentul ASCII al bitului de comanda.
Comanda: Play (binary)
Numar de bytes: 2
Byte de comanda: p
Byte de date: n = 0 to 255
Functionare: Daca exista, melodia numarul n va fi redata.
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Comanda: Set Volume (binary)
Numar de bytes: 2
Byte de comanda: v
Byte de date: n = 0 to 255
Comments: Volumul va fi setat la valoarea n. Volumul maxim se obtine cu
valoarea "0", iar volumul minim in jur de 100.
Toata gama de comenzi suportata este prezentata pe larg in manual de
utilizare al placii, disponibil la adresa http://www.robofun.ro/mp3_trigger_v2
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Cea mai simpla abordare pentru a intelege modul cum se foloseste acest
shield este sa urmarim mai jos un exemplu de program scris de Nathan Seidle
de la Sparkfun, program care genereaza cate zece note pentru fiecare
instrument inclus.
/*
2-12-2011
Spark Fun Electronics 2011
Nathan Seidle
This code is public domain but you buy me a beer if you use this and we
meet someday (Beerware license).
This code works with the VS1053 Breakout Board and controls the VS1053 in
what is called Real Time MIDI mode.
To get the VS1053 into RT MIDI mode, power up the VS1053 breakout board
with GPIO0 tied low, GPIO1 tied high.
I use the NewSoftSerial library to send out the MIDI serial at 31250bps.
This allows me to print regular messages
for debugging to the terminal window. This helped me out a ton.
5V : VS1053 VCC
GND : VS1053 GND
D3 (SoftSerial TX) : VS1053 RX
D4 : VS1053 RESET
Attach a headphone breakout board to the VS1053:
VS1053 LEFT : TSH
http://www.robofun.ro/forum
http://www.robofun.ro
L10
VS1053 RIGHT : RSH
VS1053 GBUF : GND
When in the drum bank (0x78), there are not different instruments, only
different notes.
To play the different sounds, select an instrument # like 5, then play
notes 27 to 87.
To play "Sticks" (31):
talkMIDI(0xB0, 0, 0x78); //Bank select: drums
talkMIDI(0xC0, 5, 0); //Set instrument number
//Play note on channel 1 (0x90), some note value (note), middle velocity
(60):
noteOn(0, 31, 60);
*/
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); //Soft TX on 3, we don't use RX in this code
byte note = 0; //The MIDI note value to be played
byte resetMIDI = 4; //Tied to VS1053 Reset line
byte ledPin = 13; //MIDI traffic inidicator
int instrument = 0;
void setup() {
Serial.begin(57600);
//Setup soft serial for MIDI control
mySerial.begin(31250);
void loop() {
talkMIDI(0xB0, 0x07, 120); //0xB0 is channel message, set channel volume
to near max (127)
/*
http://www.robofun.ro/forum
http://www.robofun.ro
L10
data byte command
//Play notes from F#-0 (30) to F#-5 (90):
for (note = 30 ; note < 40 ; note++) {
Serial.print("N:");
Serial.println(note, DEC);
//Note on channel 1 (0x90), some note value (note), middle velocity
(0x45):
noteOn(0, note, 60);
delay(50);
//Turn off the note with a given off/release velocity
noteOff(0, note, 60);
delay(50);
}
delay(100); //Delay between instruments
}
//=================================================================
*/
http://www.robofun.ro/forum
http://www.robofun.ro
L10
}
/*
//Demo Melodic
//=================================================================
Serial.println("Demo Melodic? Sounds");
talkMIDI(0xB0, 0, 0x79); //Bank select Melodic
//These don't sound different from the main bank to me
//Change to different instrument
for(instrument = 27 ; instrument < 87 ; instrument++) {
Serial.print(" Instrument: ");
Serial.println(instrument, DEC);
talkMIDI(0xC0, instrument, 0); //Set instrument number. 0xC0 is a 1
data byte command
//Play notes from F#-0 (30) to F#-5 (90):
for (note = 30 ; note < 40 ; note++) {
Serial.print("N:");
Serial.println(note, DEC);
//Note on channel 1 (0x90), some note value (note), middle velocity
(0x45):
noteOn(0, note, 60);
delay(50);
//Turn off the note with a given off/release velocity
noteOff(0, note, 60);
delay(50);
}
}
*/
}
//Send a MIDI note-on message. Like pressing a piano key
//channel ranges from 0-15
void noteOn(byte channel, byte note, byte attack_velocity) {
talkMIDI( (0x90 | channel), note, attack_velocity);
}
//Send a MIDI note-off message. Like releasing a piano key
void noteOff(byte channel, byte note, byte release_velocity) {
talkMIDI( (0x80 | channel), note, release_velocity);
}
//Plays a MIDI note. Doesn't check to see that cmd is greater than 127, or
// that data values are less than 127
void talkMIDI(byte cmd, byte data1, byte data2) {
digitalWrite(ledPin, HIGH);
http://www.robofun.ro/forum
http://www.robofun.ro
L10
mySerial.write(cmd);
mySerial.write(data1);
//Some commands only have one data byte. All cmds less than 0xBn have 2
//data bytes
//(sort of: http://253.ccarh.org/handout/midiprotocol/)
if( (cmd & 0xF0) <= 0xB0)
mySerial.write(data2);
}
digitalWrite(ledPin, LOW);
http://www.robofun.ro
L10
multe note, iar fiecare nota de fapt reda un alt instrument. Prima comanda din
aceasta sectiune selecteaza bank-ul cu instrumente de percutie
("talkMIDI(0xB0, 0, 0x78)"). Urmatoarea instructiune for va face exact un singur
ciclu (pentru ca asa cum am spus mai sus, instrumentul nu conteaza in cazul
bank-ului cu instrumente de percutie. A doua instructiune for din aceasta
sectiune cicleaza intre 27 si 87, cele 60 de instrumente disponibile pentru
bank-ul de percutie. Instructiunea "noteOn(0, note, 60)" genereaza o nota pe
cate unul dintre cele 60 de instrumente.
Cea de-a treia sectiune este perfect similara cu prima sectiune, doar ca in
bank-ul cu instrumente melodice instrumentele sunt intre 27 si 87.
Sa analizam acum mai atent functia noteOn, care genereaza o anumita
nota muzicala. Functia noteOn primeste trei parametri. Cel de-al doilea
parametru este nota muzicala, iar ultimul parametru reprezinta cat de
"puternic" este generata nota (daca ne gandim ca folosim un pian, atunci
ultimul parametru reprezinta cat de puternic apasam pe clapa pianului).
In rezumat :
3 bank-uri cu instrumente
talkMIDI(0xB0, 0, 0x00) selecteaza bank-ul cu instrumente clasice
talkMIDI(0xB0, 0, 0x78) selecteaza bank-ul cu instrumente de percutie
talkMIDI(0xB0, 0, 0x79) selecteaza bank-ul cu instrumente melodice
noteOn(0, note, 120) reda nota muzicala note; pentru bank-ul 0x78 valoarea
lui note selecteaza si instrumentul muzical (pentru bank-ul 0x78, valorile
posibile pentru note sunt intre 27 si 87).
noteOff(0, note, 120) opreste redarea notei muzicala note;
talkMIDI(0xB0, 0x07, volum) stabileste volumul instrumentului; valoarea
pentru volum este intre 0 si 127.
talkMIDI(0xC0, instrument, 0) stabileste instrumentul care va reda notele
muzicale; acest lucru este valabil doar pentru bank-urile 0X00 si 0X79; pentru
bank-ul 0X78, aceasta comanda nu are nici un efect.
http://www.robofun.ro/forum
http://www.robofun.ro
L10
WiFly Shield
Daca ai nevoie sa obtii informatii direct din Internet folosind Arduino, sau
sa ai un server web ruland pe Arduino si vrei sa-l accesezi tu din Internet, si
toate astea fara fir de retea, atunci WiFly Shield este ceea ce ai nevoie.
Functioneaza prin WIFI, se conecteaza la un router si iti ofera conexiune la
Internet pe Arduino. Daca nu iti este foarte clar cum functioneaza o retea de
calculatoare (termeni gen IP, DNS, MAC, DHCP iti suna ciudat), atunci iti
recomand sa citesti mai intai sectiunea in care se discuta despre shield-ul
Ethernet pentru Arduino, sectiune in care am prezentat si aceste concepte.
Libraria de care vei avea nevoie in codul de mai jos o gasesti in aceasta
pagina http://www.robofun.ro/wifly_shield, descarc-o si instaleaz-o in mediul
tau Arduino inainte de a rula exemplul de mai jos.
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Serial.println("Conectare in progres...");
if (client.connect()) {
Serial.println("Conectare reusita !");
client.println("GET /search?q=arduino HTTP/1.0");
http://www.robofun.ro/forum
http://www.robofun.ro
L10
client.println();
} else {
Serial.println("Conectare esuata");
}
}
void loop() {
if (client.available()) {
char c = client.read();
Serial.print(c);
}
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
for(;;)
;
}
Daca ai parcurs deja sectiunea despre Ethernet shield, vei vedea ca ceea
ce avem mai sus seamana foarte mult cu codul de acolo. Practic, se modifica
doar modul de conectare la retea. Sunt de remarcat cele doua constante de la
inceputul programului, care iti permit sa declari care este identificatorul tau de
retea WIFI si care este parola. Daca ai o retea fara parola, pune "" in loc de
parola si de id de retea.
Codul se conecteaza la serverul google.com si afiseaza in Serial Monitor
rezultatele cautarii pentru termenul "arduino" (tu vei vedea informatie in
format HTML, asa cum am explicat la sectiunea despre Ethernet Shield).
Serial.begin(9600);
Serial.print("IP: ");
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Serial.println(WiFly.ip());
server.begin();
}
void loop() {
Client client = server.available();
if (client) {
boolean current_line_is_blank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n' && current_line_is_blank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
for (int i = 0; i < 6; i++) {
client.print("* pe portul analogic ");
client.print(i);
client.print(analogRead(i));
client.println("<br />");
}
break;
}
if (c == '\n') {
current_line_is_blank = true;
} else if (c != '\r') {
current_line_is_blank = false;
}
}
}
delay(100);
client.stop();
Exemplul de mai sus creaza un server web care ruleaza pe placa Arduino
si la fiecare cerere din browser raspunde cu valorile de pe porturile analogice,
ca mai jos. IP-ul server-ului este alocat in mod dinamic de router, asa ca, pentru
a sti care este adresa pe care o folosesti in browser, iti recomand sa deschizi
Serial Monitor si sa vezi in debug IP-ul alocat placii.
L10
http://www.robofun.ro
principiu este de a genera un request HTTP din Arduino, care request sa fie
perfect similar cu cel generat de pagina din form-ul Google. Astfel, Google este
"pacalit" sa creada ca datele trimise de Arduino sunt de fapt trimise de un form
creat cu Google Docs.
Pentru acest proiect ai nevoie un Arduino cu conectare la Internet. Ai de
ales intre Arduino Ethernet sau Arduino UNO + Ethernet Shield. Senzorii sunt la
alegerea ta, in functie de ce date vrei sa trimiti in Google Docs. Pentru
exemplul de mai jos, eu am ales un BMP085 (ca sa masor presiunea
atmosferica si temperatura), si un HIH-4030 pentru masurarea umiditatii.
Evident ca tu poti alege ce senzori doresti.
Mai departe, acceseaza http://docs.google.com si creaza un document tip
spreasheet ("CREATE", apoi "Spreadsheet"). Ar trebui sa vezi un document
similar unui document Excel. Din meniul "Tools", alege "Create a form". Form-ul
creat ar trebui sa aiba cate un camp de tip "Text" pentru fiecare senzor pe care
il vei trimite catre Google Docs. Spre exemplu, eu am creat un camp
"temperatura", un camp "umiditate" si un camp "presiune", toate de tip "Text".
Selecteaza apoi din meniul "Form (0)" intrarea "Go to live form". Vei
vedea formularul creat de Google Docs pentru culegerea datelor. Mai departe,
va trebui sa analizezi codul sursa al paginii (in functie de browser-ul pe care il
folosesti, acest lucru se face diferit spre exemplu in Chrome trebuie sa dai
click dreapta si apoi sa selectezi "View page source"). In codul sursa al paginii
localizeaza sirul de caractere "formkey=". Vei gasi ceva de genul
"formkey=dE9MTmlMc3N1RVNfdVJIRkFMNDltaXc6MQ". Acest sir de caractere
reprezinta identificatorul unic al formularului tau, identificator pe care Arduino il
va utiliza ca sa trimita informatiile. Localizeaza si campurile in care introduci
informatia utila (va fi simplu, pentru ca vor fi prefixate de numele campurilor
pe care le-ai dat tu cand ai creat formularul vezi si imaginea de mai jos).
Numele acestor campuri ar trebui sa fie ceva de genul "entry.0.single",
"entry.1.single", "entry.2.single" si tot asa pentru toate campurile care le-ai
declarat.
http://www.robofun.ro/forum
http://www.robofun.ro
L10
http://www.robofun.ro/forum
http://www.robofun.ro
L10
http://www.robofun.ro/forum
http://www.robofun.ro
L10
Codul
sursa
integral
pentru
Arduino
il
gasesti
aici
http://robofun.ro/blog/cum-sa-trimiti-loghezi-pe-google-docs-temperaturapresiunea-atmosferica-si-umiditatea-direct-din-arduino . In cele ce urmeaza
vom analiza partile interesante din cod. Chiar la inceput ai o declaratie de
forma "char formkey[] = "dG9HWmNXWjNRdWhBWG5ITlpNeUVBU2c6MQ";"
Aici va trebui sa modifici cheia din cod cu cheia din documentul tau, pe care ai
obtinut-o mai sus. Mai departe, in functia "loop" vei gasi denumirile campurilor
din document, pe care le-ai identificat deja mai sus. Va trebui sa modifici
aceasta zona din cod pentru a trimite exact informatiile culese de tine. Spre
exemplu, in cazul meu codul este ca mai jos :
String data;
data+="";
http://www.robofun.ro/forum
http://www.robofun.ro
L10
data+="entry.2.single=";
data+=temperatura;
data+="&entry.3.single=";
data+=presiune;
data+="&entry.4.single=";
data+=umiditate;
data+="&submit=Submit";
http://www.robofun.ro/forum
http://www.robofun.ro
L11
Arduino Leonardo pe post de tastatura
Exact, daca ai un Arduino Leonardo, poti sa-l faci sa se comporte ca o
tastatura sau un mouse absolut obisnuite (din punct de vedere al
calculatorului). Este o facilitate a noului microcontroller Atmega32u4. Tot ce ai
facut este ca in codul Arduino sa apelezi libraria Keyboard si calculatorul (la
care ai conectat Arduino prin USB) se va comporta ca si cum ai fi apasat taste
pe tastatura obisnuita.
Inainte de a trece mai departe, este necesar sa iti atrag atentia asupra
unui lucru care ar putea fi neplacut. Imediat ce ai programat placa sa trimita
taste apasate catre calculator, Arduino le va trimite tot timpul, pana cand ii
spui sa se opreasca. Singurul mod in care ii poti spune sa se opreasca este
incarcand alt program. Dar daca ai pus placa sa trimita taste prea rapid, atunci
nu vei putea face acest lucru, pentru ca se vor apasa taste chiar in mediul de
dezvoltare, acolo unde vei vrea sa scrii codul. Ca sa nu se intample asta, ai
grija ca sa existe un mecanism prin care sa opresti trimiterea de taste (cum ar
fi un buton conectat la Arduino, sau un delay mare pus un setup). Cu un delay
in setup, poti oricand sa dai un reset placii altfel incat sa o fortezi sa ruleze
functia setup, si apoi cat timp placa sta in delay, tu ii vei putea modifica
programul.
Exemplu 1 void setup() {
delay(15000);
Keyboard.begin();
}
void loop() {
Keyboard.print("Hello!");
delay(10000);
}
http://www.robofun.ro/forum
http://www.robofun.ro
L11
Dupa ce au trecut cele 15 secunde din setup, Arduino apasa tasta CTRL
(si o mentine apasata), apoi apasa tasta "n" si apoi elibereaza ambele taste.
Efectul, pe majoritatea sistemelor de operare, este deschiderea unei ferestre
noi.
Mai jos, lista tuturor comenzilor asociate tastaturii emulate de Arduino.
Keyboard.begin()
- deschide o sesiune de emulare tastatura. Este necesar sa apelezi
aceasta comanda inainte de a le putea folosi pe restul.
Keyboard.end()
- inchide o sesiune de emulare tastatura.
Keyboard.press(<TASTA>)
- apasa si mentine apasata o tasta (utila pentru a trimite combinatii de
taste, gen CTRL + N).
Keyboard.print(<SIR_DE_TASTE>)
- apasa si elibereaza o tasta sau un sir de taste. Util pentru a apasa o
tasta sau un sir de taste apasate succesiv spre calculator.
Keyboard.println(<SIR_DE_TASTE>)
- acelasi lucru ca print, doar ca la final apasa si tasta ENTER. Util pentru a
introduce informatie intr-un document text si a trece automat la linie noua.
Keyboard.release(<TASTA>)
- elibereaza o tasta apasata anterior (cu Keyboard.press()).
Keyboard.releaseAll()
- elibereaza toate tastele apasate anterior (cu Keyboard.press())
Keyboard.write(<TASTA>)
http://www.robofun.ro/forum
http://www.robofun.ro
L11
http://www.robofun.ro
L11
Mouse.press(MOUSE_LEFT) este ca si cum am apasa manual pe butonul din
stanga al mouse-ului, fara a-l elibera.
Mouse.release()
elibereaza unul dintre butoanele mouse-ului apasate anterior cu Mouse.press.
Valori posibile sunt MOUSE_LEFT , MOUSE_RIGHT, MOUSE_MIDDLE.
http://www.robofun.ro/forum
http://www.robofun.ro
L12
http://www.robofun.ro/forum
http://www.robofun.ro
L12
http://www.robofun.ro/forum
http://www.robofun.ro
L12
Mai departe, codul sursa nu face altceva decat sa combine exemplele
care demonstreaza citirea datelor de la senzori cu cel care demostreaza
utilizarea Arduino Leonardo pe post de tastatura.
#include <Wire.h>
#include <BMP085.h>
BMP085 dps = BMP085();
long Temperature = 0, Pressure = 0;
void setup(void) {
Serial.begin(9600);
Wire.begin();
delay(1000);
dps.init();
delay(5000);
Keyboard.begin();
}
void loop(void) {
dps.getTemperature(&Temperature);
dps.getPressure(&Pressure);
int nivelIluminare = analogRead(1);
int nivelUmiditate = analogRead(0);
Keyboard.print(String(Temperature));
Keyboard.print(KEY_RIGHT_ARROW);
Keyboard.print(String(Pressure));
Keyboard.print(KEY_RIGHT_ARROW);
Keyboard.print(String(nivelIluminare));
Keyboard.print(KEY_RIGHT_ARROW);
Keyboard.print(String(nivelUmiditate));
Keyboard.println();
http://www.robofun.ro/forum
http://www.robofun.ro
L11
#define SENSIBILITATE_X 3
#define SENSIBILITATE_Y 3
void setup() {
Serial.begin(9600);
analogReference(EXTERNAL);
Mouse.begin();
}
void loop() {
float xAcc=readAcc(0);
float yAcc=readAcc(1);
float zAcc=readAcc(2);
Serial.print("Acceleratie X: ");
Serial.print(xAcc,DEC);
Serial.print("Acceleratie Y: ");
Serial.print(yAcc,DEC);
Serial.println();
delay(50);
Mouse.move(xAcc * SENSIBILITATE_X, yAcc * SENSIBILITATE_Y, 0);
}
float readAcc(int port) {
int value=analogRead(port);
int miliVolts=map(value,0,1023,0,3300)-3300/2;
float acc=(float)miliVolts/360;
return acc;
}
http://www.robofun.ro/forum
http://www.robofun.ro
L11
Arduino 3.3 V
ADXL335 VCC
Arduino GND
ADXL335 GND
Arduino Analog0
ADXL335 X
Arduino Analog1
ADXL335 Y
Arduino Analog2
ADXL335 Z
Arduino 3.3
Arduino AREF
http://www.robofun.ro/forum
http://www.robofun.ro
L11
http://www.robofun.ro/forum
http://www.robofun.ro
L11
SENSIBILITATE_X 3
SENSIBILITATE_Y 3
ZONA_MOARTA_X 0.3
ZONA_MOARTA_Y 0.3
void setup() {
Serial.begin(9600);
analogReference(EXTERNAL);
Mouse.begin();
}
void loop() {
float xAcc=readAcc(0);
float yAcc=readAcc(1);
float zAcc=readAcc(2);
Serial.print("Acceleratie X: ");
Serial.print(xAcc,DEC);
Serial.print("Acceleratie Y: ");
Serial.print(yAcc,DEC);
Serial.println();
delay(50);
http://www.robofun.ro/forum
http://www.robofun.ro
L11
int miscareX = 0;
if (abs(xAcc) > ZONA_MOARTA_X) {
miscareX = xAcc * SENSIBILITATE_X;
}
int miscareY = 0;
if (abs(yAcc) > ZONA_MOARTA_Y) {
miscareY = yAcc * SENSIBILITATE_Y;
}
Mouse.move(miscareX, miscareY, 0);
}
float readAcc(int port) {
int value=analogRead(port);
int miliVolts=map(value,0,1023,0,3300)-3300/2;
float acc=(float)miliVolts/360;
return acc;
}
http://www.robofun.ro/forum
http://www.robofun.ro
L11
#define
#define
#define
#define
SENSIBILITATE_X 3
SENSIBILITATE_Y 3
ZONA_MOARTA_X 0.3
ZONA_MOARTA_Y 0.3
#define BUTON1_PIN 9
#define BUTON1_PIN 10
#define DEBOUNCE_TIME 100
void setup() {
Serial.begin(9600);
analogReference(EXTERNAL);
pinMode(BUTON1_PIN, INPUT);
pinMode(BUTON2_PIN, INPUT);
http://www.robofun.ro/forum
http://www.robofun.ro
L11
Mouse.begin();
}
long lastButtonPress1 = 0;
long lastButtonPress2 = 0;
void loop() {
int buton1 = digitalRead(BUTON1_PIN);
int buton2 = digitalRead(BUTON2_PIN);
if (buton1 == 1) {
if ((millis() - lastButtonPress1) > DEBOUNCE_TIME) {
lastButtonPress1 = millis();
Mouse.click(BUTTON_LEFT);
}
}
if (buton2 == 1) {
if ((millis() - lastButtonPress2) > DEBOUNCE_TIME) {
lastButtonPress2 = millis();
Mouse.click(BUTTON_RIGHT);
}
}
float xAcc=readAcc(0);
float yAcc=readAcc(1);
float zAcc=readAcc(2);
Serial.print("Acceleratie X: ");
Serial.print(xAcc,DEC);
Serial.print("Acceleratie Y: ");
Serial.print(yAcc,DEC);
Serial.println();
delay(50);
int miscareX = 0;
if (abs(xAcc) > ZONA_MOARTA_X) {
miscareX = xAcc * SENSIBILITATE_X;
}
int miscareY = 0;
if (abs(yAcc) > ZONA_MOARTA_Y) {
miscareY = yAcc * SENSIBILITATE_Y;
}
Mouse.move(miscareX, miscareY, 0);
}
float readAcc(int port) {
int value=analogRead(port);
int miliVolts=map(value,0,1023,0,3300)-3300/2;
float acc=(float)miliVolts/360;
return acc;
}
http://www.robofun.ro
L11
am povestit mai pe larg in cadrul sectiunii despre butoane brick, atunci cand se
apasa un buton, semnalul receptionat de catre Arduino variaza de cateva ori
intre 0 si 1 (nu trece instantaneu din 0 in 1). Acest lucru se intampla datorita
faptului ca atunci cand apasam butonul, lamelele metalice care inchid
contactul nu se ating perfect. Ca sa evitam ca Arduino sa citeasca mai multe
apasari de buton, vreme de 100 de milisecunde dupa prima apasare
receptionata (valoarea lui DEBOUNCE_TIME) vom ignora orice alta apasare.
Acest lucru inca permite conceptul de dublu click (doar ca diferenta intre doua
click-uri succesive va fi exact DEBOUNCE_TIME milisecunde). Daca dublu click
nu este sesizat corect de calculatorul tau, poti sa micsorezi valoarea acestei
constante, sau sa modifici pe calculator durata intre cele doua click-uri
succesive pentru a obtine un dublu click.
http://www.robofun.ro/forum
http://www.robofun.ro
http://www.robofun.ro/forum
http://www.robofun.ro
http://www.robofun.ro/forum
http://www.robofun.ro
Divizorul de tensiune
Sa consideram circuitul electric de mai sus, format dintr-o sursa si doua
rezistoare inseriate. Curentul stabilit prin circuit este determinat foarte simplu
ca fiind I = U / (R1 + R2) (legea lui Ohm). Mai departe, daca ne concentram
doar pe R2, aceeasi lege se aplica si pentru ea, luata separat. In plus, am mai
stabilit ca in orice punct al unui circuit electric simplu (fara bifurcatii) avem
aceeasi intensitate a curentului electric. Asadar, putem scrie : I = U2 / R2 (unde
U2 este caderea de tensiune la capetele rezistorului R2. Putem astfel determina
U2 ca fiind U2 = I * R2, adica, folosind si prima relatie de mai sus : U2 = U *
R2 / (R1 + R2). Aceasta relatie, care ne da caderea de tensiune pe rezistorul R2
in functie de R1, R2 si U este foarte utila intr-o multitudine de situatii. Spre
exemplu, daca in loc de R1 (care in cazul nostru este fix), avem un senzor care
isi modifica rezistenta in functie de un element extern (de exemplu un
fotorezistor), atunci masurand cu Arduino caderea de tensiune U2 (pe un pin
analogic), indirect, masuram si valoarea lui R1, deci implicit nivelul de
iluminare al incaperii.
http://www.robofun.ro/forum
http://www.robofun.ro
Sa luam apoi bucla formata din R1 si R2. Nu stiu cat de evident este
acest lucru din analogia cu curgerea lichidelor, dar intotdeauna pe o bucla de
circuit inchisa suma caderilor de tensiune este zero. Adica :
U1 + U2 = 0
care este a doua lege a lui Kirchoff.
Gata ! Inarmati cu legea lui Ohm si cu cele doua legi ale lui Kirchoff,
putem acum determina curenti si tensiuni pe circuite oricat de complicate.
Condensatorul
Un condensator nu este altceva decat o galeata in care cad electronii.
Cand galeata s-a umplut, sarcinile incep sa curga mai departe pe fir. Din acest
motiv, vom intalni folositi condesatori peste tot unde avem nevoie de un buffer
de curent. Spre exemplu, aproape de alimentarea unui motor de curent
continuu. Astfel, atunci cand motorul porneste, are nevoie de o mare cantitate
de curent. Posibil chiar mai mare decat poate da sursa. In aceasta situatie, un
condensator de valoare mare va stoca acel curent in regimul de functionare
normal si il va oferi motorului la pornire. In acest fel, si restul dispozitivelor din
circuit vor avea suficient curent ca sa functioneze.
Semnalul PWM
Semnalul PWM (sau Pulse Width Modulation) este un tip de semnal pe
care il vom intalni destul de des cand lucram cu Arduino. Dat fiind ca Arduino
scoate porturile lui digitale doar semnal digital (cu doar doua nivele 5V si 0V),
semnalul PWM reprezinta o modalitate de a da in exterior informatie care sa
varieze pe mai multe trepte. Astfel, daca modificam raportul intre cat timp sta
http://www.robofun.ro/forum
http://www.robofun.ro
Una dintre cele mai comune aplicatii ale semnalului PWM este controlul
motoarelor de curent continuu. Un motor de curent continuu caruia i s-a aplicat
un semnal PWM cu factor de umplere 100% va functiona la viteza maxima.
Daca factorul de umplere scade la 50%, si viteza motorului se va modifica in
consecinta (tinand cont ca doar o jumatate din timp mai este actionat practic,
cealalta jumatate din timp invartindu-se din inertie).
http://www.robofun.ro/forum
http://www.robofun.ro
In ghiveci avem cei doi electrozi metalici. Pot fi din orice metal, dar
pentru a nu oxida, cel mai bine este sa fie din inox. Daca este dificil sa gasiti
sarma sau electrozi din inox, sunt la fel de bune si doua cozi de furculita din
inox. Acestea se infig la o distanta de circa 1 cm intre ele (nu este foarte
importanta distanta, important este sa NU se atinga si sa nu fie foarte
departate - gen unul intr-o margine de ghiveci si celalalt in cealalta margine).
Urmatorul pas este sa stabilim valoarea rezistorului asociat celor doi
http://www.robofun.ro/forum
http://www.robofun.ro
http://www.robofun.ro/forum
http://www.robofun.ro
#define LED_PIN 12
#define ALARM 300
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
int v = analogRead(0);
if (v < ALARM) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
delay(5000);
Serial.println(v);
}
http://www.robofun.ro
Arduino 3.3 V
MMA8452Q 3.3V
Arduino GND
MMA8452Q GND
Arduino SDA
MMA8452Q SDA
Arduino SCL
MMA8452Q SCL
MMA8452Q este un accelerometru relativ ieftin, suficient de capabil pentru pretul lui. Suporta
trei game de acceleratie (2g, 4g, 8g). Conectarea la Arduino se face folosind patru fire, ca in figura de
mai sus. Putem utiliza un accelerometru de acest tip impreuna cu un Arduino Leonardo pentru a
construi o aplicatie ce detecteaza vibratiile cum ar fi cele produse de un cutremur. Datele vor fi salvate
intr-un fisier excel pentru a fi stocate in caz ca vrei sa le utilizezi la ceva anume. Sau se pot construi mai
multe module de acest gen si interconectate intr-o retea iar daca sunt gestionate de catre un server pot fi
transformate intr-o adevarata retea de detectie a cutremurelor.
http://www.robofun.ro/forum
http://www.robofun.ro
Cum functioneaza?
Accelerometrul se alimenteaza direct de la platforma Arduino si comunica cu microcontroller-ul
prin doua fire: SDA si SCL. Orice vibratie mica, orice fel de miscare aplicata accelerometrului provoaca
o schimbare la cele trei variabile de iesire. Variabilele de iesire sunt raportate la cele trei axe de
coordonate: X, Y, Z.
Astfel daca accelerometrul va sta cu axa Z perpendiculara pe planul orizontal, la iesire vei
observa trei valori. Primele doua valori, X si Y vor oscila in jurul valorii lui 0, pentru ca nu actioneaza
nici o forta asupra lor dar oscileaza pentru ca e posibil ca accelerometrul sa aibe o usoara inclinatie. Dar
asupra lui Z actioneaza forta gravitationala. Imaginea luata din Excel arata mai bine aceasta
situatie(coloanele sunt in ordinea: X, Y si Z, cel din urma fiind in jurul valorii de 250, aproximativ 1g).
Cum incarci datele in Excel ? In primul rand, vrem ca datele referitoare la vibratii sa se incarce
in Excel doar atunci cand se detecteaza vibratii si nu incontinuu. Apoi datele vor fi grupate in cate 10
esantioane si se va face o medie. Va exista si un threshold sau valoare limita, depinde cum vrei sa o
numesti.
Daca media celor 10 esantioane depaseste valoarea thresholdului atunci Arduino va incarca
datele in Excel si va realiza acest lucru pentru 10 secunde. Apoi va realiza din nou o mediere asupra
altor 10 esantioane si din nou va testa daca s-a depasit thresholdul iar daca nu, el va ramane in
standby(nu va transmite nimic in Excel).
Cum transmite Arduino Leonardo setul de date in Excel ? Arduino Leonardo se va comporta ca
o tastatura sau keyboard emulator. Exista niste functii interesante care realizeaza acest lucru si vom
vedea in continuare.
http://www.robofun.ro/forum
http://www.robofun.ro
Codul sursa.
Avem doua directive ce reprezinta defapt librariile: I2C pentru protocol si libraria
accelerometrului. Se initializeaza si obiectul accel. Librariile se vor copia in directorul libraries din
directorul arduino.
arduino-1.0.1-windows/arduino-1.0.1/libraries/I2C/I2C.cpp
arduino-1.0.1-windows/arduino-1.0.1/libraries/I2C/I2C.h
arduino-1.0.1-windows/arduino1.0.1/libraries/MMA8453_n0m1/MMA8453_n0m1.cpp
arduino-1.0.1-windows/arduino1.0.1/libraries/MMA8453_n0m1/MMA8453_n0m1.h
#include <I2C.h>
#include <MMA8453_n0m1.h>
MMA8453_n0m1 accel;
contor;
X[10];
Y[10];
Z[10];
mediaX, mediaY, mediaZ;
thresX, thresY, thresZ;
Functia setup initializeaza variabilele declarate mai sus, adresa accelerometrului, modul de lucru
al senzorului si emularea tastaturii. Aici am stabilit si valorile de threshold si le poti modifica daca vrei sa
modifici sensibilitatea senzorului la vibratii.
void setup()
{
mediaX=0;
mediaY=0;
mediaZ=0;
thresX=10;
thresY=10;
thresZ=300;
accel.setI2CAddr(0x1D); //change your device address if necessary, default
is 0x1C
accel.dataMode(true, 2); //enable highRes 10bit, 2g range [2g,4g,8g]
Keyboard.begin();
}
Loop() este compusa din mai multe bucle for. Prima bucla se ocupa de esantionul de date, zece
la numar. Citirile de la accelerometru sunt salvate in trei vectori: X, Y, Z.
for (contor=0; contor <= 9; contor++) {
accel.update();
X[contor]=accel.x();
http://www.robofun.ro/forum
http://www.robofun.ro
Y[contor]=accel.y();
Z[contor]=accel.z();
}
Se executa o alta bucla for care aduna toate elementele vectorilor. Adunarea se imparte la 10,
adica se realizeaza media aritmetica. Media este utila daca apare o vibratie generata de o alta sursa, care
nu ne intereseaza si vrem sa o eliminam.
for (contor=0; contor <= 9; contor++) {
mediaX=mediaX+X[contor];
mediaY=mediaY+Y[contor];
mediaZ=mediaZ+Z[contor];
}
mediaX=mediaX/10;
mediaY=mediaY/10;
mediaZ=mediaZ/10;
Se compara cele trei medii cu 3 valori de threshold iar daca una dintre cele 3 medii(am folosit
functia OR) depaseste valoarea de threshold, se incarca datele in Excel. Echivalent, daca apare o vibratie
anormala si este importanta, aceasta este salvata in Excel prin apelarea functiei tipareste(). Am introdus
si o intarziere pentru ca a emula o tastatura la o viteza foarte mare, inseamna sa soliciti procesorul putin
mai mult. Am folosit intarzierea si ca etalon pentru a crea o perioada de aproximativ 10 secunde in care
datele sunt incarcate in Excel.
if (mediaX > thresX || mediaY > thresY || mediaZ > thresZ) {
for (contor=0; contor < 50; contor++){
accel.update();
tipareste();
delay(100);
}
http://www.robofun.ro/forum
http://www.robofun.ro
Keyboard.print(accel.z());
Keyboard.write(KEY_RETURN);
Keyboard.write(KEY_RIGHT_ARROW);
Keyboard.write(KEY_UP_ARROW);
Keyboard.write(KEY_DOWN_ARROW);
Keyboard.write(KEY_LEFT_ARROW);
Keyboard.write(KEY_LEFT_ARROW);
Keyboard.write(KEY_LEFT_ARROW);
Keyboard.write(KEY_LEFT_ARROW);
Concluzie.
Am optat sa montez accelerometrul cu un surub direct pe Arduino, din cauza ca este simplu.
Aplicatia nu detecteaza vibratiile foarte mici. Personal am dat volumul tare pe o melodie rock dar
vibratiile produse nu au fost detectate de senzor. Aici intra in calcul si valoarea de threshold dar si
sensibilitatea accelerometrului pe gama de lucru(2, 4 sau 8g).
In schimb aplicatia da rezultate foarte bune la vibratiile banale. In cazul unui cutremur, stim ca
miscarea se poate propaga pe orizontala sau pe verticala, adica pe una dintre cele 3 axe.
Va urez succes in constructie.
http://www.robofun.ro/forum
Ce reprezinta I2C ?
I2C este ,in explicatia lui, cea mai simpla un protocol prin care poti realiza transfer de date intre
mai multe dispozitive. Spre exemplu, doresti ca in proiectul tau sa transmiti la distanta, prin intermediul
a 2 fire, pachete de date. Aceste pachete de date le vei transmite bit cu bit, unul dupa altul, catre unul
sau mai multe dispozitive. Sau invers, poti receptiona si poti stoca pachete de date de la unul sau mai
multe dispozitive.
Cum se conecteaza dispozitivele ?
In primul rand, ai aflat ca protocolul I2C iti permite sa transmiti si sa receptionezi pachete de
date sau bytes. In al doilea rand, le poti conecta sub forma unei retele pe o singura magistrala. Poti
conecta in jur de 100 de placi Arduino folosind doar 2 fire, unul de date si unul de clock.
Conceptul de master si slave ?
Protocolul I2C introduce ideea ca o singura placa trebuie sa fie master, iar restul placilor trebuie
sa fie slave-uri. Master-ul este cel care initializeaza comunicatia si efectueaza transferul de date din si
catre slave-uri. Mai simplu spus, master-ul poate fi privit ca un server, iar slave-ul poate fi privit ca un
client.
Analogic vorbind, clientul intotdeauna raspunde cererilor serverului. Daca serverul doreste
date, acesta ii spune clientului identificat printr-o adresa ca doreste acest lucru. Clientul se
conformeaza si indeplineste cererea. In termeni generali, asa se realizeaza o tranzactie I2C intre mai
multe placi Arduino.
Daca doresti sa studiezi mai multe despre protocolul I2C, nivele logice, cum se transmit serial
octetii si alte informatii utile, acceseaza link-urile de mai jos:
http://www.i2c-bus.org/
http://www.robot-electronics.co.uk/acatalog/I2C_Tutorial.html
https://learn.sparkfun.com/tutorials/i2c
http://www.robofun.ro/forum
Un breadboard: http://www.robofun.ro/breadboard
Rezistoare: http://www.robofun.ro/electronice/rezistoare
Conecteaza placile Arduino folosindu-te de diagrama de mai jos:
In primul rand, trebuie sa realizezi masa comuna intre cele 2 placi, altfel nimic nu va functiona
corect. Pe diagrama masa comuna este realizata prin firul de culoare albastra. Firul se afla conectat intre
pinii GND ale placilor Arduino.
De asemenea conecteaza pinii 5V folosind firul de culoare rosie. Lucrul asta este necesar
pentru ca trebuie sa alimentezi rezistoarele de 4.7K.
Magistrala I2C este cea formata din cele 2 fire de culoare galbena si albastra. Prin intermediul
firelor vor circula bitii si semnalele de tact.
http://www.robofun.ro/forum
placa alegi, cat timp cealalta va fi diferita. Spre exemplu, poti alege placa din stanga ca fiind placa
master, iar placa din dreapta ca fiind placa slave.
Mai jos sunt listate 2 sketch-uri, unul il vei incarca in placa master, iar celalalt il vei incarca in
placa slave.
Codul pentru placa master:
#include <Wire.h>
#define LED_PIN 13
byte x = 0;
void setup()
{
Wire.begin();
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
}
void loop()
{
Wire.beginTransmission(9);
Wire.send(x);
Wire.endTransmission();
x++;
if (x > 5) x=0;
delay(450);
}
se initializeaza placa master prin linia Wire.begin() fara niciun parametru intre paranteze (vei
vedea ca la placa Slave este musai sa aplici si un parametru, adica adresa slave-ului).
http://www.robofun.ro/forum
Variabila x este incrementata, dupa care tot procesul explicat mai sus se reia, adica se va
transmite catre placa slave continutul variabilei x, dar incrementat.
http://www.robofun.ro/forum
void loop() {
if (x == 0) {
digitalWrite(LED_1, HIGH);
delay(200);
digitalWrite(LED_1, LOW);
delay(200);
}
if (x == 1) {
digitalWrite(LED_2, HIGH);
delay(200);
digitalWrite(LED_2, LOW);
delay(200);
}
}
void receiveEvent(int howMany) {
x = Wire.receive();
}
La fiecare tranzactie I2C initializata de catre placa Master, placa Slave va executa rutina
receiveEvent(int howMany). Ea functioneaza asemanator cu o intrerupere. Ori de cate ori
Master-ul transmite ceva se va executa aceasta rutina, prin care se stocheaza in variabila x ceea
ce a transmis placa Master.
In rutina loop() placa Slave testeaza ceea ce a transmis placa Master si anume, daca a transmis
valoarea 0 atunci se va aprinde LEDul 1, iar daca s-a transmis valoarea 2 atunci se va aprinde
LEDul 2.
Acesta este un exemplu simplu, prin care o placa Arduino master transmite catre o alta placa
Arduino slave o serie de valori. Placa Slave reactioneaza diferit in functie de valoarea transmisa.
http://www.robofun.ro/forum
http://www.robofun.ro/forum