Sunteți pe pagina 1din 14

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

Lucrare 5 Butoane i sistemul de ntreruperi

Coninutul lucrrii pe scurt:


Prezentarea modulului de conectarea a unui buton la placa
Arduino Uno
Modaliti de configurare a ntreruperilor externe
Exemplu de numrtor i cronometru cu butoane i activare
direct a sistemului de ntreruperi externe

Echipamente necesare lucrrii:


Plac de dezvoltare Arduino Uno sau compatibil
Cablu de conectare USB
2 breadboard-uri 30 pini sau 1 breadboard 60 + pini + fire
de interconectare
3 butoane, 3 rezistoare 10kohm, 3 condesatoare 100nF
2 shift-register TPIC6B595
2 rezistoare 220ohm
Afiaj pe 7 segmente 2 caractere anod comun

Seciuni lucrare:
Modaliti de conectare a unui buton
Modaliti de manipulare software a intrrilor digitale
Exemplu de activare direct a ntreruperilor externe
Proiect numrtor pe dou caractere i trei butoane
Proiect cronometru pe dou caractere i trei
butoane
Referine online

49

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

Modaliti de conectare a unui buton


Butoanele i comutatoarele (butoane fr revenire) reprezint cele mai simple exemple
de intrri pentru un sistem embedded. Astfel de dispozitive sunt capabile s trag n 0
logic sau 1 logic un pin de intrare de uz general semnaliznd n acest mod sistemului
o comand sau o condiie de intrare.
Imaginea de mai jos prezint schema clasic de conectare a trei butoane la trei pini de
intrare a plcii Arduino (Buton 1 PIN2, Buton 2 PIN3, Buton 3 PIN4) cu comand
pe 0 logic la apsarea unui buton starea pin-ului de intrare va trece din 1 logic n
0 logic.

Microcontrolerele Atmel AVR dispun de o rezisten de


pull-up intern care poate fi programat software (pinul
trebui s fie configurat ca intrare i n registrul de ieire
s fie nscris 1). Din acest motiv conectarea unui buton
la placa Arduino se poate face direct fr unei
rezistene de pull-up externe (imaginea de pe pagina
urmtoare).
Atenie!!! Conectarea direct a unui buton la un pin al
plcii Arduino fr activarea software a rezistenei de
pull-up intern poate distruge fizic pinul de intrare
datorit curentului tranzitoriu foarte mare care apare la
nchiderea contactului. Nu se recomand utilizarea unei
astfel de schem deoarece o simpl omisiune software
n timpul dezvoltrii poate conduce la distrugeri
hardware.
50

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

O alt problem care apare n cazul utilizrii unei element de


tip buton sau comutator este fenomenul de bounce. Datorit
imperfeciunilor mecanice ale contactelor electrice la
nchiderea sau la deschiderea elementelor apare un fenomen
de oscilaie a semnalului care poate conduce la citirea
eronat a comenzii (citire multipl). Pentru a evita aceast
situaie se utilizeaz un condensator (schema de mai jos)
pentru a netezi semnalul de trecere dintr-un nivel logic n
cellalt.

51

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

Modaliti de manipulare software a intrrilor


Mediul Arduino IDE pune la dispoziia programatorului funcia digitalRead(pin)
care returneaz starea pinului dorit. Pinul citit se poate configura n prealabil ca fiind de
intrare pinMode(pin, INPUT) dar avnd n vedere faptul c dup reset toii pinii
microcontrolerului sunt configurai implicit ca intrri acest lucru nu este obligatoriu dect
n cazul n care pinul respectiv a fost configurat anterior ca ieire.
Plecnd de la schema din seciunea anterioar (cu sau fr debouncing hardware dar
cu rezisten extern de pull-up) se poate testa programul urmtorul program pentru o
exemplificare a funciei digitalRead .
const int buton1 = 2;
const int buton2 = 3;
const int buton3 = 4;
int a1 = 0;
int a2 = 0;
int a3 = 0;
void setup() {
pinMode(buton1, INPUT);
pinMode(buton2, INPUT);
pinMode(buton3, INPUT);
Serial.begin(9600);
}
void loop(){
if (digitalRead(buton1) == LOW) {
a1++;
Serial.print("Butonul 1 s-a apasat butonul de ");
Serial.print(a1,DEC);
Serial.print(" ori.");
Serial.println();
//debouncing software
delay(200);}
if (digitalRead(buton2) == LOW) {
a2++;
Serial.print("Butonul 2 s-a apasat butonul de ");
Serial.print(a2,DEC);
Serial.print(" ori.");
Serial.println();
//debouncing software
delay(200);}
52

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

if (digitalRead(buton3) == LOW) {
a3++;
Serial.print("Butonul 3 s-a apasat butonul de ");
Serial.print(a3,DEC);
Serial.print(" ori.");
Serial.println();
//debouncing software
delay(200);
}
}

Se observ c citirea celor trei butoane presupune o bucl infinit care verific continuu
starea pinilor la care sunt conectate cele trei butoane i afieaz pe serial numrul de
apsri al fiecrui buton n parte. Se mai observ c programul introduce i un
debouncing software (o mic ntrziere dup declanarea fiecrei apsri de buton)
pentru a nu prinde evenimentul n mod eronat de mai multe ori. Se poate experimenta i
observa efectul nlturrii debouncing-ului software.
O alt modalitate de a prinde un eveniment de tip nchidere circuit / apsare buton se
poate face i prin utilizarea ntreruperilor externe. Mediul Arduino IDE pune la dispoziia
programatorului funcia attachInterrupt(ntrerupere, isr_asociat, mod)
care permite manipularea celor dou ntreruperi externe INT0 i INT1 ale
microcontrolerului. Din pcate acestea sunt singurele ntreruperi care sunt accesibile
prin intermediul limbajului de baz al mediului Arduino IDE. Butoanele trebuie s fie
conectate la pinii 2 (INT0) i 3 (INT1) ai plcii Arduino. Parametrii funciei sunt:
ntrerupere - 0 pentru INT0 i 1 pentru INT1, isr_asociat numele unei proceduri care
s trateze apariia ntreruperii i mod specific evenimentul extern la care s se
declaneze ntreruperea LOW (pinul devine 0 logic), FALLING (pinul trece din 1 n
0), RISING (pinul trece din 0 n 1) sau CHANGE (orice tip de tranziie la buton
acest mod va conduce la declanare dubl la fiecare apsare). Funcia pereche
detachInterrupt(ntrerupere) permite dezactivarea ntreruperii activate cu
ajutorul funciei precedente. Pentru testarea celor dou funcii se poate rula programul
urmtor utiliznd aceiai schem electric efectul programului este identic cu cel
precedent.
const int buton3 = 4;
volatile int a1 = 0;
volatile int a2 = 0;
int a3 = 0;
void setup() {
attachInterrupt(0,ISR_b1,FALLING);
53

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate


attachInterrupt(1,ISR_b2,FALLING);
Serial.begin(9600);
}
void loop(){
if ((PIND & (1<<buton3))==0) {
a3++;
Serial.print("Butonul 3 s-a apasat de ");
Serial.print(a3,DEC);
Serial.print(" ori.");
Serial.println();
//debouncing software
delay(200);}
}
void ISR_b1() {
a1++;
Serial.print("Butonul 1 s-a apasat de ");
Serial.print(a1,DEC);
Serial.print(" ori.");
Serial.println();
//debouncing software
delay(400);
}
void ISR_b2() {
a2++;
Serial.print("Butonul 2 s-a apasat de ");
Serial.print(a2,DEC);
Serial.print(" ori.");
Serial.println();
//debouncing software
delay(400);
}

Sursa programului utilizeaz dou lucruri importante:

Sistemul de ntreruperi este folosit doar pentru butonul 1 (pin2 INT0) i butonul
2 (pin3 INT1) deoarece funcia attachInterrupt nu permite definirea de
ntreruperi externe pe ali pini. Citirea butonului 3 se face n continuare n bucla
infinit principal.

Citirea butonului 3 nu se mai face cu ajutorul funciei digitalRead descris


anterior ci, direct, prin intermediul registrului intern PIND care stocheaz starea
pinilor de intrare a portului D pinul 4 al plcii este conectat la pinul PD4 al
54

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

microcontrolerului (a se revedea lucrarea 3). Verificarea strii pinului 4 al plcii


const n verificarea strii bitului 4 din registrul PIND. Acest mecanism se afl n
spatele implementrii funciei digitalRead specific mediului Arduino IDE.

Exemplu de activare direct a ntreruperilor externe


Placa de dezvoltare Arduino permite activarea tuturor pinilor I/O ca surse de ntreruperi
externe. Este adevrat c spre deosebire de pinii 2 i 3 (INT0 i INT1) restul pinilor I/0
(PCINTx) nu pot configura ntreruperi externe declanate de prinderea unui eveniment
extern de tip front cresctor, front descresctor sau zero logic (RISING, FALLING,
LOW) ci doar de modificarea nivelului logic (CHANGE). Pentru a configura ntreruperile
externe asociate cu ali pini dect 2 sau 3 este nevoie s configurm n mod direct
registrele interne ale microcontrolerului. Programul urmtor reface comportamentul
programelor anterioare fr a apela la funcia attachInterrupt. Se vor utiliza trei
ntreruperi externe INT0 pin 2 buton 1, INT1 pin 3 buton 2, PCINT2 pin4 =
PCINT20 buton 3. Pentru mai mult informaii legate de configurarea direct a
sistemului de ntreruperi se poate consulta [1].
#include <util/delay.h>
volatile int a1 = 0;
volatile int a2 = 0;
volatile int a3 = 0;
void setup() {
EIMSK |= (1 << INT0);
EIMSK |= (1 << INT1);
PCICR |= (1 << PCIE2);
PCMSK2 |= (1<<PCINT20);
Serial.begin(9600); }
void loop(){
Serial.print("Butonul 1 s-a apasat de ");
Serial.print(a1,DEC);
Serial.print(" ori.");
Serial.println();
Serial.print("Butonul 2 s-a apasat de ");
Serial.print(a2,DEC);
Serial.print(" ori.");
Serial.println();
Serial.print("Butonul 3 s-a apasat de ");
55

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate


Serial.print(a3,DEC);
Serial.print(" ori.");
Serial.println();
delay(1000); }
ISR(INT0_vect) {
a1++;
_delay_ms(400); }
ISR(INT1_vect) {
a2++;
_delay_ms(400); }
ISR(PCINT2_vect) {
a3++;
_delay_ms(400); }

Pentru activarea ntreruperilor INT0 i INT1 se seteaz biii INT0 i INT1 din registrul
intern EIMSK, de exemplu: EIMSK |= (1 << INT0).
Pentru activarea ntreruperii externe PCINT2 cu referire la pinul PCINT20 trebuie setai
biii PCIE2 i PCINT20 din registrele PCICR i PCMSK2. Datorit faptului c ntreruperile
de tip PCINT nu au dect modul de funcionare echivalent cu CHANGE fiecare apsare
de buton 3 va fi prins de dou ori (FALLING i RISING).
Funciile ISR pentru cele trei ntreruperi trebuie declarate de forma ISR(INT_vect)
unde INT_vect va fi INT0_vect, INT1_vect, PCINT2_vect. [2]
n cazul ISR-urilor reale (nu generate de mediul Arduino) sistemul de ntreruperi este
dezactivat pe durata execuiei ISR-ului (pentru ca un ISR s nu ntrerup un alt ISR).
Pentru a preveni blocarea programului (n ISR) nu trebuie folosite n cadrul unui ISR
funciile puse la dispoziie de mediul Arduino. De exemplu, utilizarea funciei delay n
cadrul unui ISR (pentru debouncing-ul software) va conduce la o execuie eronat a
programului deoarece aceast funcie utilizeaz ntreruperea asociat timer-ului 0
apelat ntr-un context de dezactivare a sistemului de ntreruperi va conduce la un
comportament incert a execuiei programului. Aceast funcie poate fi nlocuit cu
macro-ul _delay_ms(nr_ms) prezent n biblioteca util/delay.h .

56

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

Proiect numrtor pe dou caractere i trei butoane


Avnd n vedere cunotinele noi prezentate vom ncerca s implementm un
numrtor simplu cu ajutorul unui afiaj de dou caractere pe 7 segmente. Dup reset
afiajul va arta 00, la fiecare apsare a butonului 1 numrul se va incrementa
(incrementarea din 99 va duce n 00), la fiecare apsare a butonului 2 numrul de pe
afiaj se va decrementa (decrementarea din 00 va duce n 99), butonul 3 va reseta
numrul la 00 (nu vom fi deranjai de declanarea dubl a evenimentului avnd n
vedere c este o operaie de reset).
Schema electric a numrtorului este prezentat n imaginea urmtoare. Se observ
c datorit utilizrii a dou registre de deplasare nu mai apare efectul de aprindere
slab a unor segmente n cazul afirii de cifre diferite pe cele dou caractere nu se
mai efectueaz comanda prin intermediul aceluiai registru a celor dou caractere.
Comanda de aprindere a segmentelor este stabil fiecare caracter are propriul
registru.
Pentru testarea montajului se utilizeaz urmtorul cod surs:
#include <util/delay.h>
const
const
const
const
const
const

int
int
int
int
int
int

latchPin1 = 7;
clockPin1 = 8;
dataPin1 = 9;
latchPin2 = 10;
clockPin2 = 11;
dataPin2 = 12;

volatile int digit1 = 0;


volatile int digit2 = 0;
const int numbers[] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111};
void setup() {
//activare int0 si int1
EIMSK |= (1 << INT0);
EIMSK |= (1 << INT1);
//activare PCI2 (buton 3 - PCINT20 - PCI2)
PCICR |= (1 << PCIE2);
PCMSK2 |= (1<<PCINT20);

57

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

58

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate


pinMode(latchPin1, OUTPUT);
pinMode(dataPin1, OUTPUT);
pinMode(clockPin1, OUTPUT);
pinMode(latchPin2, OUTPUT);
pinMode(dataPin2, OUTPUT);
pinMode(clockPin2, OUTPUT);
}
void loop(){
digitalWrite(latchPin1, LOW);
shiftOut(dataPin1, clockPin1, MSBFIRST, numbers[digit1]);
digitalWrite(latchPin1, HIGH);
digitalWrite(latchPin2, LOW);
shiftOut(dataPin2, clockPin2, MSBFIRST, numbers[digit2]);
digitalWrite(latchPin2, HIGH);
delay(1000);}
ISR(INT0_vect) {
if (digit1==9) {
if (digit2==9) {
digit1=0;
digit2=0;
}
else {
digit1=0;
digit2++;
}
}
else digit1++;
_delay_ms(400);
}
ISR(INT1_vect) {
if (digit1==0) {
if (digit2==0) {
digit1=9;
digit2=9;
}
else {
digit1=9;
digit2--;
}
}
else digit1--;
_delay_ms(400);}
59

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

ISR(PCINT2_vect) {
digit1 = 0;
digit2 = 0;
_delay_ms(400); }

Proiect cronometru pe dou caractere i trei butoane


Utiliznd schema precedent vom implementa un sistem de tip cronometru.
Funcionarea cronometrului va fi urmtoarea: numrtoarea se va face n zecimal (0099), butonul 1 va porni cronometrul, butonul 2 va opri numrtoarea fr a terge
rezultatul astfel nct numrtoarea s poat fi reluat, butonul 3 va reseta numrul de
secunde la 00 indiferent de modul de funcionare (oprit / pornit). Evenimentele asociate
celor trei butoane vor fi prinse similar ca i n cazul numrtorului (folosind ntreruperi).
Programul ce trebuie ncrcat este urmtorul:
#include <util/delay.h>
const
const
const
const
const
const

int
int
int
int
int
int

latchPin1 = 7;
clockPin1 = 8;
dataPin1 = 9;
latchPin2 = 10;
clockPin2 = 11;
dataPin2 = 12;

volatile int digit1 = 0;


volatile int digit2 = 0;
const int numbers[] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111};
void setup() {
// activare intrerupere Timer1 overflow
TIMSK1 = (1 << TOIE1);
// timer1 oprit
TCCR1A = 0;
TCCR1B = 0;
//activare int0 si int1
EIMSK |= (1 << INT0);
EIMSK |= (1 << INT1);
//activare PCI2 (buton 3 - PCINT20 - PCI2)
PCICR |= (1 << PCIE2);
PCMSK2 |= (1<<PCINT20);

60

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate


pinMode(latchPin1, OUTPUT);
pinMode(dataPin1, OUTPUT);
pinMode(clockPin1, OUTPUT);
pinMode(latchPin2, OUTPUT);
pinMode(dataPin2, OUTPUT);
pinMode(clockPin2, OUTPUT); }
void loop(){
digitalWrite(latchPin1, LOW);
shiftOut(dataPin1, clockPin1, MSBFIRST, numbers[digit1]);
digitalWrite(latchPin1, HIGH);
digitalWrite(latchPin2, LOW);
shiftOut(dataPin2, clockPin2, MSBFIRST, numbers[digit2]);
digitalWrite(latchPin2, HIGH);
delay(1000); }
ISR(TIMER1_OVF_vect) {
if (digit1==9) {
if (digit2==9) {
digit1=0;
digit2=0;
}
else {
digit1=0;
digit2++;
}
}
else digit1++;
TCNT1 = 0x0BDC;
}
ISR(INT0_vect) {
_delay_ms(400);
TCNT1 = 0x0BDC;
//pornire timer FCPU/256
TCCR1B |= (1 << CS12); }
ISR(INT1_vect) {
TCCR1B = 0;
_delay_ms(400); }
ISR(PCINT2_vect) {
digit1 = 0;
digit2 = 0;
_delay_ms(400); }
61

Elemente practice de baz n dezvoltarea sistemelor cu microprocesoare integrate

Referine online
[1] <avr/interrupt.h>: Interrupts
http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html
[2] We interrupt this program to bring you a tutorial on Arduino interrupts
http://www.engblaze.com/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduinointerrupts/

62

S-ar putea să vă placă și