Sunteți pe pagina 1din 35

Echipamente programabile – Laborator 11 & 12

George Mois
December 7, 2021

Abstract
Luare de decizii, operat, ii pe bit, i, manipulare intrări s, i ies, iri.

1 Luarea de decizii
Când este scris un program, există ı̂ntotdeauna o parte a codului care este executată
doar atunci când sunt verificate unele condit, ii particulare. Codul trebuie să react, ioneze
corect ı̂n funct, ie de unele evenimente sau condit, ii interne sau externe. Un exemplu ar
putea fi atunci când utilizatorul apasă o tastă predefinită pentru execut, ia unui anumit set
de instruct, iuni sau efectuarea unei alte operat, ii ı̂n cazul altei taste apăsate. Un exemplu
practic ar putea fi un sistem de controlare a nivelului apei ı̂ntr-o incintă: atunci când
senzorul detectează cres, terea nivelului apei peste un anumit prag, programul execută
instruct, iuni pentru a opri motorul pompei de alimentare cu apă.
C oferă următoarele tipuri de declarat, ii de luare a deciziilor:

• Instruct, iune if – evaluează o expresie s, i execută una sau mai multe instruct, iuni
atunci când expresia este adevărată;
• Instruct, iune if ... else – o instruct, iune if poate fi urmată de o instruct, iune opt, ională
else, care se execută atunci când expresia este evaluată ca fiind falsă;
• Instruct, iunea if ... else if ... else – permite evaluarea mai multor expresii s, i
execută diferite blocuri de cod pentru mai mult de două condit, ii;
• Operatorul condit, ional – prezentat ı̂n labortorul precedent;
• Instruct, iunea switch – permite testarea unei expresii pentru egalitate fat, ă de o
listă de valori.

1.1 Instruct, iunea if


Sintaxa:
if ( expresie )
instructiune ;
sau

1
if ( expresie )
{
instructiune 1 ;
instructiune 2 ;
...
instructiune n ;
}
Expresia are următorul efect:
– Se evaluează expresia.
– Dacă rezultatul evaluării este True, atunci blocul de cod din cadrul instruct, iunii
if este executat.
– Dacă rezultatul evaluării este False, atunci se execută prima instruct, iune după
instruct, iunea if.
Programatorul trebuie să introducă ı̂ntre parantezele rotunde condit, ia pentru care
programul trebuie să execute o instruct, iune unică sau multiplă. Dacă condit, ia va fi
adevărată, programul va executa instruct, iunile, iar dacă aceasta este falsă, programul
va sări peste instruct, iunile respective. Un alt lucru de ret, inut este faptul că instruct, iunile
trebuie să fie ı̂ntotdeauna incluse ı̂ntre acolade dacă sunt mai multe. Expresia nu trebuie
să fie urmată de punct s, i virgulă.

1.1.1 Exemplu
Eroare comună la folosirea instruct, iunii if :
# i n c l u d e < s t d i o . h>
i n t main ( )
{
i n t myData = 6 0 ;

i f ( myData >= 4 0 ) ;
{
/ / nu s e va e x e c u t a
p r i n t f ( ” V a l u e − %d . \ n ” , myData ) ;
myData = 0 ;
}

/ / i n s t r . in afara i f
myData ++;

return 0;
}

2
1.1.2 Exemplu
Folosirea unei variabile ca s, i condit, ie.
# i n c l u d e < s t d i o . h>

u i n t 8 t btnApasat = 0;

i n t main ( v o i d )
{
i f ( btnApasat )
{
/ / s e e x e c u t a daca b t n A p a s a t e s t e d i f e r i t de 0
p r i n t f ( ” P o r n e s t e LED . \ n ” ) ;
btnApasat = 0;
}

return 0;
}

/* I n t e r r u p t handler for button press */


void ISR button ( void )
{
btnApasat = 0;
}
Init, ial, variabila este egală cu 0. Astfel, vom avea condit, ie falsă ı̂n instruct, iunea if
(valoarea variabilei este 0). Apăsarea butonului va seta valoarea variabilei la 1 (printr-o
ı̂ntrerupere). Condit, ia if va fi adevărată ı̂n acest caz s, i CPU va executa instruct, iunile.

1.1.3 Exercit, iu
Scriet, i un program care primes, te vârsta utilizatorului s, i ı̂i spune dacă are drept de vot.
Afis, at, i mesaje corespunzătoare.

1.2 Instruct, iunea if ... else


Sintaxa:
if ( expresie )
instructiune 1 ;
else
instructiune 2 ;
sau

3
if ( expresie )
{
instructiune 1 1;
instructiune 1 2;
...
instructiune 1 n;
}
else
{
instructiune 2 1;
instructiune 2 2;
...
instructiune 2 n;
}
Expresia are următorul efect:
– Se evaluează expresia.
– Dacă rezultatul evaluării este True, atunci blocul de cod din cadrul instruct, iunii
if este executat.
– Dacă rezultatul evaluării este False, atunci blocul de cod corespunzător ramurii
else este executat.

1.2.1 Exercit, iu
Modificat, i exercit, iul anterior pentru a folosi instruct, iunea if ... else.

1.2.2 Exercit, iu
Scriet, i un program care afis, ează cel mai mare dintre două numere introduse de către
utilizator. Dacă cele două numere sunt egale, atunci se afis, ează un mesaj corespunzător.
Modificat, i programul pentru a accepta s, i numere reale s, i a afis, a un mesaj de atent, ionare
dacă se introduc numere cu parte zecimală. Comparat, i doar partea ı̂ntreagă.
Modificat, i programul pentru a termina execut, ia dacă se introduc caractere ı̂n loc
de numere (scanf returnează 0 dacă operat, ia de citire este terminata fără succes, s, i 1
altfel).

1.3 Instruct, iunea if ... else if ... else

if ( expresie1 )
{
instructiuni ;
}
else if ( expresie2 )
{
instructiuni ;
}

4
...
else
{
instructiuni ;
}
Expresia are urmatorul efect:
– Se evaluează expresie1.
– Dacă rezultatul evaluării este True, atunci blocul de cod din cadrul instruct, iunii
if este executat.
– Dacă rezultatul evaluării este False, atunci se evaluează expresie2.
– Dacă rezultatul evaluării este True, atunci blocul de cod din cadrul instruct, iunii
if este executat.
– ....
– Dacă rezultatul evaluării este False, atunci blocul de cod corespunzător ramurii
if este executat.

1.3.1 Exemplu

# i n c l u d e < s t d i o . h>

/ / f u n c t i e pentru mentinerea terminalului deschis


void w a i t u s e r i n p u t ( void ) ;

i n t main ( )
{
int grade = 0;
p r i n t f ( ” E n t e r t h e number o f p o i n t s o b t a i n e d a t t h e exam : ” ) ;
fflush ( stdout );
s c a n f ( ”%d ” , &g r a d e ) ;
i f ( ( g r a d e >= 0 ) && ( g r a d e <= 1 0 0 ) ) {
i f ( g r a d e >= 9 0 )
p r i n t f ( ” P a s s e d w i t h A. \ n ” ) ;
e l s e i f ( g r a d e >= 8 0 )
p r i n t f ( ” Passed with B.\ n” ) ;
e l s e i f ( g r a d e >= 7 0 )
p r i n t f ( ” Passed with C.\ n” ) ;
e l s e i f ( g r a d e >= 6 0 )
p r i n t f ( ” P a s s e d w i t h D. \ n ” ) ;
else
p r i n t f ( ” Failed .\ n” ) ;
}
else {
p r i n t f ( ”You e n t e r e d an i n v a l i d g r a d e ! ” ) ;
}
fflush ( stdout );

5
wait user input ();
return 0;
}

/ / f u n c t i e pentru mentinerea terminalului deschis


void w a i t u s e r i n p u t ( void )
{
while ( g e t c h a r ( ) ! = ’ \n ’ )
{
/ / r e a d i n p u t b u f f e r and do n o t h i n g
}
getchar ( ) ;
}

1.3.2 Exercit, iu
Scriet, i un program care să calculeze taxele pentru utilizator, conform cu tabelul de mai
jos:

Table 1: Taxe
Venit % taxe
Până la 9525USD 0
Între 9526 s, i 38700 USD 12%
Între 38701 s, i 82500 USD 22%
Peste 82500 USD 32% + 1000 USD

Folosit, i instruct, iunea if ... else if ... else.

6
1.4 Instruct, iunea switch
Instruct, iunea switch poate fi folosită ı̂n locul instruct, iunii if ... else if ... else. De obicei
este mai rapidă decât instruct, iuni if ... else imbricate.
Sintaxa:
switch ( expression )
{
case constant1 :
/ / statements
break ;

case constant2 :
/ / statements
break ;
.
.
.
default :
/ / default statements
}
Expresia are următorul efect:
– Se evaluează expresia.
– Rezultatul evaluării este comparat cu constant1, constant2, ... .
– Dacă rezultatul este egal cu una dintre constante, atunci este executat blocul de
cod corespunzător.
– Dacă rezultatul nu este egal cu niciuna dintre constante, atunci este executat
blocul de cod corespunzător etichetei default.
Ramura default este opt, ională. Dacă ea lipses, te s, i valoarea expresiei nu se potrives, te
cu nicio constantă, instruct, iunea switch nu are efect. De asemenea, declarat, ia break
este opt, ională. Dacă instruct, iunea break lipses, te, toate instruct, iunile care urmează sunt
executate, până când se ı̂ntâlnes, te fie o instruct, iune break, fie se termină instruct, iunea
switch. Constantele trebuie să aibă acelas, i tip de date ca s, i expresia. Tipurile de date
permise sunt ı̂ntregi s, i caractere.

1.4.1 Exemplu

# i n c l u d e < s t d i o . h>
i n t main ( ) {
int grade = 0;

p r i n t f ( ” E n t e r one o f t h e f o l l o w i n g A, a , B , b , C , c , D, d , F , f : ” ) ;
grade = getchar ( ) ;
switch ( grade ) {
case ’ a ’ :

7
c a s e ’A ’ : p r i n t f ( ” Grade b e t w e e n 90 and 1 0 0 . \ n ” ) ;
break ;
case ’b ’ :
c a s e ’B ’ : p r i n t f ( ” Grade b e t w e e n 80 and 9 0 . \ n ” ) ;
break ;
case ’ c ’ :
c a s e ’C ’ : p r i n t f ( ” Grade b e t w e e n 70 and 8 0 . \ n ” ) ;
break ;
case ’d ’ :
c a s e ’D ’ : p r i n t f ( ” Grade b e t w e e n 60 and 7 0 . \ n ” ) ;
break ;
case ’ f ’ :
c a s e ’ F ’ : p r i n t f ( ” Grade b e t w e e n 0 and 6 0 . \ n ” ) ;
break ;
d e f a u l t : p r i n t f ( ”You e n t e r e d an i n v a l i d grade ! ” ) ;
}
return 0;
}

1.4.2 Exercit, iu
Scriet, i un program care să calculeze aria diferitelor forme geometrice, conform cu
tabelul de mai jos:

Table 2: Select, ii
Cod Formă geometrică Formulă
’c’ cerc PI * r2
’t’ triunghi (b * h)/2
’d’ dreptunghi (L * l)
’p’ pătrat l2
’r’ trapezoid ((B + b)/2)*h

Implementat, i un mecanism pentru a nu se permite introducerea de valori negative


pentru dimensiuni.

8
2 Operat, ii pe bit, i
Aceste operat, ii sunt utilizate ı̂n mod obis, nuit s, i pe scară largă ı̂n C pentru manipularea
datelor din regis, tri.

Table 3: Operat, ii pe bit, i


Operator Description Example
& Bitwise AND operator (a & b) = 0
The bits ı̂n the result are set to 1 if the corresponding bits ı̂n the two operands are both 1.
| Bitwise OR operator (a | b) = 10
The bits ı̂n the result are set to 1 if at least one of the corresponding bits ı̂n the two operands is 1.
ˆ Bitwise exclusive OR operator (a ˆb) = 10
The bits ı̂n the result are set to 1 if exactly one of the corresponding bits ı̂n the two operands is 1.
∼ Bitwise (1’s) complement operator (∼a) = -11
All 0 bits are set to 1 and all 1 bits are set to 0.
<< Left shift (a <<2) = 40
Shifts the bits of the first operand left by the number of bits specified by the second operand;
fill from the right with 0 bits.
>> Right shift (a >>2) = 2
Shifts the bits of the first operand right by the number of bits specified by the second operand;
the method of filling from the left is machine dependent.

Este important să ret, inem că este o diferent, ă ı̂ntre operatorii logici s, i operatorii
pentru operat, ii pe bit, i:
• && – operatorul logic AND,
• k – operatorul logic OR.

2.1 Exemplu

Figure 1: Operat, ii logice s, i pe bit, i - SI

În exemplu, rezultatul folosirii operatorului logic este zero sau diferit de zero sau
fals sau adevărat. Dacă variabila este o valoare diferită de zero, valoarea exactă nu
contează pentru calcularea rezultatului. În cazul operatorului bitwise, se va efectua S, I
pentru fiecare bit apart, inând celor doi operanzi, acest lucru ı̂nsemnând că rezultatul
nu va fi boolean. În exemplu vedem că S, I se realizează bit cu bit ı̂ntre reprezentarea

9
binară a celor doi operanzi. Această diferent, ă este valabilă s, i pentru SAU bitwise s, i
SAU logic.

2.2 NOT s, i XOR


Operatorul negat, ie (NOT) bitwise este aplicat s, i el bit cu bit. Pe de altă parte, operatorul
logic negat, ie produce doar adevărat sau fals ca rezultat.
Operatorul XOR (SAU-EXCLUSIV) este prezent doar ı̂n versiunea pe bit, i, nu ex-
istă XOR logic.
În programele C, operatorii pe bit, i sunt folosit, i pentru:
• & – testarea anumitor bit, i,
• | – setarea anumitor bit, i (atribuirea valorii 1),
• ~ s, i & – resetarea anumitor bit, i (clear sau atribuirea valorii 0),
• ˆ – comutarea anumitor bit, i.

10
3 Testarea, resetarea s, i setarea bit, ilor
3.1 Exemplu
Exemplu pentru determinarea parităt, ii unui număr.

Figure 2: Determinare paritate

Este clar că valoarea bitului LSB poate fi utilizată pentru a evalua dacă un număr
este par sau impar. Pentru numerele pare LSB este egal cu 0 ı̂n timp ce acest bit este
egal cu 1 pentru numerele impare. Principala problemă este identificarea valorii LSB
pentru un anumit număr. Aceasta problemă poate fi rezolvată folosind o tehnică numită
bit masking. Un exemplu de bit masking este prezentat pe pagina anterioară, pentru
testarea valorii LSB a unui număr. Operatorul S, I bitwise este aplicat ı̂ntre număr s, i
valoarea 0x01. Efectuând această operat, ie (S, I cu zero pentru tot, i bit, ii ı̂n afară de LSB)
tot, i bit, ii ı̂n afară de LSB vor fi zero. În cazul LSB, dacă LSB = 0, S, I va da 0 ca rezultat,
s, i 1 dacă LSB = 1.
Bit masking, care poate fi utilizată s, i pentru operatorul SAU, are două scopuri prin-
cipale:
• modificarea valorii unui bit (din 0 ı̂n 1 folosind SAU cu 1, s, i din 1 ı̂n 0 folosind
S, I cu 0),
• testarea valorii unui bit (verificarea dacă valoarea bitului de pe o anumită pozit, ie
este 0 sau 1).

11
Este de ret, inut utilitatea practică a operatorului SAU-EXCLUSIV (XOR). Acesta
poate fi folosit, de exemplu, pentru comutarea unei ies, iri (ex. conectată la un LED).

3.2 Exemplu

Figure 3: Comutarea unui bit

4 Shiftare (deplasare) pe bit, i


4.1 Shiftarea la dreapta
Sintaxa:
o p e r a n d 1 >> o p e r a n d 2 ;
/ / B i t i i o p e r a n d u l u i 1 v o r f i d e p l a s a t i l a d r e a p t a cu
/ / un numar de p o z i t i i e g a l cu o p e r a n d u l 2 .

4.1.1 Exemplu
Exemplul ilustrează o deplasare la dreapta a variabilei a cu 4 pozit, ii. La fiecare pas
bitul din partea dreaptă va fi ı̂mpins s, i se va pierde. T, inând cont că este o deplasare
a tuturor bit, ilor spre dreapta cu o pozit, ie, este clar că pentru bitul cel mai din stânga
vom avea o pozit, ie goală. Aceasta va fi completată cu 0 ı̂n mod implicit. Dacă acest
mecanism se repetă de 4 ori, 4 bit, i din partea dreaptă se vor pierde s, i 4 bit, i de 0 vor fi
inserat, i ı̂n stânga.

12
Figure 4: Shiftare la dreapta

4.2 Shiftarea la stânga


Această operat, ie se execută ı̂n oglindă fat, ă de operat, ia de shiftare la dreapta.

Figure 5: Shiftare la stânga

Operat, iile de shiftare la drepta s, i la stânga sunt folosite pentru a ı̂mpărt, i sau ı̂nmult, i
la/cu 2. Această proprietate a operat, iilor de shiftare este foarte utilă ı̂n programare.

13
Utilizări:
• bit masking a variabilelor pentru folosirea ı̂n alte operat, ii pe bit, i,
• setarea sau resetarea bit, ilor.

4.3 Exemplu
Setarea bitului al 4-lea al unui anumit număr.

Figure 6: Setarea unui bit

14
Resetarea bitului al 4-lea al unui anumit număr.

Figure 7: Resetarea unui bit

15
4.4 Exemplu
Extragerea unui număr de bit, i dintr-un alt număr s, i salvarea lor. Extragerea bit, ilor de
la pozit, ia 9 la pozit, ia 14 s, i salvarea lor ı̂ntr-o altă variabilă.

Figure 8: Extragerea unui grup de bit, i

5 Looping ı̂n C – bucle


5.1 Exemplu

# i n c l u d e <s t d i o . h>
i n t main ( )
{
printf ( ” 1\ n ” ) ;
printf ( ” 2\ n ” ) ;
printf ( ” 3\ n ” ) ;
printf ( ” 4\ n ” ) ;
printf ( ” 5\ n ” ) ;
printf ( ” 6\ n ” ) ;
printf ( ” 7\ n ” ) ;
printf ( ” 8\ n ” ) ;
printf ( ” 9\ n ” ) ;
printf ( ” 10\ n ” ) ;

return 0;
}

# i n c l u d e <s t d i o . h>
# i n c l u d e < s t d i n t . h>
i n t main ( )
{

16
u i n t 8 t i = 1;
w h i l e ( i <=10)
{
p r i n t f ( ”%d \ n ” , i ) ;
i ++;
}

return 0;
}
Cele două programe execută aceeas, i instruct, iune. Exemplul al doilea utilizează o
buclă. Codul arată mai eficient s, i mai compact. Este us, or să ne imaginăm că de cele
mai multe ori numărul de operat, ii de efectuat ar putea fi mult mai mult de 10 (ar fi
foarte enervantă s, i inutilă repetarea aceleias, i comenzi de atâtea ori).
C oferă următoarele tipuri de instruct, iuni pentru implementarea buclelor:
– for – execută una sau mai multe instruct, iuni de mai multe ori utilizând o vari-
abilă;
– while – repetă una sau mai multe instruct, iuni ı̂n timp ce o expresie dată este
adevărată s, i evaluează expresia ı̂nainte de a executa corpul buclei;
– do ... while – repetă una sau mai multe instruct, iuni ı̂n timp ce o expresie dată
este adevărată s, i evaluează expresia de la sfârs, itul corpului buclei.
Buclele permit executarea unor instruct, iuni repetitiv până când sunt ı̂ndeplinite an-
umite condit, ii. Setările acestor condit, ii sunt cruciale pentru funct, ionarea corectă a
buclei.

5.2 while
Sintaxa:
while ( e x p r e s i e )
{ / / s t a r t corp i n s t r while
/ / b u c l a w h i l e cu mai m u l t e i n s t r u c t i u n i
instr1 ;
instr2 ;
instr3 ;
...
instrN ;
} / / end c o r p i n s t r w h i l e

/ / b u c l a w h i l e cu o s i n g u r a i n s t r u c t i u n e
while ( e x p r e s i e )
instr ;
/ / s e p o t f o l o s i a c o l a d e l e daca s e d o r e s t e
Această instruct, iune are următorul efect:
– Expresia este evaluată.

17
– Dacă rezultatul evaluării este adevărat, atunci blocul de cod din while este exe-
cutat s, i expresia este evaluată din nou.
– Dacă rezultatul evaluării este fals, atunci prima declarat, ie după sfârs, itul while
este executată.
Este posibil ca o instruct, iune while să nu se execute deloc. Când expresia este
evaluată s, i rezultatul este fals de la ı̂nceput, blocul de cod din while este omis s, i prima
declarat, ie după while este executată.
Blocul de cod din interiorul unei instruct, iuni while trebuie să cont, ină câteva instruct, iuni
care modifică valoarea variabilelor din expresie.

5.2.1 Exemplu

# i n c l u d e < s t d i o . h>
# d e f i n e PERIOD ’ . ’
i n t main ( v o i d )
{
int character = 0 , no character = 0;

p r i n t f ( ” Computes how many t i m e s t h e c h a r a c t e r s o t h e r t h a n ” ) ;


p r i n t f ( ” s i n g l e o r d o u b l e q u o t e s a p p e a r i n an i n p u t s e n t e n c e . \ n ” ) ;
p r i n t f ( ” Type . t o end t h e s e n t e n c e . \ n ” ) ;
p r i n t f ( ” Input sentence : ” ) ;
fflush ( stdout );
w h i l e ( ( c h a r a c t e r = g e t c h a r ( ) ) ! = PERIOD ) {
i f ( ( c h a r a c t e r ! = ’ ” ’ ) && ( c h a r a c t e r ! = ’ \ ’ ’ ) )
n o c h a r a c t e r ++;
}
p r i n t f ( ” T h e r e a r e %d non q u o t e c h a r a c t e r s . \ n ” , n o c h a r a c t e r ) ;
fflush ( stdout );
return 0;
}

5.2.2 Atent, ie
Plasarea unui caracter ; imediat după instruct, iunea while duce la bucle infinite s, i im-
plicit la bug-uri ı̂n cod (code hangs forever). Această gres, eală nu va fi recunoscută ı̂n
timpul compilării, dar va schimba complet logica programului.
/ / b u c l a w h i l e cu o s i n g u r a i n s t r u c t i u n e
while ( e x p r e s i e ) ;
instr ;
/ / s e p o t f o l o s i a c o l a d e l e daca s e d o r e s t e

18
5.2.3 Bucle infinite
Bucla infinită este un tip special de buclă while. Aceste bucle sunt comune ı̂n progra-
marea C, ı̂n special cele care rulează pe microcontrolere.
# i n c l u d e < s t d i o . h>
i n t main ( v o i d )
{
/* Super loop */
while ( 1 )
{
readSensorData ( ) ;
processData ( ) ;
displayAcquiredData ( ) ;
}
}

5.3 do ... while


Sintaxa:
do
{
instr1 ;
instr2 ;
...
instrN ;
} while ( e x p r e s s i e ) ;
Această instruct, iune are următorul efect:
– Blocul de cod din interiorul do ... while este executat.
– Expresia este evaluată.
– Dacă rezultatul evaluării este adevărat, atunci blocul de cod din do ... while este
executat s, i expresia este evaluată din nou.
– Dacă rezultatul evaluării este fals, atunci prima declarat, ie după sfârs, itul do ...
while este executată.
Spre deosebire de instruct, iunile for s, i while, care evaluează expresia la ı̂nceputul
buclei, instruct, iunea do ... while verifică expresia la sfârs, itul buclei. Această caracter-
istică garantează că do ... while este executat cel put, in o dată.

5.3.1 Exemplu

# i n c l u d e < s t d i o . h>
# d e f i n e PERIOD ’ . ’
i n t main ( )
{

19
int character = 0 , no character = 0;

printf ( ” Computes how many t i m e s t h e c h a r a c t e r s o t h e r t h a n \ n ” ) ;


printf ( ” s i n g l e o r d o u b l e q u o t e s a p p e a r i n an i n p u t s e n t e n c e . \ n ” ) ;
printf ( ” Type . t o end t h e s e n t e n c e . \ n ” ) ;
printf ( ” Input sentence : ” ) ;
fflush ( stdout );
do {
i f ( ( c h a r a c t e r ! = ’ ” ’ ) && ( c h a r a c t e r ! = ’ \ ’ ’ ) )
n o c h a r a c t e r ++;
} w h i l e ( ( c h a r a c t e r = g e t c h a r ( ) ) ! = PERIOD ) ;
p r i n t f ( ” T h e r e a r e %d non q u o t e c h a r a c t e r s . \ n ” , n o c h a r a c t e r − 1 ) ;
fflush ( stdout );
return 0;
}

5.4 for
Sintaxa:
for ( expresie1 ; expresie2 ; expresie3 )
{
instructiuni ;
}
Această instruct, iune are următorul efect:
– expresie1 este executată prima s, i o singură dată. Acest pas permite programato-
rilor să definească s, i să init, ializeze orice variabilă de control al buclei.
– Se evaluează expresie2.
– Dacă rezultatul evaluării este adevărat, atunci blocul de cod din for este executat.
– Dacă rezultatul evaluării este fals, atunci se execută prima afirmat, ie după sfârs, itul
for.
– După executarea blocului de cod din for, se execută expresie3. Acest pas permite
programatorilor să actualizeze orice variabilă de control al buclei.
– expresie2 este acum evaluată din nou. Dacă este adevărat, bucla se execută s, i
procesul se repetă. După ce expresie2 devine falsă, se termină bucla for.
expresie1, expresie2 s, i expresie3 pot lipsi, dar caracterul ; trebuie sa apară.
O buclă devine infinită dacă evaluarea unei expresii este ı̂ntotdeauna adevărată.
Bucla for este utilizată ı̂n mod tradit, ional ı̂n acest scop. Deoarece niciuna dintre cele
trei expresii care formează declarat, ia for nu este necesară, se poate face o buclă fără
sfârs, it lăsând expresia2 goală.

20
5.4.1 Exemplu

# i n c l u d e < s t d i o . h>
# d e f i n e MAX SIZE 100
i n t main ( )
{
f l o a t numbers [ MAX SIZE ] = { 0 } , a v e r a g e = 0 . 0 f , sum = 0 . 0 f ;
int i = 0 , no numbers = 0 ;
p r i n t f ( ” A r i t h m e t i c avg . v a l u e o f n (<%d ) r e a l no . \ n ” , MAX SIZE ) ;
p r i n t f ( ” I n p u t t h e number o f r e a l numbers , n = ” ) ;
fflush ( stdout );
s c a n f ( ”%d ” , &n o n u m b e r s ) ;
i f ( n o n u m b e r s > 0 && n o n u m b e r s <= MAX SIZE ) {
p r i n t f ( ” I n p u t t h e r e a l numbers : \ n ” ) ;
fflush ( stdout );
f o r ( i =0 , sum = 0 ; i < n o n u m b e r s ; i ++) {
p r i n t f ( ” numbers [%3d ] = ” , i + 1 ) ;
fflush ( stdout );
s c a n f ( ”%f ” , &numbers [ i ] ) ;
sum += numbers [ i ] ;
}
a v e r a g e = sum / n o n u m b e r s ;
p r i n t f ( ” \nAVERAGE = %.2 f \ n ” , a v e r a g e ) ;
}
else
p r i n t f ( ” The number o f r e a l numbers i s i n v a l i d . ” ) ;
fflush ( stdout );
return 0;
}

6 Instruct, iuni Jump


C oferă următoarele tipuri de instruct, iuni de salt:
– break – termină instruct, iunile buclă sau switch s, i transferă execut, ia către instruct, iunea
imediat după buclă sau switch;
– continue – face ca bucla să sară peste restul corpului s, i să reevalueze imediat
condit, ia de la ı̂nceputul iterat, iei;
– goto – transferă execut, ia către o declarat, ie etichetată – a iscat o adevărată dispută
legată de utilitatea sau oportunitatea folosirii ei (highly discouraged use);
– return – ies, ire dintr-o funct, ie.

21
6.1 Exercit, iu
Scriet, i un program care afis, ează toate numerele pare de la 0 la 100, inclusiv. Numărat, i
s, i cate numere pare găsit, i. Folosit, i oricare tip de buclă dorit, i. Modificat, i apoi progra-
mul pentru a accepta numerele limită de la utilizator.

7 Recomandare
10 reguli de bază pentru scrierea de cod: link1, link2.

8 Controlarea unui LED pe placa de dezvoltare Nucleo


Scrierea unui program pentru pornirea LED-ului de pe placa de dezvoltare Nucleo-
F401RE.
Este necesară cunoas, terea not, iunilor:
– pointeri – modificarea cont, inutului regis, trilor constă ı̂n modificarea unor locat, ii
de memorie (reprezentate de pointeri),
– operat, ii pe bit, i,
– conexiuni hardware.

8.1 Conexiunile hardware


Conexiunile hardware presupun cunoas, terea modului ı̂n care este conectat hardware-ul
extern la microcontroler. Pentru aceasta vom consulta schema plăcii de dezvoltare pe
care o utilizăm (Schematic - Extension connectors - LD2).
https://www.st.com/en/evaluation-tools/nucleo-f401re.html#

Figure 9: Conexiuni LED

În figură se poate vedea ca LED-ul este conectat la pinul PA5 (port A pin 5).
Numărul pinului fizic se poate găsi ı̂n manualul de referint, a (TRM) a microcontroleru-
lui, sau mai simplu, ı̂n datasheet. Controlarea acestui pin (HIGH sau LOW) controlează
LED-ul. As, adar, ceea ce vrem să realizăm este controlarea pinului I/O PA5, prin setarea
la LOW sau HIGH, de către software pentru a opri sau porni LED-ul.

22
8.2 Porturi
Porturile sunt reprezentate de regis, tri ı̂n interiorul microcontrolerului s, i permit progra-
mului (firmware-ului) să controleze starea pinilor sau, invers, să citească starea pinilor
(dacă porturile sunt configurate ca intrări).

Figure 10: Porturi microcontroler

Fiecare port din sistemele STM32Fx sunt alcătuite din 16 pini la care se pot conecta
periferice (LED, afis, aje, butoane, memorii externe, tastaturi, etc.).
PA5 este al cincilea GPIO al portului A.

8.3 Controlarea pinilor prin software


Pentru a controla pinii conectat, i la portul A se utilizează unitatea periferica GPIO A.
Aceasta are asociat un set de regis, trii utilizat, i pentru a controla pinii, modul si starea
lor s, i alte funct, ionalităt, i. Regis, tri periferici ai GPIO A sunt mapat, i ı̂n memorie. Pinii
I/O mapat, i ı̂n memorie sunt controlat, i folosind regis, trii periferici care sunt mapat, i la
locat, iile de memorie adresabile de către procesor.

Figure 11: Comunicare ı̂ntre procesor s, i periferice

Magistrala centrală conectează procesorul cu memoria, perifericele externe, timere


s, i altele. Ea este compusă din 2 canale: adresa pe 32 de bit, i s, i datele pe 32 de bit, i.
Aceasta ı̂nseamnă că este posibil să utilizam 232 adrese diferite pentru a identifica
unităt, ile accesibile. As, adar, se pot folosi adrese de la 0x00000000 la 0xFFFFFFFF (4
Giga-octet, i de adrese).

23
Locat, iile adreselor mapate de memorie sunt ı̂nregistrate ı̂n TRM. De obicei, harta
memoriei se gaseste ı̂n sect, iunea 2 a manualului de referint, ă.

Figure 12: Limitele adreselor corespunzătoare GPIOA

Tot, i regis, trii periferici ai microcontrolerului STM32 au o lăt, ime de 32 de bit, i.


Diferite periferice au un număr diferit de regis, tri. Manualul de referint, ă al dispozi-
tivului trebuie consultat ı̂ntotdeauna ı̂n legătură cu adresele corespunzătoare. Regis, trii
de tip GPIO A sunt prezentat, i ı̂n figura de mai jos. Aceias, i regis, tri sunt disponibili
pentru GPIO B, GPIO C s, i GPIO D.

Table 4: Regis, trii periferici GPIOA (GPIO register map ı̂n manual)
Nr. Registru
1 GPIOA port mode register
2 GPIOA port output type register
3 GPIOA port output speed register
4 GPIOA port pull-up/pull-down register
5 GPIOA port input data register
6 GPIOA port output data register
7 GPIOA port bit set/reset register
8 GPIOA port configuration lock register
9 GPIOA port alternate function low register
10 GPIOA port alternate function high register

Regis, trii de moduri indică dacă pinul va fi unul de intrare sau de ies, ire. Registrul
de pull-up s, i pull-down permite activarea sau dezactivarea rezistent, elor de pull-up sau
pull-down.
GPIO A este controlat de un registru pe 32 de bit, i, iar pentru a seta sau s, terge bitul
dorit (controlarea unui singur pin), este necesar să se utilizeze tehnica de mascare a
bitului respectiv. De exemplu, pentru a seta bitul 0 la HIGH este suficientă o operat, ie
SAU pe registrul GPIO A cu o mască potrivită (GPIO A SAU 0x0000001).

24
8.4 Pas, i necesari
Procedura de pornire a unui LED poate fi rezumată ı̂n următorii pas, i:
– identificarea portului GPIO (periferic) utilizat pentru conectarea LED-ului (ı̂n
cazul nostru GPIO A);
– identificarea pinului GPIO la care este conectat LED-ul, ı̂n cazul nostru 5;
– identificarea perifericului GPIO A si activarea lui (activare ceas);
– până când se activează un periferic, el este inactiv, nu funct, ionează s, i nu ia
valori de configurare setate de programator;
– odată cu activarea ceasului unui periferic, acesta este gata să preia comenzi
sau argumente (valori de configurare);
– pentru unele microcontrolere, perifericul poate fi PORNIT ı̂n mod implicit
si necesită activare (RTM – read the manual);
– configurarea modului pinului GPIO ca ies, ire (se comandă un LED);
– scriere pin (scriere Output Data Register)
– 1 - HIGH pentru 3.3V;
– 0 - LOW pentru 0V.

8.5 Activarea ceasului unui periferic


– prin regis, trii de control al ceasului periferic;
– ı̂n microcontrolerele STM32, tot, i regis, trii de control al ceasului sunt mapat, i la in-
tervalul de adrese 0x40023800 - 0x4023BFF (TRM – Table 1. STM32F401xB/C
and STM32F401xD/E register boundary addresses).
În harta de memorie există un element numit Reset and clock control (RCC). Această
unitate controlează toate ceasurile conectate la elementele de pe placă. În cazul nostru,
trebuie identificată adresa exactă pentru unitatea periferică GPIOA.
Sect, iunea 6 a TRM se concentrează pe RCC. În Figura 3 din datasheet se poate
vedea că magistrala la care este conectat GPIOA este AHB1. Va fi astfel necesară
activarea ceasului corespunzător prin modificarea registrului RCC AHB1 peripheral
clock enable register – RCC AHB1ENR.
RCC AHB1 peripheral clock enable register controlează toate semnalele de ceas
pentru perifericele conectate la magistrala AHB1.
Calcularea adresei:
Address offset: 0x30.
Base address for RCC: 0x40023800.
As, adar, adresa registrului este: 0x40023830.
În acest registru va trebui să activăm, sau setăm, bitul corespunzător lui GPIOAEN,
aflat pe pozit, ia 0 (vezi TRM). Valoarea măs, tii va fi: 0x0001.

25
Figure 13: Activare ceas pentru GPIOA

8.6 Setarea modului pinului PA5


Adresa registrului pentru modul pinului (GPIO port mode register, sect, iunea GPIO
registers a TRM):
Address of GPIOA: 0x40020000.
GPIO port mode register address offset pentru port A: 0x00.
As, adar, adresa registrului este: 0x40020000.

Figure 14: Setarea modului pentru PA5

8.7 Modificarea stării pinului PA5


Adresa registrului pentru datele de ies, ire ale pinului (GPIO port output data register,
sect, iunea GPIO registers a TRM):

26
Address of GPIOA: 0x40020000.
GPIO port output data register pentru port A: 0x14.
As, adar, adresa registrului este: 0x40020014.

Figure 15: Setarea starii pinului

27
8.8 Codul

# i n c l u d e < s t d i n t . h>

i n t main ( v o i d )
{
u i n t 3 2 t * p C l k C t r l R e g = ( u i n t 3 2 t * ) 0 x40023830 ;
u i n t 3 2 t * pPortAModeReg = ( u i n t 3 2 t * ) 0 x40020000 ;
u i n t 3 2 t * pPortAOutReg = ( u i n t 3 2 t * ) 0 x40020014 ;

/ / E n a b l e c l o c k f o r GPIOA
/ * u i n t 3 2 t temp = * p C l k C t r l R e g ;
temp = temp | 0 x0001 ;
* p C l k C t r l R e g = temp ; * /

* p C l k C t r l R e g | = 0 x0001 ;

/ / S e t o u t p u t mode f o r PA5
/ / F i r s t c l e a r mode f o r PA5
* pPortAModeReg &= ˜ 0 x00000C00 ;
/ / S e t o u t p u t mode f o r PA5
* pPortAModeReg | = 0 x00000400 ;

/ / S e t PA5 HIGH
* pPortAOutReg | = 0 x0020 ;

/ / Super loop
for ( ; ; ) ;
}

28
Urmează codul care foloses, te shiftare pe bit, i.
# i n c l u d e < s t d i n t . h>

i n t main ( v o i d )
{
u i n t 3 2 t * p C l k C t r l R e g = ( u i n t 3 2 t * ) 0 x40023830 ;
u i n t 3 2 t * pPortAModeReg = ( u i n t 3 2 t * ) 0 x40020000 ;
u i n t 3 2 t * pPortAOutReg = ( u i n t 3 2 t * ) 0 x40020014 ;

/ / E n a b l e c l o c k f o r GPIOA
/ * u i n t 3 2 t temp = * p C l k C t r l R e g ;
temp = temp | 0 x0001 ;
* p C l k C t r l R e g = temp ; * /

/ / s e t b i t 0 of ClkCtrlReg
* p C l k C t r l R e g | = 0 x0001 << 0 ;

/ / S e t o u t p u t mode f o r PA5
/ / F i r s t c l e a r mode f o r PA5 ( c l e a r b i t s 10 and 11 o f PortAModeReg )
* pPortAModeReg &= ˜ ( 0 x03 << 1 0 ) ;
/ / S e t o u t p u t mode f o r PA5 ( s e t p i n s 11 and 10 w i t h v a l u e 0 1 )
* pPortAModeReg | = ( 0 x01 << 1 0 ) ;

/ / S e t PA5 HIGH ( s e t p i n 5 o f GPIOx ODR )


* pPortAOutReg | = ( 0 x01 << 5 ) ;

for ( ; ; ) ;
}

29
8.8.1 Debug

Figure 16: Vizualizarea stării regis, trilor cu funct, ii speciale

Figure 17: Setarea bitului GPIOAEN

30
8.8.2 Modificarea codului pentru a comuta LED-ul folosind ı̂ntârzieri software

# i n c l u d e < s t d i n t . h>

i n t main ( v o i d )
{
u i n t 3 2 t * p C l k C t r l R e g = ( u i n t 3 2 t * ) 0 x40023830 ;
u i n t 3 2 t * pPortAModeReg = ( u i n t 3 2 t * ) 0 x40020000 ;
u i n t 3 2 t * pPortAOutReg = ( u i n t 3 2 t * ) 0 x40020014 ;

/ / E n a b l e c l o c k f o r GPIOA
/ * u i n t 3 2 t temp = * p C l k C t r l R e g ;
temp = temp | 0 x0001 ;
* p C l k C t r l R e g = temp ; * /

/ / s e t b i t 0 of ClkCtrlReg
* p C l k C t r l R e g | = 0 x0001 << 0 ;

/ / S e t o u t p u t mode f o r PA5
/ / F i r s t c l e a r mode f o r PA5 ( c l e a r b i t s 10 and 11 o f PortAModeReg )
* pPortAModeReg &= ˜ ( 0 x03 << 1 0 ) ;
/ / S e t o u t p u t mode f o r PA5 ( s e t p i n s 11 and 10 w i t h v a l u e 0 1 )
* pPortAModeReg | = ( 0 x01 << 1 0 ) ;

for ( ; ; )
{
/ / S e t PA5 HIGH ( s e t p i n 5 o f GPIOx ODR )
* pPortAOutReg | = ( 0 x01 << 5 ) ;

/ / For l o o p w i t h NOP
f o r ( u i n t 3 2 t i = 0 ; i <100000; i + + ) ;

/ / S e t PA5 LOW ( s e t p i n 5 o f GPIOx ODR )


* pPortAOutReg &= ˜ ( 0 x01 << 5 ) ;

/ / For l o o p w i t h NOP
f o r ( u i n t 3 2 t i = 0 ; i <100000; i + + ) ;
}
}

31
Figure 18: Dissasembly buclă for

Comutarea PA5 folosind funct, ia SAU-EXCLUSIV.


for ( ; ; )
{
/ / T o g g l e PA5 ( t o g g l e p i n 5 o f GPIOx ODR )
* pPortAOutReg ˆ = ( 0 x01 << 5 ) ;

/ / For l o o p w i t h NOP
f o r ( u i n t 3 2 t i = 0 ; i <50000; i + + ) ;
}

32
9 Citirea unei intrări pe placa de dezvoltare Nucleo
Citirea stării butonului pentru utilizator de pe placa de dezvoltare Nucleo.

9.1 Conexiuni hardware

Figure 19: Conexiuni buton USER

În figură se poate vedea că butonul este conectat la pinul PC13 (port C pin 13).
Atunci când butonul este apăsat, PC13 este LOW, iar când butonul este liber, PC13
este HIGH.
PC13 trebuie să fie ı̂n modul intrare, iar pentru a ı̂i citi starea, trebuie să citim portul
C.

9.2 Activarea ceasului pentru GPIOC


Se va modifica bitul 2 al registrului RCC AHB1ENR.

9.3 Setarea modului pinului PC13


Adresa registrului pentru modul pinului (GPIO port mode register, sect, iunea GPIO
registers a TRM):
Address of GPIOC: 0x40020800.
GPIO port mode register address offset pentru port A: 0x00.
As, adar, adresa registrului este: 0x40020800.
Se vor modifica bit, ii 26 si 27 pentru registrul GPIOC MODER (vezi Fig. 14).

9.4 Citirea starii pinului PA5


Se va citi GPIO port input data register.

33
Address of GPIOC: 0x40020800
GPIO port mode register address offset pentru port C: 0x10.
As, adar, adresa registrului este: 0x40020810.

Figure 20: Citire pin PC13

9.5 Codul

# i n c l u d e < s t d i n t . h>

i n t main ( v o i d )
{
/ / RCC AHB1 p e r i p h e r a l c l o c k e n a b l e r e g .
u i n t 3 2 t * p C l k C t r l R e g = ( u i n t 3 2 t * ) 0 x40023830 ;
/ / GPIOA p o r t mode r e g i s t e r
u i n t 3 2 t * pPortAModeReg = ( u i n t 3 2 t * ) 0 x40020000 ;
/ / GPIOA p o r t o u t p u t d a t a r e g .
u i n t 3 2 t * pPortAOutReg = ( u i n t 3 2 t * ) 0 x40020014 ;
/ / GPIOC p o r t mode r e g .
u i n t 3 2 t * pPortCModeReg = ( u i n t 3 2 t * ) 0 x40020800 ;
/ / GPIOC p o r t i n p u t d a t a r e g i s t e r
u i n t 3 2 t * p P o r t C I n R e g = ( u i n t 3 2 t * ) 0 x40020810 ;

/ / E n a b l e c l o c k f o r GPIOA
* p C l k C t r l R e g | = ( 0 x01 <<0);
/ / E n a b l e c l o c k f o r GPIOC
* p C l k C t r l R e g | = ( 0 x01 <<2);

/ / S e t PA5 a s o u t p u t
/ / C l e a r mode b i t s f o r PA5

34
/ / * pPortAModeReg &= ˜ 0 x00000C00 ;
* pPortAModeReg &= ˜ ( 0 x03 < <10);
/ / S e t mode b i t s f o r PA5
/ / * pPortAModeReg |= 0 x00000400 ;
* pPortAModeReg | = ( 0 x01 < <10);

/ / S e t PC13 a s i n p u t
* pPortCModeReg &= ˜ ( 0 x03 < <26);

/ * Loop f o r e v e r * /
for ( ; ; )
{

/ / r e a d PC13 s t a t u s
u i n t 8 t p i n S t a t u s = ( u i n t 8 t ) ( ( * p P o r t C I n R e g & ( 0 x01 < <13)) > >13);

i f ( pinStatus ) / / Button not pressed


{
/ / S e t PA5 LOW
* pPortAOutReg &= ˜ ( 0 x01 <<5);
}
else
{
/ / S e t PA5 HIGH
* pPortAOutReg | = ( 0 x01 <<5);
}
}
}

35

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