+ All Categories
Home > Documents > 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1....

1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1....

Date post: 12-Sep-2018
Category:
Upload: phamthuan
View: 282 times
Download: 8 times
Share this document with a friend
17
Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici 1. Intreruperi in Arduino Ne amintim din laboratorul 3 ca intreruperile sunt evenimente care necesita atentia imediata a microcontrollerului. In momentul in care se intampla un eveniment care are ca efect declansarea unei intreruperi, microcontrollerul opreste taskul pe care il executa si incepe sa se ocupe de intrerupere declansand o ISR (intrerupt service routine), o rutina care este atasata intreruperii respective. Pentru ca microcontrollerul sa raspunda la intreruperi, trebuie activat un bit (Global Intrerupt Enable) si bitul corespunzator intreruperii. Urmatoarele lucruri sunt esentiale in momentul in care lucrati cu intreruperi: - Intreruperea trebuie sa fie activata activand bitul corespunzator din registrul corespunzator - Bitul Global corespunzator intreruperilor, I, din SREG trebuie si el activat - Stiva trebuie initializata. In momentul in care se realizeaza o intrerupere, inainte de a intra in procedura dedicata trebuie sa stocam informatiile esentiale pe stiva pentru a nu le pierde la revenirea din rutina; asadar stiva trebuie initializata - Fiecare rutina se finalizeaza cu RETI. In acel moment microcontrollerul stie sa se intoarca la taskul precedent Intreruperile sunt de doua feluri : interne si externe. Intreruperile interne sunt asociate cu perifericele microcontrollerului (Timer/Counter intrerupts, Analog comparator etc.) Intreruperile externe sunt declansate de pini externi (amintiti-va de intreruperile declansate de apasarea butoanelor PMOD sau butoanelor tastaturii). Fiecare avr are o lista de intreruperi, care include tipul de eveniment care va declansa intreruperea. In momentul in care intreruperile sunt activate si unul din aceste evenimente se intampla procesorul va realiza un salt in memorie la o anumita locatie (vectorul intreruperii, locatie pe care o va gasi in lista/tabela de intreruperi). Scriind o ISR si apoi facand un link rutinei la adresa locatiei intreruperii corespunzatoare, putem sa ii spunem sistemului sa realizeze ceva specific in momentul in care evenimentul declanseaza intreruperea. In primul exemplu, vom folosi o intrerupere declansata de butoane si vom afisa pe LCD un mesaj corespunzator butoanelor. In momentul in care butonul este apasat se declanseaza intreruperea si programul afiseaza un mesaj pe LCD. Pentru acest exemplu aveti nevoie de o placa Arduino, un afisor LCD, un modul pModBtn si un bread board. Atmega 2560 are 6 pini de intrerupere. Pentru a vedea lista de pini si intreruperile corespunzatoare accesati linkul 1. Vom conecta butoanele la pinii corespunzatori intreruperilor INT0 si INT1, adica pinii digitali 20 si 21. In figura 1 se observa o imagine a conexiunilor necesare, iar mai jos codul corespunzator programului.
Transcript
Page 1: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

Laborator 7

1. Intreruperi in Arduino

2. Generare de semnale PWM in Arduino

3. Senzori Analogici

1. Intreruperi in Arduino

Ne amintim din laboratorul 3 ca intreruperile sunt evenimente care necesita atentia imediata a

microcontrollerului. In momentul in care se intampla un eveniment care are ca efect

declansarea unei intreruperi, microcontrollerul opreste taskul pe care il executa si incepe sa se

ocupe de intrerupere declansand o ISR (intrerupt service routine), o rutina care este atasata

intreruperii respective. Pentru ca microcontrollerul sa raspunda la intreruperi, trebuie activat

un bit (Global Intrerupt Enable) si bitul corespunzator intreruperii. Urmatoarele lucruri sunt

esentiale in momentul in care lucrati cu intreruperi:

- Intreruperea trebuie sa fie activata activand bitul corespunzator din registrul corespunzator

- Bitul Global corespunzator intreruperilor, I, din SREG trebuie si el activat

- Stiva trebuie initializata. In momentul in care se realizeaza o intrerupere, inainte de a intra

in procedura dedicata trebuie sa stocam informatiile esentiale pe stiva pentru a nu le

pierde la revenirea din rutina; asadar stiva trebuie initializata

- Fiecare rutina se finalizeaza cu RETI. In acel moment microcontrollerul stie sa se intoarca

la taskul precedent

Intreruperile sunt de doua feluri : interne si externe. Intreruperile interne sunt asociate cu

perifericele microcontrollerului (Timer/Counter intrerupts, Analog comparator etc.)

Intreruperile externe sunt declansate de pini externi (amintiti-va de intreruperile declansate de

apasarea butoanelor PMOD sau butoanelor tastaturii).

Fiecare avr are o lista de intreruperi, care include tipul de eveniment care va declansa

intreruperea. In momentul in care intreruperile sunt activate si unul din aceste evenimente se

intampla procesorul va realiza un salt in memorie la o anumita locatie (vectorul intreruperii,

locatie pe care o va gasi in lista/tabela de intreruperi). Scriind o ISR si apoi facand un link

rutinei la adresa locatiei intreruperii corespunzatoare, putem sa ii spunem sistemului sa

realizeze ceva specific in momentul in care evenimentul declanseaza intreruperea.

In primul exemplu, vom folosi o intrerupere declansata de butoane si vom afisa pe LCD un

mesaj corespunzator butoanelor. In momentul in care butonul este apasat se declanseaza

intreruperea si programul afiseaza un mesaj pe LCD. Pentru acest exemplu aveti nevoie de o

placa Arduino, un afisor LCD, un modul pModBtn si un bread board. Atmega 2560 are 6 pini

de intrerupere. Pentru a vedea lista de pini si intreruperile corespunzatoare accesati linkul 1.

Vom conecta butoanele la pinii corespunzatori intreruperilor INT0 si INT1, adica pinii digitali

20 si 21. In figura 1 se observa o imagine a conexiunilor necesare, iar mai jos codul

corespunzator programului.

Page 2: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

Fig 1. Conexiunile necesare primului exemplu

//includem headerul responsabil pentru operatii

//cu intreruperi pentru avr

#include "avr/interrupt.h"

//include libraria de manipulat LCD

#include <LiquidCrystal.h>

//initializeaza lcd-ul la valorile stabilite ale pinilor

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

volatile int buttonVariable;

void setup(void)

{

buttonVariable = 0;//initializam variabila shared intre ISR si programul principal

Serial.begin(9600); //deschidem conexiunea seriala

Serial.println("A inceput");//afisam un mesaj la consola pentru a vedea ca a inceput

comunicarea

//seteaza numarul de randuri si coloane ale LCD-ului

lcd.begin(16, 2);

lcd.print("The show has begun");

delay(1000);//facem o scurta pauza pentru a vizualiza mesajul de pe ecran

pinMode(21 ,INPUT); //setam pinul 21 ca si pin de input; acesta este pinul pe care se

afla intreruperea 0 INT0

pinMode(13, OUTPUT); //setam pinul 13 ca si pin de output

pinMode(20, INPUT);

digitalWrite(20, HIGH);

digitalWrite(21,HIGH);//facem pentru pinul 21 sa fie tras in 1 printr-un rezistor de tip

pull up

digitalWrite(13,HIGH);

delay(1000);

sei(); //activam intreruperile si flaglul de intreruperi din SREG va fi setat in 1

Page 3: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

EIMSK |= (1 << INT0); //activam intreruperea INT0

EIMSK |= (1 << INT1); //activam intreruperea INT1

EICRA |= (1 << ISC01); //activam intreruperea cand semnalul este pe falling edge.

EICRA |= (1 << ISC11);// ca si mai sus

//amintiti-va ca pe eicra setam cand si cum vrem sa activam inpulsul ex : front

crescator, descrescator, pe nivel pozitiv sau negativ

digitalWrite(13,LOW);

Serial.println(EICRA,BIN);//afisam valoarea din EICRA

Serial.println(EIMSK,BIN);//afisam valoarea din EIMSK

lcd.clear();//curatam ecranul

}

void loop()

{

//DO NOTHING

if(buttonVariable == 1)//daca am fost intr-o rutina trebuie sa stergem ecranul si sa

afisam iar mesajul din principal

{

lcd.clear();//curatam ecranul

buttonVariable = 0;

}

delay(1000);

Serial.println("Acum nu se intampla nimic");//afisam un mesaj

lcd.setCursor(0,0);//setam cursorul

lcd.print("Voi stiti asta..");//afisam mesaj

}

//Rutina pentru handlingul intreruperii atasata la INT0

ISR(INT0_vect)

{

digitalWrite(13, !digitalRead(13));//facem toggle la pinul 13

lcd.setCursor(0,0);//setam cursorul

lcd.print("Intrerupem");//afisam mesaj

lcd.setCursor(0,1);

lcd.print("ptr stirea zilei");

buttonVariable = 1;

}

ISR(INT1_vect)

{

digitalWrite(13, !digitalRead(13));

lcd.clear();

lcd.setCursor(0,0);

lcd.print("Stirea Doi");

buttonVariable = 1;

}

Este bine sa ne tinem ISR-urile cat mai scurte intrucat programul principal este oprit in acele

momente asteptand terminarea rutinei.

Tineti minte ca delay() si millis() nu functioneaza „pe parcursul” unei rutine de intrerupere.

Acest lucru se intampla pentru ca intreruperile globale sunt dezactivate pe parcursul unei

Page 4: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

rutine. Acest lucru deterimina ca in cazul in care un alt eveniment corespunzator unei alte

intreruperi se declanseaza programul nu va putea prinde acea intrerupere (de aceea e

important ca tot ce este scris in codul rutinei sa fie cat de scurt posibil). De asemenea, daca

vreti sa modificati o variabila in interiorul unei rutine si doriti ca valoarea acestei variabile sa

fie vizibila in tot programul faceti acea variabila de tipul volatile. Introducand volatile

inaintea tipului variabilei informam compilatorul ca variabila este o variabila shared.

Arduino ne permite sa utilizam sistemul de intreruperi si fara avea cunostinte specifice despre

mecanismul specific microcontrollerului, punandu-ne la dispozitie anumite functii. Prima

functie pe care o vom prezenta este attachIntrerrupt(). Functia aceasta are rolul de a atasa

un anumit ISR la o intrerupere, de a inlocuii orice functie precedenta care a fost atasata la

intreruperea respectiva. Sintaxa este attachInterrupt(interrupt, ISR, mode). Primul pin la

functia attach interrupt reprezinta numarul intreruperii.

!!Atentie Pinii digitali de pe arduino corespnzatori intreruperii nu sunt aceasi cu pinii chipului

atmega2560 si nu sunt la fel cu numarul intreruperii pe care trebuie sa o introducem in

functia attachinterrupt(). Distinctia dintre pini este specificata in tabelul de mai jos:

Fig 2. Numarul care trebuie introdus in attach intrerrupt

pentru o anumita intrerupere din atmega2560.

Al doilea prametru din aceasta functie reprezinta procedura care e asociata intreruperii(ISR).

Al treilea parametru reprezinta modul in care ar trebuii sa fie declansata intreruperea (pe front

crescator (RISING), descrescator (FALLING), pe nivel o (LOW) sau nivel 1 (HIGH) sau

pur si simplu cand se intampla o schimbare ex – pinul atasat intreruperii isi schimba

valoarea(CHANGE)).

Functia noInterrupts() dezactiveaza intreruperile. Acestea pot fi reactivate cu functia

interupts().

Functia interrupts() reactiveaza intreruperile dupa ce au fost dezactivate cu functia

noInterrupts in prealabil. Intreruperile permit anumitor taskuri importante sa se execute in

fundal si sunt activate implicit. Intreruperile pot afecta negativ anumite sectiuni de cod si de

aceea pe durata acelor sectiuni de cod ele se dezactiveaza, urmand sa fie reactivate ulterior.

Functia detachInterrupt() dezactiveaza o intrerupere al carei numar este pasat ca si

parametru. Sintaxa este detachInterrupt(interrupt);

Exemplul anterior a fost implementat folosind registri de configurare ai AVR, echivalentul in

C++ al abordarii din laboratorul 3. In continuare, vom prezenta un exemplu cu functionalitate

Page 5: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

similara, realizat cu ajutorul mediului de programare Arduino. Codul care se repeta din

exemplul precedent nu il vom mai comenta.

#include <LiquidCrystal.h>

LiquidCrystal lcd(7,6,5,4,3,2);

volatile int buttonVariable;

void setup()

{

buttonVariable = 0;

Serial.begin(9600);

Serial.println("A inceput");

lcd.begin(16,2);

lcd.print("The show has begun");

lcd.setCursor(0,1);

lcd.print("again");

delay(1000);

//atasam intreruperii zero functia unu care sa se declanseze cand //pinul isi schimba

valoarea

digitalWrite(20, HIGH);

digitalWrite(21,HIGH); attachInterrupt(2, functieUnu, RISING);

attachInterrupt(3, functieDoi, CHANGE);

}

void loop()

{

//aici sunt taskuri care se executa in mod normal cand se ruleaza //programul

Serial.println("Tasks that are executed");

delay(1000);

}

//prima ISR

void functieDoi()

{

lcd.clear();

lcd.setCursor(0,0);

lcd.print("Functia Doi");

}

//a doua ISR

void functieUnu()

{

lcd.clear();

lcd.setCursor(0,0);

lcd.print("Functia Unu");

}

In afara intreruperilor externe, exista si intreruperi interne, care nu sunt cauzate de evenimente

pe pinii exteriori, ci de componente hardware incluse in microcontroller. In aceasta categorie

sunt incluse intreruperile de timer.

Page 6: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

Prin utilizarea acestor intreruperi, puteti genera actiuni la intervale precise de timp, fara a

utiliza functii de tip delay sau millis. Intreruperile de temporizatoare functioneaza asincron,

lucru care permite ca programul sa execute bucla principala si doar cand s-a ajuns la un

anumit prag de timp sa se declanseze o rutina specifica. Timerul incrementeza un registru

numit counter register si in momentul in care apare un overflow un flag de overflow se

seteaza. Acest flag poate fi verificat manual sau putem atasa o intrerupere in caz de overflow.

Rutina (ISR) va reseta si flagul. Fiecare timer are nevoie de sursa de clock. In general se alege

ca si sursa oscilatorul placii si in functie de acesta se determina si rezolutia timerului ( tineti

minte formula T = 1/ F unde F e frecventa in Hz).

Arduino Mega are 5 timere care pot fi folosite. Pentru a folosi aceste timere va trebuii sa

setam valori specifice pentru configurarea temporizatoarelor. Doua din aceste registre contin

valori de configurare si sunt TCCRxA si TCCRxB, unde x este numarul temporizatorului.

TCCR vine de la Timer Counter Control Register. Cand incepem sa folosim timerul cei mai

importanti sunt cei trei biti de control care seteaza cum sa fie scalat timerul. In figura 3

observati registrii A si B si posibile configurari pentru ultimii biti ai registrului de timer.

Fig 3 Configurarea temporizatorului.

Implicit cei trei biti sunt setati la 0. Pentru a sumariza, mai jos sunt cei mai importanti registrii

care se folosesc cu temporizatoare.

- TCCRx - Timer/Counter Control Register. Valoarea de pre scalling poate fi stabilita aici

- TCNTx - Timer/Counter Register. Valoarea actuala este stocata aici. Aici puteti vedea

valoarea adevarata a timerului.

- OCRx - Output Compare Register

- ICRx - Input Capture Register (only for 16bit timer)

Page 7: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

- TIMSKx - Timer/Counter Interrupt Mask Register. Pentru activarea sau dezactivarea

intreruperilor de timp

- TIFRx - Timer/Counter Interrupt Flag Register. Indicates a pending timer interrupt.

Registrii A si B sunt descrisi in figura 4 de mai jos.

Fig 4 Registrii Importanti de timere in AVR

In exemplu care va urma vom incrementa o variabila in momentul in care timerul

nostru(TIMER1) va face overflow. Valoarea incrementarii la overflow va fi afisata pe LCD.

#include <avr/io.h>

#include <avr/interrupt.h>

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

volatile int myVar;

void setup()

{

myVar = 0;

//initializarea primului numarator

cli(); //facem disable la intreruperile globale pentru a face //modificarile

corespunzatoare timerelor

TCCR1A = 0;// SETAM TCCR1A si B la 0

TCCR1B = 0;

lcd.begin(16, 2);

lcd.print("Timere");

//facem enable la intrerupere de overflow pentru timerul 1

TIMSK1 = (1 << TOIE1); //timer overflow intrerupt eneble for timer 1

//setam timerul sa ruleze o frecventa divizata cu 1024

//DE MENTIONAT CA FRECVENTA PROCESORULUI e de 16 MHZ si timer 1

//este un timer de 16 biti

//cu un prescaller de 1024 avem de a face cu v = 1 / (16 * 10 ^6)

//timerul va da overflow la fiecare 4.194 s ( v * 2 ^ 16)

TCCR1B |= (1 << CS10);

TCCR1B |= (1 << CS12);

//activam intreruperile globale

sei();

Page 8: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

}

void loop()

{

// Serial.println("Ruleaza programul");

lcd.setCursor(0,1);

lcd.print(myVar);

lcd.setCursor(5, 1);

lcd.print(TCNT1);

}

ISR(TIMER1_OVF_vect)

{

myVar = myVar + 1;

}

Pentru a face ca intreruperea de timer de la avr sa se declanseze la un anumit moment (nu

atunci cand counterul face overflow) vom folosi un alt mod de declansare al intreruperii numit

CTC. Pentru a stabilii de cate cicluri de ceas sunt necesare pentru a ajunge la noul puls al

timerului nostru folosim formula (1)

(# timer counts + 1) = (target time) / (timer resolution) (1)

In aceasta formula target time reprezinta timpul la care vrem sa ajungem, timer resolution

reprezinta rezolutia clockului actual, setat prin intermediul bitilor CS (in exemplul precedent

1024) iar timer counts reprezinta valoarea la care va trebuii sa ne divizam clockul pentru a

obtine target time-ul dorit. Se ia valoarea + 1 intrucat resetarea valorilor timerului in

momentul in care a ajuns la valoarea dorita dureaza un ciclu de ceas.

#include <avr/io.h>

#include <avr/interrupt.h>

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

volatile int myVar;

void setup()

{

// initialize Timer1

cli(); // facem disable la intreruperile globale

TCCR1A = 0; // setam TCCR1A si B la 0

TCCR1B = 0;

lcd.begin(16, 2);

lcd.print("Timere with CTC");

// setam registrul cu valoarea caruia vom compara TCNT

OCR1A = 15624;

// activam modul CTC:

TCCR1B |= (1 << WGM12);

// divizam clockul placii cu 1024:

TCCR1B |= (1 << CS10);

TCCR1B |= (1 << CS12);

// facem enable la modul de comparare prin setarea bitului

Page 9: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

//corespunzator din masca

TIMSK1 |= (1 << OCIE1A);

// enable global interrupts:

sei();

}

void loop()

{

lcd.setCursor(0,1);

lcd.print(myVar);

lcd.setCursor(5, 1);

lcd.print(TCNT1);

}

ISR(TIMER1_COMPA_vect)

{

myVar = myVar + 1;

}

Spre deosebire de exemplul anterior in care incrementam variabila doar la overflow (la

aproximativ 4 secunde) in acest exemplu avem mai mult cotrol asupra perioadei de

incrementare a variabilei noastre; variabila se incrementeaza la fiecare secunda.

In continuare vom vedea o alta metoda pentru utilizarea temporizatoarelor, folosind biblioteca

TimerOne. Exemplul de mai jos va activa o rutina la fiecare secunda. Biblioteca Timer One

poate fi descarcata de pe site-ul Arduino, de la adresa [2].

#include <TimerOne.h>

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

volatile int myVar;

void setup(void)

{

Timer1.initialize(1000000);//se initializeaza valoarea CTC a temporizatorului

//de fiecare data cand acea valoare va fi atinsa se va executa functia de mai jos

//

Timer1.attachInterrupt(ShowMessage); // increment variable to run every 1 second

}

void ShowMessage(void)

{

lcd.setCursor(0,0);

lcd.print(myVar);

myVar++;

}

void loop(void)

{

Page 10: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

}

Observatie In exemplele precedente ati vazut cum se pot folosii fie functii avr pentru manipularea

intreruperilor, fie librarii din mediul arduino. Desi librariile arduino simplifica mult lucrurile,

recomandam sa se studieze si sa se inteleaga si functiile avr, intrucat daca veti dori vreodata

sa manipulati alte microcontrollere care nu sunt compatibile cu librariile din arduino nu veti

avea fundamentarea tehnica pentru a le folosi.

2. Generare de semnale PWM in Arduino

PWM este o metoda de a obtine un semnal analogic prin intermediul unui semnal digital

generand tensiuni de 1 si 0 la anumite perioade de timp. Fractiunea de perioada cat semnalul

este activ (1 logic) se numeste factor de umplere, sau duty cycle. In Arduino se poate folosi

PWM in trei moduri, fie prin temporizatoare, fie folosind functia analogWrite, sau variind

manual durata cat un pin este activ (1 logic).

In aceasta parte vom folosi functia analogWrite(factor de umplere). Valorile posibile pentru

analogWrite sunt de la 255 care reprezinta 5V la 0. Factorul de umplere de 50% se realizeaza

pentru valoarea 127. In figura 5 veti obsera cateva exemple de PWM.

Fig. 5 Exemple PWM cu factor de

umplere diferit

In exemplul care va urma vom genera un semnal PWM pentru generatorul de sunete

piezoelectric. PWM-ul care va fi atasat buzerului va fi afisat si pe ledul pinului 13 al Arduino

Mega. Montajul pentru acest exemplu este unul simplu, nemaifiind nevoie de o imagine. Pinul

de semnal al difuzorului (firul rosu) se conecteaza la pinul 9 pe placa iar firul negru la GND.

Ledul pinului 13 este deja pe placa.

int buzerPin = 9; //pinul la care atasam buzerul

int puls = 0; // pwm-ul care il dam perifericelor

int pas = 10; // pasul de incrementare al pwm-ului

int ledPin = 13;//ledul este cel de pe placa

void setup() {

Page 11: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

// declararea pinilor ca pini de output

pinMode(buzerPin, OUTPUT);

pinMode(ledPin, OUTPUT);

}

void loop() {

// setam pwm-ul buzerului si ledului

analogWrite(buzerPin, puls);

analogWrite(ledPin, puls);

// modificam pwm-ul pentru urmatoarea iteratie

puls = puls + pas;

// schimbam directia de fading

if (puls == 0 || puls == 255) {

puls = -puls ;

}

// un mic delay pentru a vedea efectul

delay(30);

}

3. Senzori Analogici

Microcontrollerele sunt capabile sa detecteze semnale binare, 0 sau 1, cum este de

exemplu starea unui buton (apasat sau ridicat). Aceste semnale se numesc semnale digitale.

Cand un microcontroller este alimentat de la 5 V el intelege valoarea tensiunii de 5V ca si 1

logic si 0V ca si 0 logic. Cu toate acestea noi avem nevoie sa masuram si altfel de semnale in

lumea reala, semnale intermediare valorilor extreme (de exemplu, 2.57 V). Aceste semnale

contin informatie relevanta in nivelul tensiunii lor, si poarta numele de semnale analogice.

Un ADC (convertor analog la digital) converteste un semnal analogic la un numar. Prin

intermediul acestui dispozitiv avem posibilitatea de a interfata tot felul de periferice la

microcontrollerul nostru si de a masura informatiile analogice din jurul nostru. Nu toti pinii de

pe arduino pot face astfel de conversii. Pinii care pot fi folositi impreuna cu senzori analogici

sunt pinii care au un ‚A’ im fata numelui lor pe placa. Pinii incercuiti cu rosu in figura 6.

Fig 6 Pinii Analogici din Arduino Mega

Page 12: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

ADC-urile pot varia mult intre diferite tipuri de microcontrollere. Spre exemplu pe Arduino

Mega avem ADC-uri care au o precizie de 10 biti. Acest lucru inseamna ca aceste convertoare

pot detecta pana la 1024 valori. Exista si adc-uri care au rezolutie de 8 sau 16 biti. ADC-ul

intoarce o valoare ratiometrica. Asta inseamna ca adc-ul considera 5 V ca 1023 si orice

valoare mai mica ca si 5V va fi construita ca si o fractie intre 5V si 1023 (2).

�����

��� �� � ���

� �� �� �� ������ � ��� (2)

Pinii analogici de pe arduino pot fi folositi si ca pini de tip I/O general (GPIO), ei avand

aceleasi functionalitati ca si pinii digitali, in cazul in care cei oferiti de placa nu sunt

suficienti. Pinii analogici de pe placa au la randul lor pull up rezitors. Sintaxa arduino pentru

activarea acestor rezistori este similara cu cea de la pinii digitali: digitalWrite(A0,

HIGH);//pinul A0 fiind setat ca input.

Pentru citirea unei valori de la un senzor se foloseste comanda analogRead().

!!Atentie Comanda analogRead() nu va functiona corect daca pinul de pe care incercati sa cititi a fost

setat ca si pin de output.

Datasheetul de la ATMEGA mai avertizeaza despre folosirea senzorilor analogici in pozitii

apropiate. In momentul in care realizam o citire daca executam rapid switching-ul intre

pozitiile pe care dorim sa le citim, se vor introduce zgomote in citirea semnalului. Se

recomanda folosirea unui mic delay() inaintea citirii unei valori analogice consecutive.

O alta functie importanta legata de utilizarea senzorilor analogici o reprezinta

analogReference().

Pentru a masura o tensiune analogica trebuie sa existe o tensiune de referinta fata de care sa o

raportam. Functia analogReference() seteaza tensiunea maxima cu care sa efectuam

masuratoarea.

Configuratii posibile pentru aceasta referinta sunt :

- DEFAULT – foloseste tensiunea de referinta a placii (5V pentru placile Arduino care

folosesc tensiune de 5V sau 3.3 V pentru placi cu tensiune de referinta de 3.3 V).

- INTERNAL – seteaza o tensiune de referinta de 1.1 V. Poate fi folosita pe placile care

contin ATMEGA 328 spre exemplu dar nu poate fi folosita pe ATMEGA2560.

- INTERNAL1V1 – Tensiune de referinta de 1.1 V folosita pe placile MEGA

- INTERNAL2V56 – tensiune de referinta de 2.56 V aceasta e valabila doar pe placile

MEGA

- EXTERNAL – tensiune aplicata pinului AREF. Aceasta tensiune este intre 0 si 5V.

Folositi tensiunea de referinta cea mai buna pentru senzorul analog utilizat. Ideal, referinta

trebuie sa fie valoarea maxima pe care o poate genera senzorul analogic, pentru a obtine o

rezolutie cat mai buna la conversia in digital. Daca referinta este mai mica decat valoarea

maxima pe care o poate avea semnalul, tensiunea ce depaseste valoarea de referinta nu va

putea fi cuantizata, ea generand la digitizare valoarea de saturatie 1023.

Page 13: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

In exemplul urmator vom citi valoarea de la un potentiometru liniar. Valoarea citita va fi

afisata pe LCD. Circuitul pentru acest exemplu este ilustrat in figura 7. (legati pinii VCC si

GND ai potentiometrului la +5V si GND de pe placa, si semnalul de iesire la un pin

analogic)

Fig 7 Conexiunile pentru exemplul cu senzorii analogici

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

void setup()

{

analogReference(DEFAULT); //setarea tensiunii de referinta la tensiunea default

lcd.begin(16, 2); //initializarea LCD ului

lcd.setCursor(0,0);

lcd.print("Cititi senzor");

pinMode(A1, INPUT); // setarea pinului analogic A1 ca si pin de input

digitalWrite(A1, HIGH); //activarea rezistorului pull up pentru pinul A1

}

void loop()

{

int val = analogRead(A1); //citirea valorii analogice

lcd.setCursor(0,1);

lcd.print(val);

}

In al doilea exemplu pe care il vom realiza vom folosi o tastatura analogica (Fig 8)

Page 14: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

Fig 8. Tastatura analogica

Nu vom intra in foarte mare detaliu in functionarea acestei componente. Important este ca la

apasarea unei taste, in functie de tensiunea de alimentare, pe pinul Vout se transmite o

anumita tensiune. In imaginea de mai jos( fig 9) aveti tensiunile pentru fiecare tasta.

Fig 9. Valori in functie de tasta apasata

In momentul in care aveti mai mult de o tasta apasata se va afisa valoarea tensiunea celei mai

mari.

Pentru exemplul acesta veti avea nevoie de un LCD shield si o tastatura analogica. Realizati

montajul din figura 10 (legati semnalele VCC si GND ale tastaturii la +5V si GND de pe

placa, si semnalul de iesire al tastaturii la un pin analogic) iar apoi introduceti codul de

mai jos.

Page 15: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

Fig 10 Montaj pentru tastatura cu LCD

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

//se creaza o valoare intermediara in asa fel incat

//sa nu stergem ecranul LCD ului doar cand valoarea se modifica

int valIntermediar;

void setup()

{

//setam tensiunea de referinta la 5V

analogReference(DEFAULT); //setarea tensiunii de referinta la tensiunea default

lcd.begin(16, 2); //initializarea LCD ului

lcd.setCursor(0,0);

lcd.print("Cititi senzor");

pinMode(A1, INPUT); // setarea pinului analogic A1 ca si pin de input

digitalWrite(A1, HIGH); //activarea rezistorului pull up pentru pinul A1

//initializam valoarea intermediara la o valoare foarte mare

valIntermediar = 1000;

}

void loop()

{

int val = analogRead(A1); //citirea valorii analogice

//luam tasta aferenta tensiunii analogice

val = getTasta(val);

if(valIntermediar != val)

{

//setam ca noua valoare intermediara sa fie egala cu val

valIntermediar = val;

lcd.clear();//curatam ecranul

lcd.setCursor(0,0);

lcd.print("Cititi senzor");

lcd.setCursor(0,1);//si afisam noua valoare

Page 16: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

lcd.print(valIntermediar);

}

}

/*

in aceasta functie se paseaza ca si parametru o valoare analogica

si se returneaza o tasta corespunzatoare acelei valori

Din cauza faptului ca semnalul analogic nu este filtrat si stabilizat acesta

fluctueaza in continuu.

Pentru a prinde doar acele valori care ne intereseaza se face o histereza

Intervalele au fost alese experimental, bineinteles bazandu-ne si pe tensiunile din data

sheet.

*/

int getTasta(int val)

{

if(val > 10 && val < 40) return 0;//nu e apasata nici o tasta

else if(val > 50 && val < 80)return 12;//e apasata tasta 12

else if(val > 90 && val < 120) return 11; //e apasata tasta 11

else if(val > 120 && val < 160) return 10;

else if(val > 160 && val < 200) return 9;

else if(val > 200 && val < 240)return 8;

else if(val > 240 && val < 290) return 7;

else if(val > 290 && val < 320) return 6;

else if(val > 320 && val < 370) return 5;

else if(val > 370 && val < 410) return 4;

else if(val > 410 && val < 450) return 3;

else if(val > 450 && val < 490) return 2;

else if(val > 490 && val < 530) return 1;

}

!!!Atentie Una dintre probleme atunci cand lucram cu senzori analgici este ca valorie citite fluctueaza

destul de mult. Acest lucru poate fi reparat hardware punand un condensator sau un filtru

trece jos pentru a ameliora efectul spike-urilor sau mai poate fi reparat software fie printr-o

variabila intermediara fie citirea a n valori si afisarea mediei lor aritmetice ca fiind valoarea

de la senzor.

Lucru Individual

1. Implementati toate exemplele din laborator. Intrebati cadrul didactic pentru orice

nedumerire legata de conceptele din laborator sau conectivitatea cu placa.

2. Night Light. Realizati un sistem care sa faca urmatoarele – sa citeasca datele de la un

senzor de lumina si cu cat valoarea citita de la senzorul de la lumina scade cu atat nivelul

de iluminare la un led va creste. Pentru acest punct aveti nevoie de un senzor de lumina

brick, un led sau un grup de leduri (folositi pmodurile), o placa arduino si fire de

conectare.

3. Ceas electronic. Realizati un ceas electronic pentru secunde si minute. Valoarea initiala

pentru secunde si minute va fi setata de la tastatura analogica. Cand apasati un buton(nu

de pe tastatura) acea valoare va fi setata. In momentul in care ceasul ajunge la o anumita

valoare (scrisa in cod) se va declansa o alarma pe difuzor si se va afisa mesajul

Page 17: 1. Intreruperi in Arduino - users.utcluj.rousers.utcluj.ro/~rdanescu/pmp-lab7.pdf · Laborator 7 1. Intreruperi in Arduino 2. Generare de semnale PWM in Arduino 3. Senzori Analogici

„Desteptarea” pe lcd. Pana la atingerea punctului alarmei se afiseaza valoarea curenta a

ceasului.

Pentru acest proiect aveti nevoie de o placa arduino, un lcd shield, un difuzor, o tastatura

analogica, un modul Pmod BTN, fire de conectare.

Referinte

[1] http://arduino.cc/en/Hacking/PinMapping2560

[2] https://github.com/PaulStoffregen/TimerOne


Recommended