Introducere in Programarea Microcontrollerelor

49
INTRODUCERE IN PROGRAMAREA MICROCONTROLLERELOR DIN SERIA ATMEL AVR 1. Resurse necesare Resursele necesare pentru studiul microcontrollerelor din seria Atmel AVR sunt prezentate in fig. 1. Fig. 1 Resurse pentru studiul microcontrollerelor Atmel AVR Acest document prezinta detaliat fiecare din resursele de mai sus. 2. Modulul de dezvoltare cu microcontroller Schema bloc a modulelor cu care vom lucra este prezentata in fig. 2 MCU ATMega16 Interfata seriala Rs232 Interfata seriala Rs485 Interfata de programare Circuite de clock si RESET Sursa de alimentare DRIVERE PE LINIILE DE IESIRE CIRCUITE PENTRU IZOLARE INTRARI Fig. 2 Schema bloc a modulelor de dezvoltare COMPUTER ECHIPAT CU UN COMPILATOR PENTRU LIMBAJUL C PROGRAMATOR MODUL DE DEZVOLTARE CU MICROCONTROLLER

Transcript of Introducere in Programarea Microcontrollerelor

Page 1: Introducere in Programarea Microcontrollerelor

INTRODUCERE IN PROGRAMAREA MICROCONTROLLERELOR DIN SERIA ATMEL AVR

1. Resurse necesare Resursele necesare pentru studiul microcontrollerelor din seria Atmel AVR sunt prezentate in fig. 1.

Fig. 1 Resurse pentru studiul microcontrollerelor Atmel AVR Acest document prezinta detaliat fiecare din resursele de mai sus. 2. Modulul de dezvoltare cu microcontroller Schema bloc a modulelor cu care vom lucra este prezentata in fig. 2

MCUATMega16

Interfataseriala Rs232

Interfataseriala Rs485

Interfata deprogramare

Circuite declock si RESET

Sursa dealimentare

DRIVERE PELINIILE DEIESIRE

CIRCUITEPENTRUIZOLAREINTRARI

Fig. 2 Schema bloc a modulelor de dezvoltare

COMPUTERECHIPAT CU UNCOMPILATORPENTRULIMBAJUL C

PROGRAMATOR

MODUL DEDEZVOLTARE CUMICROCONTROLLER

Page 2: Introducere in Programarea Microcontrollerelor

2.1. Schema de principiu a modulului cu 2 relee

ATMega16

Y1

16MHZ SS

O0

O1

O2

O3

PB0/T01

PB1/T12

PB2/INT23

PB3/OC04

PB4/SS5

PB5/MOSI6

PB6/MISO7

PB7/SCL8

RESET9

VCC10

GND11

XT AL212

XT AL113

PD0/RXD14

PD1/TXD15

PD2/INT016

PD3/INT117

PD418

PD519

PD620

PA040

PA139

PA238

PA337

PA436

PA535

PA634

PA733

AREF32

GND31

AVCC30

PC729

PC628

PC527

PC426

PC325

PC224

PC123

PC022

PD721

U1

AN0

AN1

I7

I6

I5

VREF

VREF

XT AL2

XT AL1

RXD

MOSI

MISO

SCL

RESET

VCCC2

22p

C1

22p

VCC

R30

10K

TXD

O4

O5

PWM1

O6

PWM2

I4

I3

I2

I1

I0

O7

JP1

JUMPER

RESET

C23

2.2uF

Fig. 3 Schema de principiu a modulului de dezvoltare (MCU+clock+RESET)

1

3

5

7

9

2

4

6

8

10

J3

CON10A

BA

RX232

DTR2321

3

5

7

9

2

4

6

8

10

J1

CON10A

DCD232

TX232

Conector RS232

Conector RS485

RX

D2

RX

D

12

3 J2 CO

N3

B

RX

D1

VCC

R5

10K

D4

DE3

R1

RE2

A6

B7

U3

SN75176

TXD

PA7

RXD2

Interfata RS485

A

B

R6

10K

C1+1

V+2

C1-3

C2+4

C2-5

V-6

T2OUT7

R2IN8

R2OUT9

T2IN10

T1IN11

R1OUT12

R1IN13

T1OUT14

U2

MAX232

Interfata RS232

C3

22uF

C4

22uF

RX232

DCD232

TXD

RXD1

I0

TX232

DTR232

O7

C5

22uF

C6

22uF

VCC

JUMPER PENTRUSELECTIA RS232-RS485

Fig. 4 Interfetele seriale RS232/RS485

Page 3: Introducere in Programarea Microcontrollerelor

Fig. 5. Driverele pentru iesirile digitale si releele

VCC

VCC

12

13

A11

K12

K23

A24

A35

K36

K47

A48

E116

C115

C214

E213

E312

C311

C410

E49

U6

CNY74-4

I0

I1

XI0

XI1

R16

4K7

R17

4K7

R18

4K7

XI2

XI3

R19

4K7

I2

I3

VCC

VCC

14

15

XI0

XI1

XI2

XI3

1

2

3

4

J13

XI4

XI5

XI6

XI7

1

2

3

4

J14

VCC

VCC

16

17

A11

K12

K23

A24

A35

K36

K47

A48

E116

C115

C214

E213

E312

C311

C410

E49

U7

CNY74-4

I4

I5

XI4

R20

4K7

R21

4K7

XI5

XI6

XI7

R22

4K7

R23

4K7

I6

I7

VCC

VCC

18

R12G

19

R12H

XA0

XA1

AO0

AO1

1

2

3

4

J15

Fig. 6 Circuitele pentru izolarea intrarilor digitale

C0

NO0

NC0

NO1

1

2

3

4

5

6

J11NC0

K1

C0

REL0

REL1

REL2

REL3

REL4

REL5

I11

I22

I33

I44

I55

I66

I77

I88

GND9

KID10

O811

O712

O613

O514

O415

O316

O217

O118

U5

ULN2803S

O0

O1

O2

O3

O4

O5

O6

O7

Iesiri digitale

Vpp

REL6

REL7

VPP

REL0

NO0C1

NC1

REL21

2

3

4

5

6

J12

REL3

REL4

REL5

REL6

REL7

NC1

NO1

K2

REL1

C1

VPP

Page 4: Introducere in Programarea Microcontrollerelor

VCC

VCC

AO0

10

9

8

4

11

U9C

TL084

V-

R9

1K C17

2.2uF

AN0 PH0

3

2

1

4

11

U9A

TL084

V-

D3

DZ5V1

XA0

D4

DZ5V1

5

6

7

4

11

U9B

TL084

VCC

VCC

AO1

12

13

14

4

11

U9D

TL084

V-

R10

1K C18

2.2uF

AN1 PH1

V-

XA1

Intrari analogice Iesiri analogice (PWM)

Fig. 7 Circuitele pentru adaptarea intrarilor analogice si iesirile PWM Schema modulului cu 8 relee este prezentata integral in fig. 8 Diferente intre cele doua module: a. Modulul cu 8 relee nu mai foloseste intrari/iesiri analogice b. In schimb, sunt disponibile mai multe intrari digitale I8-I15, pe conectorul J21 c. Cablajul imprimat permite conectarea a pana la 8 relee direct pe placa. Nota Consultati foile de catalog ale circuitelor de interfata pentru a intelege bine functionarea intregului montaj

Page 5: Introducere in Programarea Microcontrollerelor

VP

PX

1 2 3 4J1

3

1 2 3 4J1

4

1 2 3 4J1

6

C0

NO

0

C1

NO

1

C2

NO

2

C3

NO

3

K1

RE

L2

C0

NO

0

R1

6

4K

7R

17

4K

7

R1

8

4K

7

RE

L0

RE

L1

RE

L2

D1

6

D1

7

D1

8

Vp

p

Vp

p

Vp

p

VC

C

VC

C

A1

1

K1

2

K2

3

A2

4

A3

5

K3

6

K4

7

A4

8

E1

16

C1

15

C2

14

E2

13

E3

12

C3

11

C4

10

E4

9

U11

CN

Y7

4-4

I0 I1

12

R3

5A

13

R3

5B

VR

EF

VR

EF

I5I6I7

XI0

R3

1

4K

7

R3

2

4K

7

I8 I9 I10

I11

I12

I13

I14

I15

XTA

L2

XTA

L1

RX

D

SS

MO

SI

MIS

O

RE

SE

T

O0

O1

O2

O3

VC

C

PB

0/T

01

PB

1/T

12

PB

2/I

NT

23

PB

3/O

C0

4

PB

4/S

S5

PB

5/M

OS

I6

PB

6/M

ISO

7

PB

7/S

CL

8

RE

SE

T9

VC

C1

0

GN

D11

XTA

L2

12

XTA

L1

13

PD

0/R

XD

14

PD

1/T

XD

15

PD

2/I

NT

01

6

PD

3/I

NT

11

7

PD

41

8

PD

51

9

PD

62

0

PA

04

0

PA

13

9

PA

23

8

PA

33

7

PA

43

6

PA

53

5

PA

63

4

PA

73

3

AR

EF

32

GN

D3

1

AV

CC

30

PC

72

9

PC

62

8

PC

52

7

PC

42

6

PC

32

5

PC

22

4

PC

12

3

PC

02

2

PD

72

1

U1

AT

90

S8

53

5

SC

K

Y1

8M

HZ

C1

22

p

C2

22

p

VC

C

JP

1

JU

MP

ER

R3

0

10

K

C2

3

2.2

uFRE

SE

T

TX

D

O4

O5

PW

M1

O6

PW

M2

I3 I2 I1 I0 O7

I4

XI1

XI2

XI3

R3

3

4K

7

R3

4

4K

7

I2 I3

14

R3

5C

15

R3

5D

D1

9

D2

0

D2

1

D2

2

Vp

p

Vp

p

Vp

p

Vp

p

VC

C

VC

C

R1

9

4K

7

R2

0

4K

7R

21

4K

7

R2

2

4K

7

RE

L3

RE

L4

RE

L5

RE

L6

K2

RE

L2

VP

P

VP

P

RE

L0

RE

L1

C1

NO

1

1 2 3 4J1

9

CO

N4

1 2 3 4J2

0

CO

N4

C4

NO

4

C5

NO

5

C6

NO

6

C7

NO

7

1 2 3 4J2

2

CO

N4

XI0

XI1

XI2

XI3

K3

RE

L2

VP

P

RE

L2

C2

NO

2

R2

3

4K

7

RE

L7

D2

3

Vp

p

RX

23

2

VC

C

I9 I11

I13

I15

RX

23

2

1 3 5 7 9

2 4 6 8

10

J1

CO

N1

0A

DC

D2

32

RX

D1

1 3 5 7 9

2 4 6 8

10

J2

1

CO

N1

0A

I8 I10

I12

I14

C1

+1

V+

2

C1

-3

C2

+4

C2

-5

V-

6

T2

OU

T7

R2

IN8

R2

OU

T9

T2

IN1

0

T1

IN11

R1

OU

T1

2R

1IN

13

T1

OU

T1

4

U2

MA

X2

32

C3

22

uF

JP

2

JU

MP

ER

DC

DI0

VC

C

C4

22

uF

C5

22

uF

C6

22

uF

DC

D2

32

TX

D

TX

23

2

DT

R2

32

TX

23

2

TX

D

RX

D2

RX

D

O7

O7

DC

DD

TR

23

2

D4

DE

3

R1

RE

2

A6

B7

U3

SN

75

17

6

A B

VC

C

R5

10

K

R6

10

K

1 3 5 7 9

2 4 6 8

10

J1

0

CO

N1

0A

RE

SE

T

PD

2-M

ISO

PD

3-M

OS

I

PD

4-S

CK

PD

5-S

S

SC

K

MIS

O

MO

SI

SS

0V

CC

SS

1

SS

2

SS

3

K4

RE

L2

K5

RE

L2

VP

P

RE

L3

C3

C4

NO

3

K6

RE

L2

VP

P

RE

L4

C5

NO

4

NO

5

SS

0

SS

1

SS

2

SS

3

1 3 5 7 9

2 4 6 8

10

J1

7

CO

N1

0A

SS

12

3 J2

CO

N3

B

RX

D2

1 3 5 7 9

2 4 6 8

10

J3

CO

N1

0A

AB

VP

P

RX

D1

VC

C

VC

CV

CC

C9

22

uF

C1

0

10

0n

C11

10

0n

C1

4

10

0u

F

12

D2

1N

40

01

VP

PX

VP

P

C2

1

C1

VC

C

C2

2

C1

Vp

p

VC

C

Vcc

R2

7

47

0

D7

I11

I22

I33

I44

I55

I66

I77

I88

GN

D9

KID

10

O8

11

O7

12

O6

13

O5

14

O4

15

O3

16

O2

17

O1

18

U5

UL

N2

80

3S

O0

O1

O2

O3

O4

O5

O6

O7

RE

L0

RE

L1

RE

L2

RE

L3

RE

L4

RE

L5

RE

L6

RE

L7

Vp

p

K7

RE

L2

VP

P

VP

P

RE

L5

RE

L6

C6

NO

6

K8

RE

L2

VP

P

RE

L7

C7

NO

7

VR

EF

VC

C

R3

10

0

C1

9

2.2

uF

IN1

G N D

2

OU

T3

U1

0

UA

78

05

VP

P

Fig. 8 Schema completa a modulului cu 8 relee

Page 6: Introducere in Programarea Microcontrollerelor

3. Programatorul ISP Memoria de program a microcontrollerului ATMega16 este de tip flash si se poate programa “in system” (ISP) cu ajutorul unor interfete simple. Vom folosi cea mai simpla interfata de programare, denumita in literatura “Kanda systems”, sau STK200. Schema de principiu a interfetei este prezentata in fig. 9.

Fig. 9 Scheme interfetei de programare Kanda Systems Denumirea Kanda Systems vine de la firma care a comercializat-o initial. Se conecteaza prin J1 la portul paralel al computerului, iar la J2 cu modulul de dezvoltare echipat cu microcontroller. Comunicatia cu microcontrollerul este de fapt seriala. Alimentarea circuitului 74HC244 se face din sursa modulului de dezvoltare prin conectorul J2. Evident ca pe computerul la care se conecteaza interfata trebuie sa existe un soft special care sa controleze dialogul cu microcontrollerul pentru programare. In cazul de fata, compilatorul HP Infotech cu care lucram include un modul de programare.

Page 7: Introducere in Programarea Microcontrollerelor

4. Compilatorul CodeVisionAVR produs de HP INFOTECH Este unul din cele mai bune produse de acest gen disponibil pe piata. Principalul sau avantaj consta in existenta unui asa-numit “CodeWizzard”, care automatizeaza procedura de creare a unui nou proiect si genereaza automat codul pentru initializarea diverselor subsisteme ale microcontrollerului. Utilizatorului ii ramane doar sarcina de a scrie programul principal. In acest paragraf, este prezentata pas cu pas secventa de creare a unui proiect, prin care se comanda iesirea digitala PB0 alternativ ON/OFF cu durata de 0.5 secunde. Pasul 1. Se lanseaza CVAVR Pasul 2. Din menu-ul principal se selecteaza optiunea File, New Programul prezinta urmatoarea fereastra de dialog:

Fig. 10 Secventa de dialog CVAVR Se selecteaza Project si se apasa butonul OK. Pasul 3. CVAVR prezinta fereastra de dialog din fig. 11

Fig. 11 Dialog CVAVR Se raspunde cu Yes pentru lansarea utilitarului CodeWizard Pasul 4. Se selecteaza tipul de microcontroller cu care se lucreaza – in cazul de fata ATMega16 si frecventa oscilatorului (data de cristalul de quartz care echipeaza modulul – in cazul de fata 16MHz). (vezi fig. 12)

Page 8: Introducere in Programarea Microcontrollerelor

Fig. 12 Dialog CodeWizardAVR Pasul 5. Configurarea resurselor folosite in proiect. Singura resursa folosita in exemplul considerat este Port B bit 0. Se selecteaza Tab-ul Ports. Se obtine fereastra de dialog din figura 13.

Fig. 13 Dialog CodeWizardAVR

Page 9: Introducere in Programarea Microcontrollerelor

In aplicatia noastra, din toate resursele microcontrollerului folosim doar o linie din portul B, pe care dorim s-o configuram ca linie de iesire. In consecinta, vom selecta Tab-ul marcat Port B, apoi vom face click pe Bit 0. Se obtine fereasta din figura 14.

Fig. 14. Configurarea Port B bit 0 ca linie de iesire cu CodeWizardAVR Pasul 6. Generarea efectiva a proiectului Se alege din menu-ul CodeWizardAVR optiunea File, si apoi Generate Save and Exit. In continuare programul prezinta o fereastra de dialog in care se solicita numele dorit pentru fisierele sursa (.C) project (.prj) si CodeWizardProject (.cwp) (vezi fig. 15). Pentru usurinta gestionarii proiectelor, este recomandabil sa salvati fiecare proiect nou intr-un folder distinct, de exemplu C:\CVAVR\WORK\LED1 Puteti selecta acelasi nume (led1) pentru fisierele sursa (.c) si project (.prj, .cwp). Dupa salvarea proiectului nou generat, se paraseste utilitarul CodeWizardAVR si se intra in editorul CodeVisionAVR, afisandu-se in partea dreapta programul sursa generat de Wizard. Acesta contine chiar o serie de comentarii si indicatii de genul “Place you global variables here”, “Place your code here”, etc., care sunt utile la primul contact cu mediul CodeVisionAVR.

Page 10: Introducere in Programarea Microcontrollerelor

Fig. 15 Dialogul pentru salvarea proiectului Pasul 7. Editarea fisierelor generate automat de CodeWizardAVR Iata listing-ul complet al programului generat automat: /************************************************** *** This program was produced by the CodeWizardAVR V1.25.5 Standard Automatic Program Generator © Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r .l. http://www.hpinfotech.com Project : Version : Date : 3/14/2008 Author : Y406 Company : Ugal. Comments: Chip type : ATmega16 Program type : Application Clock frequency : 16.000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 *************************************************** **/ #include <mega16.h> // Declare your global variables here void main(void) { // Declare your local variables here // Input/Output Ports initialization // Port A initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Fun c2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T Sta te2=T State1=T State0=T PORTA=0x00; DDRA=0x00; // Port B initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Fun c2=In Func1=In Func0=Out

Page 11: Introducere in Programarea Microcontrollerelor

// State7=T State6=T State5=T State4=T State3=T Sta te2=T State1=T State0=0 PORTB=0x00; DDRB=0x01; // Port C initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Fun c2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T Sta te2=T State1=T State0=T PORTC=0x00; DDRC=0x00; // Port D initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Fun c2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T Sta te2=T State1=T State0=T PORTD=0x00; DDRD=0x00; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: Timer 0 Stopped // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x00; TCNT0=0x00; OCR0=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: Timer 1 Stopped // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization // INT0: Off // INT1: Off // INT2: Off MCUCR=0x00; MCUCSR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x00; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off

Page 12: Introducere in Programarea Microcontrollerelor

ACSR=0x80; SFIOR=0x00; while (1) { // Place your code here }; }

Observati urmatoarele elemente: a. #include <mega16.h> - este header-ul care contine definitiile resurselor

corespunzator microcontrollerului selectat. b. In functia main() se incepe cu o serie de initializari din care remarcam

initializarea registrului de directie asociat cu Port B, DDRB cu valoarea 0x01, ceea ce este echivalent cu configurarea Port B bit 0 ca linie de iesire.

c. Dupa initializari, programul continua cu un while (1) – o bucla infinita unde trebuie plasat codul aplicatiei propriu-zise.

Editarea sursei generate automat are in vedere urmatoarele aspecte: a. O modificare de ordin “cosmetic” – destinata sa faca programul mai usor de

citit, consta in eliminarea comentariilor inutile si plasareaq tuturor initializarilor intr-o functie init(), care va fi apelata la inceputul main().

b. Nu uitati sa includeti propriile comentarii care sa va ajute sa rememorati scopul proiectului si eventualele amanunte demne de retinut in legatura cu el.

c. Alegerea si includerea fisierelor header necesare aplicatiei (daca este cazul) d. Scrierea functiei main corespunzator cerintelor aplicatiei Iata cum arata programul dupa editare: /* Un prim test cu microcontrollerul ATMega16 Se comanda comutarea alternativa ON/OFF la interval e de 0.5 sec a unui LED conectat la Portb bit 0. Constantele de timp folosesc functiile predefinite in delay.h */ #include <mega16.h> #include <delay.h> // Declare your global variables here void init(void); void main(void) { // Declare your local variables here init();

Page 13: Introducere in Programarea Microcontrollerelor

while (1) { // Place your code here PORTB.0=1; delay_ms(500); PORTB.0=0; delay_ms(500); }; } void init(void) { // Input/Output Ports initialization // Port A initialization PORTA=0x00; DDRA=0x00; // Port B initialization PORTB=0x00; DDRB=0x01; // Port C initialization PORTC=0x00; DDRC=0x00; // Port D initialization PORTD=0x00; DDRD=0x00; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: Timer 0 Stopped // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x00; TCNT0=0x00; OCR0=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: Timer 1 Stopped // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock

Page 14: Introducere in Programarea Microcontrollerelor

// Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization // INT0: Off // INT1: Off // INT2: Off MCUCR=0x00; MCUCSR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x00; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; }

Pasul 8 – Compilarea programului si generarea codului executabil. Din menu-ul principal se selecteaza Project apoi Make. Daca la compilare se detecteaza erori, acestea sunt semnalate. Pasul 9. Transferul programului executabil in memoria microcontrollerului In urma compilarii, CVAVR genereaza un fisier cu extensia .rom care contine codul executabil al aplicatiei. Inainte de a lansa utilitarul de programare, asigurati-va ca a fost selectat programatorul corect (Kanda systems). In acest scop, selectati din menu-ul principal optiunea Settings si apoi, Programmer si specificati tipul de programator si portul paralel la care acesta este conectat. (LPT1:)

Fig. 16 Selectia tipului de programator

Page 15: Introducere in Programarea Microcontrollerelor

Se conecteaza programatorul la conectorul J10 si se alimenteaza modulul de dezvoltare ca in figura 17. Asigurati-va ca programatorul este conectat si la portul paralel al computerului.

Conector programator

V+ GND Fig. 17 Conectarea programatorului si a tensiunii de alimentare Nota: Alimentarea modulului se face de la un alimentator stabilizat de 12V dc, cu polaritatea indicata in figura 17. Curentul necesar este de circa 100mA. Programatorul se alimenteaza pe cablul de conectare la modulul cu microcontroller din sursa stabilizata de 5V a acestuia, deci nu mai e necesara o sursa suplimentara pentru programator. Lansarea modulului soft de programare se face alegand din menu-ul principal optiunea Tools si apoi Chip Programmer, sau direct actionand butonul marcat cu un chip ca in figura 18.

LANSARE PROGRAMATOR

Fig. 18 Lansarea modulului soft de programare

Page 16: Introducere in Programarea Microcontrollerelor

Fereastra de dialog a programatorului este prezentata in figura 19.

Fig. 19 Fereastra de dialog a programatorului Programarea efectiva a chipului consta in urmatoarele etape: a. Stergerea memoriei flash. Se face selectand din menu optiunea Program - >

Erase chip. b. Incarcarea fisierului .rom in bufferul programatorului. Se face alegand din

menu optiunea File ->Load Flash c. Transferul continutului bufferului in memoria flash a microcontrollerului. Se

face alegand din menu optiunea Program - > FLASH. Transferul dureaza cateva secunde in functie de lungimea programului, dupa care programul este automat lansat in executie. Daca toate etapele de mai sus au fost parcurse corect, LED-ul conectat la PortB bit 0 incepe sa clipeasca cu frecventa de 1Hz. Precautii importante 1. Inainte de a face orice operatie cu programatorul, asigurati-va ca check-box-

ul “program fuse bits este sters (nemarcat). Programarea la intamplare a fuse-bits conduce aproape intotdeauna la “defectarea” microcontrollerului – in sensul ca puteti dezactiva viitoarele programari, sau puteti configura clock-ul altfel decat cu oscilatorul cu cristal de quartz existent pe placa. In orice situatie, aceste configurari la intamplare fac inutilizabil circuitul.

2. Nu folositi NICIODATA butonul Program All!

Page 17: Introducere in Programarea Microcontrollerelor

Exercitiu: Modificati exemplul de mai sus in asa fel incat LED-ul de pe PORTB bit 0 sa comute la intervale de o secunda, iar LED-ul de pe PORTB bit 1 sa comute la intervale de 500ms. Indicatie: - se modifica functia init, in asa fel incat sa se configureze bit 0 si bit 1 ai PortB

ca linii de iesire. - Se modifica main() in asa fel incat sa se comande si PortB bit 1 Introducere in programarea microcontrollerelor din seria Atmel AVR Partea a II-a II.1 Exemplu de folosire a liniilor de intrare iesire digitale. Comanda unui motor pas cu pas. Tema: Sa se scrie un program care sa comande un motor pas cu pas in sens de rotatie direct daca intrarea portului C bitul 0 este in 1 si in sens invers daca intrarea portului C bitul zero este 0. Motorul se conecteaza prin driverul ULN2803 la liniile PORTD bitii 2,3 5, si 7. Solutie: Iata listing-ul programului care corespunde cerintelor de mai sus: #include <mega16.h> #include <delay.h> // Declare your global variables here unsigned char STEPM[4]={0x04,0x08,0x20,0x80}; int current_position; void step(int i); void init(void); void main(void) { init(); while (1) { step(current_position); delay_ms(3); }; } /* Rutina step executa un pas inainte sau inapoi in fu nctie de starea liniei de intrare 0 a portului C

Page 18: Introducere in Programarea Microcontrollerelor

*/ void step(int offset) { if(PINC.1==1) { PORTB.0=1; //semnalizare pe LED PORTD=STEPM[offset]; offset++; if(offset==4) offset=0; current_position=offset; } if(PINC.1==0) { PORTB.0=0; //semnalizare pe LED PORTD=STEPM[offset]; offset--; if(offset<0) offset=3; current_position=offset; } }

Observatii: 1. Listingul de mai sus nu contine si initializarile. Asigurati-va ca in rutina de

initializari, ati configurat PORTD in mod output (DDRD=0xFF) si PORTB.1 de asemenea in mod output.

2. Important! Cand se citeste un port de intrare folositi PINx in loc de PORTx . PORTx se foloseste NUMAI in operatiile de scriere intr-un port de iesire. Daca in program faceti citirea PORTx in loc de PINx, obtineti ultima valoarea scrisa in port NU STAREA LINIEI DE INTRARE.

II.2 Un exemplu de folosire a timerelor In exemplele precedente, pentru controlul unor intarzieri am folosit functiile predefinite delay_ms(unsigned int) - intarziere cu un numar de milisecunde definit de parametrul functiei si delay_us(unsigned int) – intarziere cu un numar de microsecunde definit de parametrul functiei. Dezavantajul acestei solutii este acela ca functiile delay realizeaza intarzierea printr-o bucla de asteptare (decrementarea unui contor). Pe durata asteptarii, microcontrollerul nu mai poate executa alte functii si efectul este ca 99% din timpul total se pierde in asteptare. O solutie mult mai buna este sa folosim timerele interne pentru generarea unor intervale de timp precise. In esenta, subistemul timer al unui microcontroller contine un numarator realizat hardware, care poate numara pe un ceas cu frecventa selectabila prin program (cu ajutorul unui asa-numit prescaller). Susbsitemul timer poate genera cereri de intrerupere in urmatoarele situatii: a. La overflow – cand se atinge valoarea maxima, inainte de revenirea la starea

0 a numaratorului (numararea se face de regula in sens direct)

Page 19: Introducere in Programarea Microcontrollerelor

b. La “output compare” – cand valoarea din numarator egaleaza valoarea dintr-un registru special (OCR – output compare register) care este accesibil pentru scriere/citire prin program

c. La o conditie de “input capture” – cand se detecteaza o tranzitie (front crescator sau cazator al unei intrari asociate cu timerul respectiv).

Generarea unor intervale precise cu ajutorul intreruperii de overflow a unui timer. La scrierea unei valori CNTVAL in numaratorul timerului, (TCNT) se stie ca acesta va ajunge la overflow peste un numar de (0xFFFF-CNTVAL+1) perioade ale ceasului de numarare. De exemplu, daca dorim ca timerul sa genereze intreruperi la intervale de 2ms, iar frecventa selectata pentru ceasul de numarare a timerului este 2MHz, atunci trebuie sa scriem in TCNT la fiecare intrerupere valoarea CNTVAL=(65535-4000+1). Generarea unor intervale precise de timp cu ajutorul functiei output compare In cazul output compare se genereaza intrerupere in momentul cand numaratorul ajunge sa egaleze valoarea scrisa prin program in registrul OCR asociat. Ca sa generam interruperi la intervale de 2ms cu un ceas de 2MHz, trebuie sa adunam valoarea curenta a OCR cu 4000 si sa scriem rezultatul inapoi in OCR. In acest fel, urmatoarea intrerupere va surveni peste 4000 de perioade ale ceasului de numarare, adica – la 2MHz – peste 2ms. Exercitiu Folosind timerul 1 in mod output compare, sa se scrie un program care sa comande alternativ LED-urile conectate pe PORTb.0 si PORTB.1 la intervale de timp de 200ms respectiv 330ms. Solutie: 1. Se parcurge procedura de creare a unui nou proiect descrisa anterior 2. Se configureaza PORTB in asa fel incat bitul 0 si 1 sa fie iesiri. 3. Se configureaza Timer1 ca in figura 1: 4. Se salveaza proiectul 5. Se editeaza proiectul generat automat de CodeWizard, conform cu listing-ul

urmator: #include <mega16.h> unsigned char TTAB[8]; unsigned int OCR1; bit qtoc=0;

Page 20: Introducere in Programarea Microcontrollerelor

// Timer 1 output compare A interrupt service routi ne // se seteaza flagul qtoc // se scrie OCR1 cu valoarea curenta + 20000 - in a sa fel incat urmatoarea // intrerupere sa vina peste 10ms interrupt [TIM1_COMPA] void timer1_compa_isr(void) { qtoc=1; OCR1=(OCR1AH*256+OCR1AL)+20000; OCR1AH=(OCR1&0xFF00)>>8; OCR1AL=OCR1&0xFF; } void init(void); void soft_timers(void); void dectmr10ms(void); void main(void) { init(); TTAB[0]=20; // 20*10=200ms TTAB[1]=33; // 33*10=330ms // Global enable interrupts #asm("sei") while (1) { soft_timers(); if(TTAB[0]==0) { TTAB[0]=20; PORTB.0=!(PORTB.0); } if(TTAB[1]==0) { TTAB[1]=33; PORTB.1=!(PORTB.1); } }; } // Verifica daca a fost intrerupere (qtoc=1) // Daca a fost, sterge flagul qtoc, apoi decremente aza TTAB[i] daca // valoarea gasita este mai mare decat zero void soft_timers(void) { if(qtoc==0) return; qtoc=0; dectmr10ms();

Page 21: Introducere in Programarea Microcontrollerelor

} void dectmr10ms(void) { unsigned char i; for(i=0;i<8;i++) { if(TTAB[i]!=0) TTAB[i]--; } }

Fig. 1 Configurarea timer1 pentru intreruperi la output compare, cu ceas de 2MHz Observatii - In rutina de tratare a intreruperii, care se executa la intervale de 10ms, se

seteaza flagul qtoc (care va fi testat apoi de functia soft_timers() ) si se aduna 20.000 la valoarea curenta din OCR1A, in asa fel incat urmatoarea intrerupere sa vina peste 20000*0.5us=10000us=10ms

Page 22: Introducere in Programarea Microcontrollerelor

- Rutina soft_timers() verifica valorile din matricea TTAB[8] – daca sunt diferite de zero le decrementeaza. In acest fel, daca scriem prin program o valoare in TTAB, aceasta va fi decrementata la intervale de 10ms pana la zero.

- Pentru a realiza prin program diverse intervale de timp, tot ce avem de facut este sa initializam TTAB cu valoarea dorita si sa testam momentul cand timerul soft TTAB ajunge la zero.

II.3. Organizarea modulara a proiectelor Pe masura ce complexitatea programelor creste, constatam ca este incomod sa scriem intregul program sursa intr-un singur fisier. CVAVR permite organizarea proiectelor in mai multe fisiere sursa, care sunt compilate simultan. Pe langa avantajul comoditatii, acest mod de organizare are inca un avataj major – modulele scrise si testate pot fi refolosite, practic fara modificari in alte proiecte. Exercitiu Sa se reorganizeze proiectul din exercitiul precedent, in asa fel incat toate rutinele refoeritoare la timer sa fie plasate intr-un fisier distinct de modulul main. Solutie 1. Din menu-ul principal, se selecteaza New 2. Apare fereastra de dialog din figura 2

Fig. 2 Fereatra de dialog pentru crearea unui nou fisier sursa Se creaza automat fisierul gol untitled.c. Se salveaza (Save as) cu numele dorit – timer1.c.

Page 23: Introducere in Programarea Microcontrollerelor

Fig. 3 Fereastra navigatorului dupa crearea unui nou fisier 3. Cu Cut si Paste se muta din fisierul principal toate variabilele si functiile care

se refera la timer in noul fisier creat. Se adauga #include <mega16.h> si in fisierul nou creat!!

4. Se definesc in modulul main ca externe functiile si variabilele mutate in fisierul nou creat.

5. Se alege din menu-ul principal optiunea Project -> Configure si se adauga fisierul nou creat la proiect. (vezi fig. 4)

Fig. 4 Adaugarea fisierului nou creat la proiect 6. Se apasa butonul Add si din fereastra de dialog care urmeaza se selecteaza

fisierul nou creat. Fereastra navigatorului devine:

Page 24: Introducere in Programarea Microcontrollerelor

Fig. 5 Fereastra navigatorului dupa adaugarea fisierului timer1.c la proiect 7. Se compileaza proiectul (din menu-ul principal se alege optiunea Project ->

Make) Iata listingul celor doua module ale proiectului in forma finala: Modulul principal – tmr1.c #include <mega16.h> extern void init_timer1(void); extern void soft_timers(void); extern unsigned char TTAB[8]; void init(void); void main(void) { init(); init_timer1(); TTAB[0]=20; // 20*10=200ms TTAB[1]=33; // 33*10=330ms // Global enable interrupts #asm("sei") while (1) { soft_timers(); if(TTAB[0]==0) { TTAB[0]=20; PORTB.0=!(PORTB.0); } if(TTAB[1]==0) {

Page 25: Introducere in Programarea Microcontrollerelor

TTAB[1]=33; PORTB.1=!(PORTB.1); } }; }

Modulul timer1.c #include <mega16.h> unsigned char TTAB[8]; unsigned int OCR1; bit qtoc=0; void dectmr10ms(void); // Timer 1 output compare A interrupt service routi ne // se seteaza flagul qtoc // se scrie OCR1 cu valoarea curenta + 20000 - in a sa fel incat // urmatoarea intrerupere sa vina peste 10ms interrupt [TIM1_COMPA] void timer1_compa_isr(void) { qtoc=1; OCR1=(OCR1AH*256+OCR1AL)+20000; OCR1AH=(OCR1&0xFF00)>>8; OCR1AL=OCR1&0xFF; } void soft_timers(void) { if(qtoc==0) return; qtoc=0; dectmr10ms(); } void dectmr10ms(void) { unsigned char i; for(i=0;i<8;i++) { if(TTAB[i]!=0) TTAB[i]--; } } void init_timer1(void) { // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 2000.000 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off

Page 26: Introducere in Programarea Microcontrollerelor

// Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: On // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x02; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; } II.4. Refolosirea modulelor soft in alte proiecte Exercitiu Sa se implementeze soft un monostabil care sa activeze LED-ul conectat la PORTB.0 pentru o durata de 2 secunde, de fiecare data cand se activeaza intrarea PORTC.0 (nota: intrarea este actiuva LOW din cauza optocuplorului). 1. Se deschide proiectul tmr1 2. In fereastra navigatorului, se selecteaza fisierul tmr1.c 3. Din menu-ul principal se selecteaza optiunea Save as si se salveaza fisierul

intr-un folder nou creat – sa zicem C:\cvavr\work\tmr2 4. Se repeta operatia cu toate fisierele din proiectul model pe care dorim sa le

folosim in noul proiect. 5. Se inchide proiectul model 6. Se foloseste CodeWizard pentru a genera un nou proiect. Se salveaza noul

proiect cu denumirea tmr2 7. Se inlocuieste continutul fisierului tmr2.c cu continutul fisierului tmr1.c folosind

Copy/Paste. 8. Se configureaza noul proiect incat sa includa fisierul timer1.c 9. Se recompileaza pentru a verifica corectitudinea operatiilor. daca nu sunt

erori, procesul de export a proiectului este incheiat si acum putem trece la editarea noului proiect.

Modificarile pentru implementarea functiei de monostabil se executa doar in modulul principal, conform listing-ului urmator: #include <mega16.h> extern void init_timer1(void); extern void soft_timers(void); extern unsigned char TTAB[8]; void init(void);

Page 27: Introducere in Programarea Microcontrollerelor

void main(void) { init(); init_timer1(); TTAB[0]=0; // Global enable interrupts #asm("sei") while (1) { soft_timers(); if(PINC.0==0) TTAB[0]=200; if(TTAB[0]!=0) PORTB.0=1; if(TTAB[0]==0) PORTB.0=0; } } Introducere in programarea microcontrollerelor din seria Atmel AVR Partea a III-a III. Exemple de utilizare a interfetei seriale asincrone III.1. Generalitati despre comunicatia seriala asincrona Majoritatea microcontrollerelor sunt echipate cu o interfata seriala asincrona denumita SCI (Serial Communication Interface) sau UART/USART (Universal Synchronous/Asynchronous Receiver Transmitter). In principiu, o transmisie seriala asincrona poate fi realizata cu ajutorul unor registre de deplasare, ca in figura 1.

Tx Shift register Rx Shift register

TxCLK RxCLK

Data Data

Serial

line

Transmiter Receiver Fig. 1 Schema bloc a unei comunicatii asincrone Se observa ca pe linia de comunicatie nu se transmite si un clock de sincronizare si, din acest motiv, sunt necesare urmatoarele masuri pentru sincronizarea emitatorului cu receptorului: a. Emitatorul si receptorul trebuie sa convina asupra unei “viteze de transmisie”

– cu alte cuvinte frecventa ceasurilor TXCLK si RXCLK trebuie sa fie aceeasi.

Page 28: Introducere in Programarea Microcontrollerelor

b. Fiecare octet de date trebuie precedat de un “bit de start”, cau polaritate inversa fata de starea de repaus a liniei de comunicatie (de obicei starea de repaus a liniei este 1 logic, astfel incat bitul de start are valoarea logica zero)

c. Dupa fiecare octet e transmite cel putin un “bit de stop” pe durata caruia linia are polaritatea starii de repaus (1 logic).

Cu aceste conventii, octetul 0x31 (codul ASCII al cifre 1) se transmite astfel:

Start Stop

Tb/2 Tb Tb Tb Tb Tb Tb Tb Tb Tb

1 0 0 0 1 1 0 0

Fig. 2 Forma de unda a semnalului pentru transmisia asincrona a octetului 0x31 Observati ca octetii se transmit serial incapand cu bitul cel mai putin semnificativ. Schema bloc a USART este prezentata in figura 3

BAUD rate generator

Tx shift register

Control logic

Internal bus

Rx shift register

Control Tx Data Rx Data Status

CLK

TxD RxD

Fig. 3 Schema bloc generala a unui USART Microcontrollerele din seria AVR sunt echipate cu unul sau (uneori) doua USART-uri. ATmega16 are un usart. Registrele de date ale transmitatorului si receptorului sunt “vizibile” pentru program la aceeasi adresa, denumite simbolic UDR (Usart Data Register), cu precizarea ca la scriere in UDR se scrie in registrul de date al transmitatorului iar la citire se citeste din registrul de date al receptorului. Registrul de control si cel de stare sunt comasate in registrele de control si stare UCSRA, UCSRB, si UCSRC. UCSRA are structura:

Page 29: Introducere in Programarea Microcontrollerelor

Fig. 4 Registrul de control si stare UCSRA Semnificatia bitilor: RXC- RX Complete – receptie completa TXC Tx Complete – transmisie completa UDRE – Usart Data Register Empty – setat pe 1 cand registrul de date al transmitatorului este gol (se pot accepta scrieri) FE, DOR, PE sunt biti de eroare (Framing error, Overrun error, si parity error) U2X – bit de control Cand e setat dubleaza viteza de comunicatie asincrona. MPCM – Multi Processor Communication Mode. Comanda intrarea intr-un regim de functionare multiprocesor, care nu ne intereseaza acum. UCSRB contine biti de control pentru activarea/dezactivarea separata a transmitatorului si receptorului si pentru validarea generarii de intreruperi, iar UCSRC contine biti de control pentru selectia modului de functionare (sincron/asincron) si pentru activarea/dezactivarea controlului de paritate, pentru selectia numarului de biti per caracter etc. III.2. Programarea interfetei seriale asincrone la AVR Programarea interfetei seriale consta in: a. Initializarea interfetei, prin activarea emitatorului si receptorului, selectia

vitezei de comunicatie, a numarului de biti per caracter, si activarea (daca e cazul) intreruperilor asociate cu interfata.

b. Programarea emisiei si receptiei la nivel de caracter. O metoda buna de a programa emisia si receptia caracterelor este de a activa intreruperile de receptie si de a testa bitul de stare UDRE (Data register empty) la emisia unui caracter, Iata un exemplu de functie care emite un caracter pe linia seriala: #define UDRE 5 void send_char(char ch) { UDR = ch; while ( !( UCSRA & (1<<UDRE)) ); }

Se observa ca emisia efectiva a caracterului incepe odata cu scrierea in registrul UDR. Apoi se asteapta momentul cand bitul de stare UDRE (bitul 5) din registrul UCSRA devine 1, moment in care transmisia este incheiata. Se mai poate scrie si asa:

Page 30: Introducere in Programarea Microcontrollerelor

#define TXC 6 void send_char(unsigned char ch) { UDR = ch; while ( ( UCSRA & (1<<TXC))==0 ); UCSRA=(1<<TXC); } De aceasta data se testeaza bitul de stare TXC (Tx Complete - bitul 6 din UCSRA). Diferenta este ca bitul TXC nu se sterge automat si trebuie sters prin program scriind 1 in pozitia 6 din UCSRA!! Un exemplu de rutina de intrerupere la receptia unui caracter de la USART este urmatorul: // USART Receiver interrupt service routine interrupt [USART_RXC] void usart_rx_isr(void) { char status, data; status=UCSRA; data= UDR; rxdata=data; rflg=1; }

Se observa ca rutina de intrerupere face urmatoarele operatii: a. Seteaza flagul rflg=1 pentru a indica programului principal ca s-a primit un

caracter pe linia seriala b. Salveaza caracterul primit in variabila rxdata c. Salveaza registrul de stare UCSRA (inclusiv bitii de eroare) in variabila status III.3 Exemple de aplicatii simple de folosire a intefetei seriale III.3.1. Exemplul nr. 1 Sa se scrie un program care face primeste pe linia seriala caracterele emise de un terminal ASCII. Face ecou la toate caracterele, dar schimba case de la literele mici la literele mari. Se parcurg urmatorii pasi: a. Se creaza un nou proiect folosind CodeWizardAVR. Sa zicem ca il denumim

serial1. b. Se selecteaza tab-ul “USART”. se obtine urmatoarea fereastra de dialog:

Page 31: Introducere in Programarea Microcontrollerelor

Fig. 5 Dialogul in cazul initializarii USART-ului la ATMEGA16 Se bifeaza check-box-urile Receiver si Transmitter pentru validarea lor. Se obtine urmatoarea fereastra:

Fig. 6 Dialogul pentru initializarea USART-ului Restul perifericelor se lasa la initializarile default.

Page 32: Introducere in Programarea Microcontrollerelor

c. Se editeaza codul generat pentru a obtine urmatoarele fisiere-sursa: - Un fisier distinct USART.C cu urmatorul continut: #include <mega16.h> #define RXB8 1 #define TXB8 0 #define UPE 2 #define OVR 3 #define FE 4 #define UDRE 5 #define RXC 7 #define FRAMING_ERROR (1<<FE) #define PARITY_ERROR (1<<UPE) #define DATA_OVERRUN (1<<OVR) #define DATA_REGISTER_EMPTY (1<<UDRE) #define RX_COMPLETE (1<<RXC) bit rflg; unsigned char rxdata; void send_char(char ch); void init_usart(void); // USART Receiver interrupt service routine interrupt [USART_RXC] void usart_rx_isr(void) { char status,data; status=UCSRA; data=UDR; rflg=1; rxdata=data; } void send_char(char ch) { UDR = ch; while ( !( UCSRA & (1<<UDRE)) ); } void init_usart(void) { // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Par ity // USART Receiver: On // USART Transmitter: On // USART Mode: Asynchronous // USART Baud Rate: 9600 UCSRA=0x00; UCSRB=0x98;

Page 33: Introducere in Programarea Microcontrollerelor

UCSRC=0x86; UBRRH=0x00; UBRRL=0x67; }

Si programul principal serial1.c cu urmatorul continut: #include <mega16.h> extern unsigned char rxdata; extern bit rflg; extern void send_char(char ch); extern void init_usart(void); void init(void); unsigned char change_case(unsigned char ch); void main(void) { init(); init_usart(); // Global enable interrupts #asm("sei") while (1) { if(rflg==1) { rflg=0; rxdata=change_case(rxdata); send_char(rxdata); } }; } /* Caracterele ASCII pentru litere mici sunt in plaja 0x61 ("a") pana la 0x7A ("z") Caracterele coresunzatoare literelor mari sunt in p laja 0x41 ("A") pana la 0x5A ("Z"). Conversia consta in stergerea bitului 5 (0x20) */ unsigned char change_case(unsigned char ch) { // verificam daca parametrul corespunde unei li tere mici if((ch<0x61)||(ch>0x7A)) return(ch); else { ch=ch&0xDF; return(ch);

Page 34: Introducere in Programarea Microcontrollerelor

} }

Nota: Tabelul urmator contine toate codurile ASCII:

Tabelul 1. Codurile ASCII

0 1 2 3 4 5 6 7 8 9 A B C D E F 0 NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI 1 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US 2 SP ! " # $ % & ' ( ) * + , - . / 3 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 4 @ A B C D E F G H I J K L M N O 5 P Q R S T U V W X Y Z [ \ ] ^ _ 6 ` a b c d e f g h i j k l m n o 7 p q r s t u v w x y z { | } ~ DEL

III.3.2 Exemplul nr. 2 Sa se scrie un program care activeaza releul conectat pe PORTB.0 cand pe linia seriala se primeste ASCII ‘1’ si il dezactiveaza cand se primeste ASCII ‘0’. Se face ecou la toate caracterele primite, pentru control. Se cfolosesc procedurile de copiere a unui proiect cu alt nume descrise in cap[itolul II. Se modifica modulul principal in urmatoarele aspecte: a. Se schimba initializarea portului B in asa fel incat PORTB.0 sa fie configurat

ca linie de iesire b. Se modifica bucla infinita din functia main() in felul urmator: while (1) { if(rflg==1) { rflg=0; send_char(rxdata); if(rxdata==0x31) PORTB.0=1; if(rxdata==0x30) PORTB.0=0; } };

Page 35: Introducere in Programarea Microcontrollerelor

Introducere in programarea microcontrollerelor din seria Atmel AVR Partea a IV-a IV. Exemple de utilizare a convertorului A/D intern IV.1. Generalitati despre convertorul A/D In esenta, orice microcontroller este o masina digitala, capabila sa prelucreze marimi reprezentate in sistemul binar. Pentru a opera cu semnale analogice, este necesara o interfata speciala, denumita convertor analog-digital, care esantioneaza semnalul analogic la momente discrete de timp, si evalueaza amplitudinea acestuia (vezi figura 1).

f(t)

S1

S2

S3

S4

T1 T2 T3 T4

t

Fig. 1 Esantionarea unui semnal analogic Convertorul A/D masoara si reprezinta numeric valorile S1, S2, S3 ... ale esantioanelor semnalului analogic, la momente discrete de timp T1, T2, T3... Schema bloc a unui convertor A/D este prezentata in figura 2.

Vref

DAC SAR & control

logic

S/HMUX

ADC CONTROL ADC STATUS ADC DATA

Internal bus

Analog

input

ADCLK

_

+

Fig. 2 Schema bloc a unui convertor A/D tipic Principalele caracteristici ale unui convertor A/D sunt descrise de “rezolutia convertorului” – definita ca numarul de biti ai rezultatului conversiei si “timpul de

Page 36: Introducere in Programarea Microcontrollerelor

conversie” – definit ca intervalul intre momentul cand se genereaza o comanda de conversie si momentul in care rezultatul este disponibil. Din punct de vedere al programarii, convertorul A/D este conectat la unitatea centrala a micorcontrollerului prin intermediul unui registru de control si stari, care contine biti de comanda pentru activarea blocului de conversie, selectia intrarii analogice multiplexate, selectia ceasului de lucru, comanda de start conversie si bitul de stare care indica sfarsit de conversie si a unui registru de date care va contine rezultatul conversiei. IV.2 Exercitii de programare a convertorului A/D 1. Sa se scrie un program care citeste periodic, la intervale de o secunda, linia

analogica 0 si transmite rezultatul pe interfata seriala, sub forma a doua caractere ASCII.

Solutie: a. Folosind CodeWizard se genereaza un nou proiect si se salveaza intr-un

folder distinct sub numele analog1 b. Se copiaza fisierele usart.c si timer1.c din exemplele descrise in capitolele

anterioare. c. Se foloseste optiunea Tools -> CodeWizard -> Program preview pentru a

initializa convertorul A/D . Se copiaza si se salveaza sectiunea de initializare a convertorului A/D intr-un fisier distinct ADC.C

Acesta va avea urmatorul continut: #include <mega16.h> #include <delay.h> #define ADC_VREF_TYPE 0x60 void init_adc(void) { // ADC initialization // ADC Clock frequency: 1000.000 kHz // ADC Voltage Reference: AVCC pin // Only the 8 most significant bits of // the AD conversion result are used ADMUX=ADC_VREF_TYPE & 0xff; ADCSRA=0x84; } // Read the 8 most significant bits // of the AD conversion result unsigned char read_adc(unsigned char adc_input) { ADMUX=adc_input | (ADC_VREF_TYPE & 0xff); // Delay needed for the stabilization of the ADC in put voltage delay_us(10); // Start the AD conversion ADCSRA|=0x40; // Wait for the AD conversion to complete

Page 37: Introducere in Programarea Microcontrollerelor

while ((ADCSRA & 0x10)==0); ADCSRA|=0x10; return ADCH; }

d. Se editeaza modulul principal (analog1.c) ca sa aiba urmatorul continut: /************************************************** *** Un exemplu de folosire a convertorului A/D Programul citeste linia analogica 0 si transmite rezultatul pe linia seriala sub forma a doua caract ere ASCII *************************************************** **/ #include <mega16.h> extern void init_usart(void); extern void init_timer1(void); extern void init_adc(void); extern void soft_timers(void); extern void send_char(char ch); extern unsigned char read_adc(unsigned char adc_inp ut); extern unsigned char TTAB[8]; unsigned char hinib, lonib; void init(void); void casc(unsigned char ch); void main(void) { unsigned char adc_value; init(); init_usart(); init_timer1(); init_adc(); TTAB[1]=100; // Global enable interrupts #asm("sei") while (1) { soft_timers(); if(TTAB[0]==0) { TTAB[0]=100; adc_value=read_adc(0); casc(adc_value); send_char(hinib); send_char(lonib); send_char(0x20); // emite un spatiu

Page 38: Introducere in Programarea Microcontrollerelor

} }; } // casc - converteste un octet binar la doua carac tere ascii hiniob, lonib void casc(unsigned char ch) { hinib=(ch&0xf0)>>4; lonib=ch&0x0f; if(hinib>9) hinib=hinib+'7'; else hinib=hinib+'0'; if(lonib>9) lonib=lonib+'7'; else lonib=lonib+'0'; } void init(void) { // Input/Output Ports initialization // Port A initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Fun c2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T Sta te2=T State1=T State0=T PORTA=0x00; DDRA=0x00; // Port B initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Fun c2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T Sta te2=T State1=T State0=T PORTB=0x00; DDRB=0x0F; // Port C initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Fun c2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T Sta te2=T State1=T State0=T PORTC=0x00; DDRC=0x00; // Port D initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Fun c2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T Sta te2=T State1=T State0=T PORTD=0x00; DDRD=0x00; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: Timer 0 Stopped // Mode: Normal top=FFh

Page 39: Introducere in Programarea Microcontrollerelor

// OC0 output: Disconnected TCCR0=0x00; TCNT0=0x00; OCR0=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization // INT0: Off // INT1: Off // INT2: Off MCUCR=0x00; MCUCSR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x10; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; SFIOR=0x00; }

Observatii: Se observa ca rezultatul binar al conversiei obtinut in variabila adc_value, actualizata prin apelarea functiei read_adc(numar_canal) este un octet binar. Daca emitem pe linia seriala acest octet, terminalul il va afisa intr-un mod neinteligibil. Din acest motiv este necesar ca inainte de a emite octetul citit de la ADC, sa-l convertim la doua caractere ASCII, corespunzator reprezentarii hexazecimale a numarului. Exemplu Sa presupunem ca octetul citit de la ADC are valoarea binara 0011 1010 (0x3A). Daca emitem direct pe linia seriala acest octet, terminalul va interpreta valoarea primita ca un digit ASCII si va afisa ‘:’. Rutina de conversie casc(unsigned char ch) foloseste doua variabile globale hinib si lonib pentru a stoca rezultatul conversiei. void casc(unsigned char ch) { hinib=(ch&0xf0)>>4; lonib=ch&0x0f; if(hinib>9) hinib=hinib+'7';

Page 40: Introducere in Programarea Microcontrollerelor

else hinib=hinib+'0'; if(lonib>9) lonib=lonib+'7'; else lonib=lonib+'0'; }

Observam ca, pentru inceput, casc izoleaza cei doi semiocteti ai parametrului in variabilele hinib si lonib: hinib=(ch&0xf0)>>4; lonib=ch&0x0f;

In acest moment, hinib=0x03 si lonib=0x0A. In continuare, observam ca reprezentarea ASCII a numerelor de la 0 la 9 este 0x30-0x39, ceea ce inseamna ca pentru a converti un numar situat in plaja [0-9] la ASCII este suficient sa adunam constanta 0x30 – care este codul SCII pentru ‘0’. In mod similar pentru a obtine codurile ASCII corespunzatoare numerelor hexazecimale [A-F] este suficient sa adunam constanta 0x37 (echivalent cu ASCII ‘7’). if(hinib>9) hinib=hinib+'7'; else hinib=hinib+'0'; if(lonib>9) lonib=lonib+'7'; else lonib=lonib+'0';

In final, hinib=0x33 si lonib=0x41 (0x0A+0x37=0x41). 2. Adaugati la exercititiul precedent urmatoarea functie: - Sa se activeze releul conectat la PORTB.0 cand se depaseste un prag

PRAG_SUS si releul conectat la PORTB.1 cand valoarea semnalului scade sub PRAG_JOS.

Solutie: Se modifica doar modulul main in felul urmator: while (1) { soft_timers(); adc_value=read_adc(0); if(TTAB[0]==0) { TTAB[0]=100; casc(adc_value); send_char(hinib); send_char(lonib); send_char(0x20); // emite un spatiu } if(adc_value>=PRAG_SUS) PORTB.0=1; else PORTB.0=0; if(adc_value<=PRAG_JOS) PORTB.1=1; else PORTB.1=0; }; }

Page 41: Introducere in Programarea Microcontrollerelor

3. Sa se scrie un program care activeaza si dezactiveaza alternativ releul

conectat la PORTB.0 pentru o durata controlata printr-un potentiometru conectat la intrarea analogica 0.

Solutie: Se modifica functia main() dupa cum urmeaza: while (1) { soft_timers(); if(TTAB[0]==0) { adc_value=read_adc(0); TTAB[0]=~adc_value; PORTB.0=!PORTB.0; casc(adc_value); send_char(hinib); send_char(lonib); send_char(0x20); // emite un spatiu } }; }

Introducere in programarea microcontrollerelor din seria Atmel AVR Partea a V-a V. Notiuni de baza despre PWM V.1 Definitie. Principiul de functionare al generatoarelor PWM PWM este un acronim de la Pulse Width Modulator – Modulator de impulsuri in durata, mai precis e vorba de un generator de semnale dreptunghiulare cu frecventa fixa, dar cu factor de umplere modificat dinamic.

T

PWMOUT

Fig. 1 Forma de unda a unui semnal PWM Un astfel de semnal poate fi generat cu o schema ca in figura 2.

Page 42: Introducere in Programarea Microcontrollerelor

PrescallerClock

Counter

Carry

Comparator

Compareregister

Flipflop

S

R QPWM

Fig. 2 Schema logica a unui circuit generator PWM Circuitul consta intr-un numarator, care numara permanent pe un ceas obtinut prin divizarea programabila cu ajutorul unui prescaller a ceasului principal. Continutul numaratorului este comparat de un comparator digital cu valoarea continuta de un registru programabil (compare register) si la coincidenta se seteaza un bistabil R-S. Stergerea bistabilului se face in momentul cand numaratorul ajunge la overflow. Functionarea schemei din figura 2 este ilustrata in figura 3.

PWMOUT

T ime

T ime

TOP

COMPARE

Fig. 3 Principiul de functionare a unui generator PWM Se observa ca frecventa semnalului PWM este constanta, data de frecventa ceasului principal si de constantele de divizare ale prescallerului si ale numaratorului PWM. Factorul de umplere al semnalului este insa dependent de valoarea regsitrului de comparatie (compare register). Aceasta particularitate face ca sistemul de timere al microcontrollerelor sa poata fi usor fi folosit si ca generator PWM.

Page 43: Introducere in Programarea Microcontrollerelor

In cazul microcontrollerelor din seria AVR, toate timerele principale pot fi folosite si ca generatoare PWM. ATMega16, are 3 timere , iar timer1 are asociate doua registre output compare, deci in total se pot genera 4 semnale PWM simultan. Principala utilitate a semnalelor PWM deriva din faptul ca prin filtrarea trece-jos a unui semnal PWM se obtine un semnal proportional cu factorul de umplere al semnalului PWM, ceea ce este echivalent cu o demodulare. In acest mod, subsistemul PWM al unui microcontroller este echivalent cu un convertor Digital-Analog. V.2 Exemple de programare a timerelor in mod PWM la AVR 1. Folosind timer1 al ATMega16 sa se genereze la iesirile OC1A si OC1B (pinii

18 si 19 ai microcontrollerului) doua ceasuri, unul cu factor de umplere ½ iar celalat cu factor de umplere ¼.

Solutie Folosind CodeWizardAVR, se selecteaza initializarile pentru timer1 ca in figura 4. Apoi se editeaza programul generat pentru a configura iesirile PORTD corespunzatoare pinilor OC1A si OC1B ca iesiri si se aleg valorile de initializare pentru OCR1AL si OCR1BL la jumatate, respectiv un sfert din 255. (0x80 si 0x40). Programul principal se reduce la o bucla infinita de asteptare – totul se reduce la aceste initializari. Odata initializat subsistemul timer PWM functioneaza independent de programul principal.

Fig. 4 Initializarile cerute de exercitiul 1

Page 44: Introducere in Programarea Microcontrollerelor

2. Folosind iesirea PWM OC1B asociata cu timer1 sa se genereze un semnal

care, dupa filtrarea trece-jos, sa aproximeze un semnal liniar variabil. Solutie: Se initializeaza timer1 in mod similar cu initializarea din exercitiul porecedent. In bucla infinita din functia main se scrie urmatorul cod: while (1) { for (i=0;i<10;i++) { OCR1BL=PWMTAB[i]; delay_ms(1); } };

Unde variabila PWMTAB a fost definita ca: unsigned char PWMTAB[10]={10,30,50,70,90,110,130,15 0,170,190};

3. Sa se scrie un program care modifica factorul de umplere al unui ceas

generat la iesirea OC1B in functie de valoarea masurata pe intrarea analogica 0.

Introducere in programarea microcontrollerelor din seria Atmel AVR Partea a VI-a VI. Programarea interfetei SPI VI.1 Definitie. Principiul de functionare SPI este un acronim pentru Synchronous Peripheral Interface – interfata de comunicatie sincrona cu perifericele. Principiul de functionare al SPI se bazeaza pe modul de functionare al registrelor de deplasare. In figura 1, sunt prezentate doua registre de deplasare concatenate si controlate de acelasi ceas de sincronizare. In aceasta structura, continutul registrului A este transferat bit cu bit (serial) in registrul B, sincron cu ceasul exterior, aplicat ambelor registre.

Page 45: Introducere in Programarea Microcontrollerelor

SERIN SERINSEROUT SEROUT

CLK CLK

Data In

Clock

A B

Fig. 1 Un exemplu elementar de comunicatie sincrona cu registre de deplasare Intr-o astfel de structura, dispozitivul care genereaza clock-ul de sincronizare, controleaza integral momentul cand are loc transmisia, precum si viteza de comunicatie si, din acest motiv este denumit MASTER, iar dispozitivul pasiv este numit SLAVE. In practica, pentru a asigura comunicatia bidirectionala intre MASTER si SLAVE, se folosesc circuite care contin patru registre de deplasare, conectate ca in figura 2.

Rx Data Register Tx Data Register

SCK

Tx Data Register Rx Data Register

MISO

SCK

MOSI

SSMaster Slave Fig. 2 Schema bloc a unei conexiuni SPI bidirectionale Se observa ca toate cele patru registre sunt controlate de acelasi clock SCK, generat de dispozitivul MASTER. Liniile de date se numesc MOSI (Master Out Slave In – iesirea de date a dispozitivului MASTER) si MISO (Master In Slave Out – intrarea de date pentru MASTER) Suplimentar fata de aceste semnale, dispozitivul MASTER genereaza inca un semnal de control, denumit SS (SLAVE SELECT), activ de obicei pe zero. In acest mod se pot realiza retele cu un MASTER si mai multe dispozitive SLAVE., fiecare SLAVE avand un semnal distinct de selectie. La un moment dat, numai unitatea SLAVE care primeste semnal de selectie participa la transferul de date. O consecinta evidenta si importanta a faptului ca toate registrele implicate intr-o conexiune SPI sunt controlate de acelasi ceas, este faptul ca transmisia si receptia datelor au loc simultan, cu alte cuvinte, comunicatia SPI este in mod inerent full-duplex.

Page 46: Introducere in Programarea Microcontrollerelor

VI.2 Structura interfetei SPI care echipeaza microcontrollerele Majoritatea microcontrollerelor moderne sunt echipate cu un subsistem SPI, cu structura descrisa in figura 3.

SCK

MOSI

CLK

MISOTx shift register Rx shift register

Control logic

Control

register

Status

registerData

register

Interrupt

request

Internal bus Fig. 3 Schema bloc a interfetei SPI a unui microcontroller Microcontrollerele din seria Atmel AVR, au urmatoarele registre in structura subsistemului SPI: a. Registrul de date al interfetei, denumit SPDR (SPI Data Register) La nivelul

MASTER, o scriere in acest registru initiaza imediat procesul de transfer serial al datelor, prin generarea a 8 impulsuri de ceas. La sfarsitul transferului, SPDR al MASTER contine datele receptionate de la SLAVE.

b. Registrul de stare SPSR (SPI Status Register), contine doi biti de stare, si anume: SPIF (SPI transfer complete Flag) care indica incheierea transferului si WCOL – Write Collision, un bit de eroare, setat atunci cand se incearca o scriere soft in registrul SPDR pe durata cat exista un transfer in curs.

c. Registrul de control SPCR (SPI Control Register) – contine biti de control cu urmatoarele functii:

- selectia vitezei de transfer (frecventa ceasului) - polaritatea clock-ului generat - ordinea de transfer a bitilor (incepand cu MSB sau cu LSB) - selectia regimului de functionare (ca MASTER sau SLAVE) - activarea generala a interfetei - activarea optionala a emisiei unei cereri de intrerupere la sfarsitul unui

transfer SPI. VI.3 Aplicatii ale interfetei SPI a. Conectarea a doua sau mai multe microcontrollere in sisteme multiprocesor.

In acest mod se pot realiza viteze de transfer relativ mari (4Mb/s). b. Conectarea unor memorii sau dispozitive periferice (display-uri, tastaturi etc.)

la un microcontroller. Acest sistem are avantajul ca implica putini pini ai microcontrollerului.

Page 47: Introducere in Programarea Microcontrollerelor

VI.4 Programarea interfetei SPI Programarea interfetei SPI vizeaza urmatoarele aspecte: a. Initializarea interfetei – proces care are ca obiectiv selectia regimului de

functionare (MASTER sau SLAVE), activarea generala a interfetei, selectia frecventei si a polaritatii ceasului, si – eventual – activarea intreruperii de sfarsit de transfer. Este de asemenea necesara configurarea liniilor I/O asignate pentru MOSI si SCK, ca linii de iesire iar a liniei MISO ca linie de intrare.

b. Scrierea functiei de emisie/receptie (reamintim ca procesul de emisie si cel de receptie au loc simultan)

O rutina tipica de emisie/receptie SPI este urmatoarea (ATMega16, MASTER): unsigned char spi_send(unsigned char ch) { PORTB.4=0; // genereaza semnalul SS=0 delay_us(10); // intarziere necesara pen tru periferice lente SPDR=ch; // inceputul transmisiei while(!(SPSR&0x80)); // asteptarea incheierii t ransmisiei PORTB.4=1; // Deselecteaza SLAVE return(SPDR); // intoarce caracterul rec eptionat de la SLAVE }

Exemplu Sa se scrie un program care sa configureze microcontrollerul ATMega16 ca SPI MASTER si sa comande aprinderea unor LED-uri conectate la un circuit MC14489. Solutie Circuitul MC14489 poate comanda direct 24 de LED-uri, sau 5 digiti de afisare cu 7 segmente. Datele care se afiseaza se primesc pe o interfata SPI. Evident, circuitul se comporta ca un SPI SLAVE. Formatul datelor transmise catre MC14489 este urmatorul: a. Dispozitivul MASTER trimite 4 octeti, dintre care primul octet este un cuvand

de configurare. Pentru a accesa individual cel 24 de LED-uri acest cuvant are valoarea 0x3F.

b. In continuare, se trannsmit 3 octeti de date, corespunzator celor 24 de LED-uri pe care le poate controla circuitul.

Toti cei patru octeti se transmit cu bitul cel mai semnificativ primul. Programul de initializare a SPI pentru comanda MC14489 se obtine cu CodeWizardAvr, selectand optiunile din figura 4.

Page 48: Introducere in Programarea Microcontrollerelor

Fig. 4 Dialogul CodeWizardAVR pentru initializarea SPI Se vor configura de asemenea liniile PORTB.4, PORTB.5 si PORTB.7 ca linii de iesire (pentru SS, MOSi si SCK respectiv). Se scrie apoi programul principal ca mai jos: void main(void) { init(); PORTB.4=1; while (1) { send_spi(0x3F); send_spi3(0x81,0x0F,0x55); delay_ms(1000); }; } Iar functiile send_spi() si send_spi3() au urmatorul continut: unsigned char send_spi(unsigned char ch) { PORTB.4=0; delay_us(100); SPDR=ch; while(!(SPSR&0x80)); PORTB.4=1; return(SPDR); } void send_spi3(unsigned char ch1, unsigned char ch2 , unsigned char ch3) { PORTB.4=0; delay_us(10);

Page 49: Introducere in Programarea Microcontrollerelor

SPDR=ch1; while(!(SPSR&0x80)); SPDR=ch2; while(!(SPSR&0x80)); SPDR=ch3; while(!(SPSR&0x80)); PORTB.4=1; }

Nota: Functia send_spi3() a fost necesara pentru ca MC14489 cere ca toate cele 3 caractere care urmeaza dupa caracterul de configurare trebuie transmise fara ca linia SS sa revina in 1. Exercitii 1. Sa se scrie un program care sa afiseze pe LED-urile conectate la un circuit

MC14489 caracterele ASCII primite pe linia seriala asincrona.