KKM: APDS-9960

Početnik si s Croduinom. Ili s elektronikom? Za oko ti je zapeo određeni modul, ali ne znaš kako ga koristiti? Bez brige, tu je KKM! Kako Koristiti Module (KKM) je serija blog tutorijala e-radionice na kojoj ćeš pronaći sve što ti treba kako bi započeo rad sa svojim omiljenim modulom. Tutorijali obuhvaćaju: tehničke karakteristike, princip rada, upute kako povezati modul s Croduinom te osnovni kod. Sve ostalo prepuštamo tebi na maštu.

Uvod

U ovome tutorijalu, upoznat' ćemo se s APDS-9960 digitalnim senzorom blizine, količine svjetla u prostoru, boja i gesti. Kontrola gesti omogućuje nam da se detektira pokret ruke u lijevu ili desnu stranu, te gore ili dolje, kao i neke kompleksnije geste poput udaljavanje ruke od senzora prema gore ili pak približavanje ruke prema senzoru. Zbog svojih dimenzija, mogućnosti i potrošnje, primjenu je našao u mobitelima kao senzor detekcije blizine da se prilikom korisnikovog javljanja na mobitel onemogući touchscreen (a samim time i slučajni dodiri na zaslonu), snimi sliku zaslona pokretom ruke i sl. No, za početak promotrit' ćemo neke karakteristike senzora kao i sam izgled senzora.

 

Slika modula

Karakteristike senzora:

• Napon napajanja: 2.4 VDC - 3.6 VDC

• Napon na ulazima SDA i SCL: 0.8 VDC - 3.6 VDC

• Napon LED diode u senzoru: 3 VDC - 4.5 VDC

• Struja senzora: 1 – 10 uA Sleep Mode, 38 uA  Stanje čekanja, 790 uA Očitavanje blizine i geste

• Struja LED diode u senzoru: 12.5 mA – 100 mA

• Vrsta komunikacije: I2C (Two Wire)

• Maksimalna frekvencija I2C-a: 400 kHz

• Dimenzije modula: 16 x 16 mm

Kako modul radi?

Senzor na modulu je sastavljen od dva dijela; samog senzora i LED diode koja služi za određivanje blizine predmeta. U samom senzoru se nalaze četiri foto diode koje služe za detekciju geste (postavljene su na način da uspješno detektiraju pokret ruke u različitim smjerovima) i četiri foto diode koje služe za detekciju boje i intenziteta svjetla.

Blok dijagram

Svaka od tih četiri foto diode za boju mjeri intenzitet svjetla određenog opsega valnih duljina, pa tako imamo foto diodu za crvenu, zelenu i plavu boju što je izvedeno na način se da ispred foto diode nalazi određeni filtar boje. Zadnja foto dioda je čista, sadrži samo infracrveni i UV filtar, te detektira cijeli spektar boje koje foto diode za crvenu, zelenu i plavu boju detektiraju zajedno. Ona služi za određivanje intenziteta svjetla koje dolazi na senzor. Na slici dolje, vidljivo je koji spektar boja pojedinačna foto dioda detektira.

Spektar detekcije foto dioda

Detektiranje geste se bazira na tome da se promatra koliki se intenzitet svjetlosti infracrvene diode ugrađene u senzor reflektira nazad u foto diode za detekciju geste. Na slici ispod je vidljivo kako se prepoznaje određeni pokret. U, L, D, R predstavlja foto diode za detekciju geste. Ukoliko se prvo detektirala blizina predmeta na D foto diodi, zatim na L i R i s sličim countom (intenzitetom), te zatim na kraju na U diodi, to bi značilo da se dogodio pokret prema dolje.

Detekcija geste

Kod detekcije geste može se podesiti da se na INT pinu javi promjena stanja pri detekciji neke od gesti, no također se može isto to omogućiti za detekciju prepreke (predmeta), te bi nam u tom slučaju to senzor preko INT pina dojavio. To omogućava da se obavi neka vrlo brza i vrlo bitna operacija u kodu koristeći prekide (Interrupts).

Kako povezati?

Način na koji će biti povezani Croduino i naš senzor biti će opisan u nastavku. No, prije toga treba napomenuti da ovaj modul radi na 3.3 V, pa tako i pinovi za komunikaciju mogu izdržati najviše do 3.3 V, u protivnom može doći do oštećenja modula. Stoga je potrebno koristiti Logic Level Konverter Modul koji će omogućiti da Croduino i senzor mogu bez problema komunicirati.

Shema spajanja

Arduino kod

Kako bi si olakšali programiranje i korištenje ovoga modula, koristiti ćemo gotovu biblioteku za upravljanje ovim modulom. Biblioteka se može pronaći ovdje. Ukoliko ne znate kako instalirati biblioteku, pročitajte naš tutorijal.

Ovdje ćemo prikazati kako se koristi senzor geste.

#include "Wire.h" //Dodavanje Wire biblioteke
#include "SparkFun_APDS9960.h" //Dodavanje biblioteke senora
#define APDS9960_INT 2 //Definiranje Croduino pina na koji ce biti spojen INT pin sa senzora (mora biti Interrupt pin)
SparkFun_APDS9960 apds = SparkFun_APDS9960(); //Konstruktor za nasu biblioteku da bi imali pristupa funkcija koje upravaljanju senzorom
int isr_flag = 0; //Varijabla koja sluzi kao zastavica da znamo da je detektirana neka gesta
void setup() {
//Postavljamo pin na Croduinu na ulaz. Na taj pin spajamo INT pin sa senzora.
pinMode(APDS9960_INT, INPUT);
Serial.begin(9600); //Inicijalizacija serijske komunikacije i postavljanje brzine komunikacije (9600 bauda)
Serial.println(); //Ispis poruke da znamo da je komunikacija izmedju racunala i Croduina u redu
Serial.println(F("**********Test APDS-99600 Senzora – Senzor geste**********"));
//Podesavanje prekidne rutine. Ukoliko se dogodi da se na pinu broj 2 na Croduinu
//detektira pad sa logicke jedinice na logicku nulu, prekida se glavni program i "skace" se na funkciju "detekcijaGeste()"
attachInterrupt(0, detekcijaGeste, FALLING);
//Inicijalizacija biblioteke za senzor i provjera da li je senzor uopce spojen na Croduino
if ( apds.init() ) {
Serial.println(F("Inicijalizacija biblioteke za APDS-9960 senzor je uspjesna!"));
} else {
Serial.println(F("Inicijalizacija biblioteke je neuspjesna. Senzor nije pronadjen. Provjeri spojeve!"));
}
//Ako je inicijalizacija bila uspjesna, pokreni senzor
if ( apds.enableGestureSensor(true) ) {
Serial.println(F("Senzor geste je pokrenut i aktivan. Napravi neku gestu. :)"));
} else {
Serial.println(F("Nije moguce pokrenuti senzor za gestu... :("));
}
}
void loop() {
if ( isr_flag == 1 ) { //Ako je gesta detektirana, isr_flag ce biti postavljena na 1.
detachInterrupt(0); //Nemoj vise detektirati geste, da bi se mogla ocitati trenutna gesta.
gesta(); //Ocitaj trenutnu gestu
isr_flag = 0; //Vrati nazad zastavicu na 0, sto bi znacilo da se gesta jos nije dogodila.
attachInterrupt(0, detekcijaGeste, FALLING); //Ponovo postavi detekciju geste sada kada je Croduino procito o kojoj se gesti radilo.
}
}
void detekcijaGeste() { //Ukoliko je INT pin pao s logicke jedinice na logicku nulu, to znaci da je senzor ocitao neku gestu, pa je u glavnom programu ocitaj.
isr_flag = 1;
}
void gesta() { //Ovdje ocitavamo gestu s senzora i ispisujemo o kojoj gesti se radilo.
if ( apds.isGestureAvailable() ) {
Serial.print("Detektirana gesta: ");
switch ( apds.readGesture() ) {
case DIR_UP:
Serial.println("Gore");
break;
case DIR_DOWN:
Serial.println("Dolje");
break;
case DIR_LEFT:
Serial.println("Lijevo");
break;
case DIR_RIGHT:
Serial.println("Desno");
break;
case DIR_NEAR:
Serial.println("Blizu");
break;
case DIR_FAR:
Serial.println("Daleko");
break;
default:
Serial.println("Ne moze se odrediti.");
}
}
}

U daljnjem kodu, vidjet' ćemo kako se upotrebljava senzor za očitavanje razine crvene, zelene i plave bolje (RGB).

#include "Wire.h" //Dodavanje Wire biblioteke.
#include "SparkFun_APDS9960.h" //Dodavanje biblioteke senzora.
SparkFun_APDS9960 apds = SparkFun_APDS9960();
uint16_t kolcinaSvjetlosti = 0; //Varijabla za spremanje iznosa kolicine svjetlosti.
uint16_t crvenaBoja = 0; //Varijabla za iznos kolicine crvene svjetlosti.
uint16_t zelenaBoja = 0; //Varijabla za iznos kolicine zelene svjetlosti.
uint16_t plavaBoja = 0; //Varijabla za iznos kolicine plave svjetlosti.
void setup() {
Serial.begin(9600); //Inicijalizacija serijske komunikacije i postavljanje brzine komunikacije (9600 bauda).
Serial.println(); //Ispis poruke da znamo da je komunikacija izmedju racunala i Croduina u redu.
Serial.println(F("**********Test ADPS-99600 Senzora – Senzor boje**********"));
//Inicijalizacija biblioteke za senzor i provjera da li je senzor uopce spojen na Croduino.
if ( apds.init() ) {
Serial.println(F("Inicijalizacija biblioteke za APDS-9960 senzor je uspjesna!"));
} else {
Serial.println(F("Inicijalizacija biblioteke je neuspjesna. Senzor nije pronadjen. Provjeri spojeve!"));
}
//Ako je inicijalicija bila uspjesna, pokreni senzor za boju.
if ( apds.enableLightSensor(false) ) {
Serial.println(F("Senzor boje je uspjesno aktiviran. :)"));
} else {
Serial.println(F("Nije moguce prokrenuti senzor za boju... :("));
}
//Pricekajmo malo da se senzor stabilizira i kalibrira.
delay(500);
}
void loop() {
//Procitaj iznose svjetline prostora, te iznose crvene, zelene i plave boje.
//Ako nesto od toga nijie uspjesno ocitano, dojavi nam gresku.
if ( !apds.readAmbientLight(kolcinaSvjetlosti) ||
!apds.readRedLight(crvenaBoja) ||
!apds.readGreenLight(zelenaBoja) ||
!apds.readBlueLight(plavaBoja) ) {
Serial.println("Greska tijekom citanja vrijednosti sa senzora.");
} else {
Serial.print("Svjetlina prostora: "); //Ispisi vrijednosti na Serial monitoru.
Serial.print(kolcinaSvjetlosti);
Serial.print(" Crvena boja: ");
Serial.print(crvenaBoja);
Serial.print(" Zelena boja: ");
Serial.print(zelenaBoja);
Serial.print(" Plava boja: ");
Serial.println(plavaBoja);
}
//Pricekaj jednu sekundu prije novog citanja podataka sa senzora.
delay(1000);
}

U slijedećem kodu, vidjet' ćemo kako se koristi senzor blizine (eng. Proximity sensor).

#include "Wire.h" //Dodavanje Wire biblioteke.
#include "SparkFun_APDS9960.h" //Dodavanje biblioteke senora.
#define APDS9960_INT 2 //Definiranje pina na Croduinu na kojeg ce se spojiti INT pin sa senzora (mora biti Interrupt pin, Na Croduino Basic pinovi 2 i 3).
#define LED_PIN 13 //Pin na kojeg zelimo spojiti LED-icu koja ce nam dati do znanja kada je detektiran neki predmet u blizini senzora. Koristimo vec ugradjenu LED-inu u Croduinu.
#define PROX_INT_HIGH 50 //Definiramo na kojem nivoe kada da nam se aktivira senzor.
#define PROX_INT_LOW 0
// Global variables
SparkFun_APDS9960 apds = SparkFun_APDS9960(); //Konstruktor biblioteke koju koristimo.
uint8_t blizina = 0; //Varijabla u koju cemo spremati vrijednost blizine predmeta koji se detektira.
int isr_flag = 0; //Varijabla koja sluzi kao zastavica da znamo da je detektiran neki predmet u blizini senzora
void setup() {
// Set LED as output
pinMode(LED_PIN, OUTPUT); //Postavimo pin na koji se spojena LEDica na izlaz.
pinMode(APDS9960_INT, INPUT); //Postavimo pin na koji je spojen INT pin sa senzora na ulaz na Croduinu.
//Inicijaliziramo serijsku komunikaciju s racunalom i postavljamo zadanu brzinu komuniukacije (9600 bauda).
Serial.begin(9600);
Serial.println(); //Ispis poruke da znamo da je komunikacija izmedju racunala i Croduina u redu.
Serial.println(F("**********Test APDS-99600 Senzora – Senzor blizine predmeta**********"));
//Podesavanje prekidne rutine. Ukoliko se dogodi da se na pinu broj 2 na Croduinu
//detektira pad sa logicke jedinice na logicku nulu, prekida se glavni program i "skace" se na funkciju "detekcijaBlizine()".
attachInterrupt(0, detekcijaBlizine, FALLING);
//Inicijalizacija biblioteke za senzor i provjera da li je senzor uopce spojen na Croduino.
if ( apds.init() ) {
Serial.println(F("Inicijalizacija biblioteke za APDS-9960 senzor je uspjesna!"));
} else {
Serial.println(F("Inicijalizacija biblioteke je neuspjesna. Senzor nije pronadjen. Provjeri spojeve!"));
}
//Podesi pojacanje na senzoru (eng. Gain).
if ( !apds.setProximityGain(PGAIN_2X) ) {
Serial.println(F("Neuspjesno podesavanje pojacanja na senzoru."));
}
//Podesi razine detekcije na senzoru (radi prekidne rutine).
if ( !apds.setProximityIntLowThreshold(PROX_INT_LOW) ) {
Serial.println(F("Neuspjesno podesavanje niske razine detekcije."));
}
if ( !apds.setProximityIntHighThreshold(PROX_INT_HIGH) ) {
Serial.println(F("Neuspjesno podesavanje visoke razine detekcije."));
}
//Neka senzor zapocne s radom, s prekidnim nacinom rada. Kada se detektira predmet u blizini senzora, prekida se glavni program (main loop) i "skace" se na detekcijaBlizine.
if ( apds.enableProximitySensor(true) ) {
Serial.println(F("Senzor blizine je pokrenut i aktivan. Postavi predmet u blizinu senzora da bi ga aktivirao."));
} else {
Serial.println(F("Nije moguce pokrenuti senzor za blizinu... :("));
}
}
void loop() {
//Ako je nastupila detekcija predmeta u blizini senzora, onda za to obavjesti korisnika.
if ( isr_flag == 1 ) {
//Ocitaj vrijednosti blizine predmeta i ispisi to preko serijske komunikacije.
if ( !apds.readProximity(blizina) ) {
Serial.println("Neuspjesno citanje blizine predmeta.");
} else {
Serial.print("Predmet u blizini detektiran, izos: ");
Serial.println(blizina);
}
//Osim na serijskom portu, obavjesti nas i LEDicom na Croduinu. Neka LEDica trepne.
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
//VRLO BITNO! Ponisti zastavicu za prekidni program i ponisti detekciju predmeta u senzoru!
isr_flag = 0;
if ( !apds.clearProximityInt() ) {
Serial.println("Neuspjesno brisanje prekidne rutine.");
}
}
}
void detekcijaBlizine() { //Prekidni program na kojeg se skace kada se detektira neki predmet u blizini senzora.
isr_flag = 1; //Sluzi nam da bi sto prije postavili zastavicu na stanje da u glavnom programu mozemo znati da je doslo do detekcije predmeta.
}

I na kraju, u zadnjem primjeru, vidjet' ćemo kako se koristi senzor za količinu svjetla u prostoru.

#include "Wire.h" //Dodavanje Wire biblioteke.
#include "SparkFun_APDS9960.h" //Dodavanje biblioteke senora.
#define APDS9960_INT 2 //Definiranje pina na Croduinu na kojeg ce se spojiti INT pin sa senzora (mora biti Interrupt pin, Na Croduino Basic pinovi 2 i 3).
#define LED_PIN 13 //Pin na kojeg zelimo spojiti LED-icu koja ce nam dati do znanja kada je detektiran neki predmet u blizini senzora. Koristimo vec ugradjenu LEDicu u Croduinu.
//Definiramo nivoe za visoku i nisku razinu svjetlosti (odnosno kada dam nam se dojavi da je do promjene).
#define LIGHT_INT_HIGH 1000 //Nivo za visoku razinu svjetlosti
#define LIGHT_INT_LOW 10 //Nivo za nisku razinu svjetlosti
SparkFun_APDS9960 apds = SparkFun_APDS9960(); //Konstruktor biblioteke.
uint16_t svjetlost = 0; //Varijabla za kolicinu svjetla u prostoru.
int isr_flag = 0; //Varijabla koja sluzi kao zastavica da znamo da je detektiran neki predmet u blizini senzora
uint16_t prag = 0; //Varijabla za prag detekcije.
void setup() {
//Postavljamo pinove za ulaz ili izlaz
pinMode(LED_PIN, OUTPUT); //Postavimo pin na koji se spojena LEDica na izlaz.
pinMode(APDS9960_INT, INPUT); //Postavimo pin na koji je spojen INT pin sa senzora na ulaz na Croduinu.
//Inicijaliziramo serijsku komunikaciju s racunalom i postavljamo zadanu brzinu komuniukacije (9600 bauda).
Serial.begin(9600);
Serial.println(); //Ispis poruke da znamo da je komunikacija izmedju racunala i Croduina u redu.
Serial.println(F("**********Test APDS-99600 Senzora – Senzor kolicine svijetla**********"));
//Podesavanje prekidne rutine. Ukoliko se dogodi da se na pinu broj 2 na Croduinu
//detektira pad sa logicke jedinice na logicku nulu, prekida se glavni program i "skace" se na funkciju "detekcijaSvjetlosti()".
attachInterrupt(0, detekcijaSvjetlosti, FALLING);
//Inicijalizacija biblioteke za senzor i provjera da li je senzor uopce spojen na Croduino.
if ( apds.init() ) {
Serial.println(F("Inicijalizacija biblioteke za APDS-9960 senzor je uspjesna!"));
} else {
Serial.println(F("Inicijalizacija biblioteke je neuspjesna. Senzor nije pronadjen. Provjeri spojeve!"));
}
//Postavljanje razina pragova detekcije svjetlosti
if ( !apds.setLightIntLowThreshold(LIGHT_INT_LOW) ) {
Serial.println(F("Neuspjesno podesavanje praga niske razine svjetlosti"));
}
if ( !apds.setLightIntHighThreshold(LIGHT_INT_HIGH) ) {
Serial.println(F("Neuspjesno podesavanje praga visoke razine svjetlosti"));
}
//Neka senzor zapocne sa radom (ali bez prekida glavnog programa za sada).
if ( apds.enableLightSensor(false) ) {
Serial.println(F("Senzor svjetlosti je pokrenut i aktivan. Promjeni intenzitet svjetosti da bi se senzor aktivirao"));
} else {
Serial.println(F("Nije moguce pokrenuti senzor za svjetlost."));
}
// Procitaj razine pragova detekcije (da li su ispravno upisane).
if ( !apds.getLightIntLowThreshold(prag) ) {
Serial.println(F("Nije moguce ocitati prag razinu za nizak intenzitet svjetlosti"));
} else {
Serial.print(F("Razina praga za nizak intenzitet svjetlosti: "));
Serial.println(prag);
}
if ( !apds.getLightIntHighThreshold(prag) ) {
Serial.println(F("Nije moguce ocitati prag razinu za visok intenzitet svjetlosti"));
} else {
Serial.print(F("Razina praga za nizak intenzitet svjetlosti: "));
Serial.println(prag);
}
//Omoguci prekidanje programa za zadani intenzitet svjetlosti.
if ( !apds.setAmbientLightIntEnable(1) ) {
Serial.println(F("Nije moguce postaviti prekide programa na razinu svjetlosti."));
}
//Pricekajmo malo da se senzor smiri i kalibrira.
delay(500);
}
void loop() {
//Ako je zastavica postavljena na 1, prekid se dogodio, a time se predjen prag za detekciju odredjenog intenziteta svjetlosti.
if ( isr_flag == 1 ) {
//Ispisi koliki je intenzitet svjetlosti.
if ( !apds.readAmbientLight(svjetlost)) {
Serial.println("Neuspjesno ocitaje intenz. svjetlosti");
} else {
Serial.print("Intenzitet svjetlosti: ");
Serial.println(svjetlost);
}
//Neka LEDica trebne da bi se dalo do znanja da je detektirana odredjena razina svjetlosti.
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
//VRLO BITNO! Ponisti zastavicu za prekidni program i ponisti detekciju razine svijetlosti u senzoru!
isr_flag = 0;
if ( !apds.clearAmbientLightInt() ) {
Serial.println("Neuspjesno brisanje prekidne rutine.");
}
}
}
void detekcijaSvjetlosti() { //Prekidni program na kojeg se skace kada se detektira zadana razina svjetlosti..
isr_flag = 1; //Sluzi nam da bi sto prije postavili zastavicu na stanje da u glavnom programu mozemo znati da je doslo do detekcije zadane kolicine svjetlosti.
}
Leave a Reply