Laboratorul 0: Aplicații introductive

Capitole utile din Datasheet ATmega324P

  • 1. Pin Configurations - pag. 15
  • 13. I/O-Ports - pag. 95

1. Introducere

1.1. De ce?

I: Ce facem noi aici? Unde se folosește ce învățăm? Chiar e util?

R: Ca să răspundem pe scurt: “multe”, “peste tot” și “da”; ar fi răspunsurile, dar mai bine începem cu un exemplu.

Tocmai ți-ai construit un nou PC și i-ai pus și RGB pe RAM, pe ventilatoare, pe carcasă, o grămadă. Acum vine întrebarea, cine “apasă” butoanele astfel încât culorile să iasă așa cum le pui tu în software? CPU-ul să stea el și să aibă grijă să schimbe culorile? Ar cam fi o irosire de resurse. Aici intervine un microcontroller! E un procesor mai mic, mai simplist, cu un task bine determinat în sistem. Treaba lui în cazul nostru este să controleze RGB-ul întreaga lui viață.

1.2. Ce e un microcontroller (µC)?

TLDR, un calculator într-un cip. Mai în detaliu, el este un circuit integrat ce reunește o unitate de procesare (CPU), memorii (volatile RAM, nevolatile EEPROM, Flash, ROM) și diverse periferice ce îi permite acestuia să comunice cu mediul extern.

1.3. µC in the wild

Le găsim în diferite dispozitive precum: telefoane, electro-casnice, sateliți, avioane, în fabrici etc. Există o gamă largă de microcontrollere disponibile și acestea se aleg în funcție de aplicație, având în vedere mai ales optimizarea costului și a consumului energetic pentru dispozitivul unde µC urmează a fi folosit.

Exemple de proiecte

Exemple de proiecte

 [1] Bird tracking  [2] Bird tracking  [3] Palm size quad-copter [4] Robot line follower (Tare N' Bară) [5] Robot ce joacă fotbal (IronFoot) [6] Robot submarin (R0X1) [7] Self-balancing skateboard

Pentru alte exemple, puteți începe căutarea de aici: https://www.hackster.io/projects/tags/microcontroller

1.4. Ce găsim într-un µC?

  • Unitatea centrală de procesare (µP core) cu o arhitectură care poate fi pe 8, 16, 32 sau 64 de biţi
  • Memorie de date volatilă (RAM) și/sau non-volatilă (Flash sau EEPROM)
  • Memorie de program non-volatilă (Flash sau EEPROM)
  • Porturi digitale de intrare-ieşire de uz general (GPIO - General Purpose Input Output)
  • Interfeţe seriale de comunicație (USART, SPI, I2C, PCM, USB, SDIO etc.)

More

More

  • Interfețe ethernet
  • Interfețe pentru afișaj grafic (LVDS, HDMI sau alte protocoale dedicate controlului afișajelor LCD)
  • Timere (cu rol intern, sau utilizate în generarea semnalelor periodice -ex: PWM-, sau ca watchdog)
  • Convertoare analog-digitale și digital-analogice (ADC, DAC), front-end-uri analogice și alte circuite dedicate semnalelor analogice
  • Sursă de tensiune integrată
  • Interfață pentru programare şi debugging


Perifericele reprezintă orice dispozitiv, intern sau extern, care se conectează la un sistem de calcul și îi extinde funcționalitatea de bază. În cazul microcontroller-ului, există o serie de astfel de periferice incluse direct în circuitul integrat (exemple mai sus). Deși nu seamănă cu perifericele unui PC (monitor, placă grafică, tastatură, mouse etc.), fără ele microcontroller-ul nu ar putea interacționa cu mediul exterior. Mai mult, perifericele ne ajută să conectăm alte elemente mai performante la controller și să îi putem oferi funcționalități similare unui sistem PC (conexiune la internet, linie de date USB, display grafic etc.)

2. Microchip (Atmel) AVR

Pe parcursul semestrului vom lucra cu microcontrollere din familia AVR de la Microchip. Acestea au arhitectură Harvard pe 8 biţi şi set redus de instrucţiuni (RISC).

Vă mai amintiți de banda de asamblare (pipeline)? Haideți să vă dăm un “fun fact”. µC AVR au o unitate de execuţie în bandă de asamblare cu două niveluri, acest lucru permiţând că următoarea instrucţiune să fie adusă din memorie (fetch) în timp ce instrucţiunea curentă este în execuţie. Majoritatea instrucţiunilor se execută într-un singur ciclu de instrucţiune, acest lucru permiţând atingerea unui throughput de 1MIPS pe MHz.

2.1. ATmega324P

 atmega324| Un µC ATmega324 în capsulă PDIP

Este un microcontroller pe 8 biți din familia megaAVR cu care vom lucra pe parcursul semestrului. Registrele şi magistrala internă de date sunt pe 8 biţi.

Specificațiile µC-ului

Specificațiile µC-ului

  • 32 KB Flash (determină dimensiunea maximă a programului care poate fi executat)
  • 1 KB EEPROM
  • 2 KB RAM
  • 20 MHz frecvența maximă de lucru
  • Tensiune de alimentare între 2.7V și 5.5 V
  • 6 canale de PWM
  • 8 canale de ADC, cu rezoluție de 10 biți
  • 4 porturi digitale de I/O , fiecare cu 8 pini, în total 32 de pini de I/O
  • 3 timere (două pe 8 biți și unul pe 16 biți)
  • Interfeţe de comunicație seriale: USART, SPI, TWI
  • Interfaţe de programare ISP și debug JTAG


La acest microcontroller vom învăța să îi configurăm pinii și să interacționam cu mediul exterior din cod. Acesta are 40 de pini (prezentați mai jos), dintre care 5 sunt pentru alimentare sau funcții auxiliare, iar 32 sunt pentru I/O. microcontrollerul are patru porturi: A, B, C și D. Configurarea pinilor pentru ATmega324P

Pentru mai multe detalii, mereu puteți consulta datasheet-ul (documentația tehnică sumarizată) a microcontrollerului. :)

2.2. Placa de laborator

Placa de laborator este bazată pe microcontrolerul ATmega324P și vine cu următoarele caracteristici:

  • LSM9DS0 - Senzor inerțial cu 9 axe (accelerometru, giroscop și magnetometru)
  • MPL3115 - Senzor baro-altimetru
  • Senzori de temperatura și lumină ambientală
  • Display LCD 128×160 ST7735 color cu cititor de card SD
  • RGB LED
  • Display LCD cu 16×02 caractere
  • LEDuri GPIO și butoane
  • Conectori JTAG și ISP
  • Interfață USB programabilă și interfața de date

Placa de laborator reprezintă un circuit care ne pune la dispoziție facil pinii µC-ului de pe ea și care conține circuite de alimentare, de protecție și eventual programatorul µC-ului.

Programatorul este un cip special, chiar un microcontroller uneori, care are rolul sa încarce codul în memoria µC. Nu putem lega µC-ul direct la liniile USB de la un PC, avem nevoie de cineva să “traducă” informația respectivă.

2.3. Pinout-ul plăcii de dezvoltare

LCD Displays

Character LCD GPIO Pin
RS PC0
RW PC1
EN PC2
D4 PC3
D5 PC4
D6 PC5
D7 PC6
Backlight PC7
Graphical LCD GPIO Pin
CS PB0
RST PB1
A0 PB4
SDA PB5
SCK PB7
Backlight PA7

I2C Sensors & Bus Addresses

I2C GPIO Pin Chip Address
I2C Enable PA6 LSM9DS0 0x1D (XM) 0x6B (G)
SCL PC0 MPL3115A2 0x60
SDA PC1

SD Card

GPIO Pin
CS PA2
MOSI PB5
MISO PB6
SCK PB7

RGB LED

GPIO Pin
Red PD5
Green PD7
Blue PB3

Miscellaneous

GPIO Pin
Temperature Sensor PA0
Ambient Light Sensor PA1
Buttons (BTN1 - 6) PA5
BTN 1 PB2
BTN 2 PD6
Speaker PD4

3. Let's get to work

3.1. Actuatori și Traductori (Senzori)

Pentru a putea intefața cu mediul exterior, sunt utilizate diferite componente electronice care au rol fie de actuator (modifică starea mediului exterior) sau de traductor/senzor (sunt influențate de mediul exterior și oferă informații microcontroller-ului despre diverși parametri).

Exemplu actuatori:

  • Ventilatoare;
  • Indicatoare sonore - buzzere;
  • Indicatoare luminoase;
  • Rezistențe de încălzire.

Uneori pentru a putea activa un actuator, este nevoie de un element de acționare. Spre exemplu, dacă am dori să pornim un motor, µC-ul doar dă o comandă logică de start la un tranzistor ce se va deschide și va lăsa un curent mare să treacă prin el (aici prin “curent mare” comparăm față de maximul de câțiva miliamperi pe care îi poate scoate un µC).

Exemplu Senzori:

  • Butoane;
  • Fotorezistori - rezistența lui electrica este influențată de cantitatea de lumină;
  • Termistori - rezistența lui electrica este influențată de temperatură.

În funcție de tipul traductoarelor, acestea pot avea nevoie de prelucrarea semnalului înainte ca acesta să fie preluat de µC (signal conditioning) - de exemplu fotorezistorul trebuie folosit într-un montaj cu divizor de tensiune sau cu sursă de curent -, sau pot fi conectate direct la microcontroller - de exemplu butonul.

3.1.1. LEDs

LED-urile - Light Emitting Diode - numite și diode electroluminesciente - emit lumină când ele sunt polarizate direct. A nu se confunda cu becurile deoarece au metode de funcționare radical diferite.

In depth

In depth

În funcție de semiconductorii care sunt utilizați în construcție, și de plasticul ce are rol de lentilă de dispersie și filtru optic, LED-urile pot emite lumină în diferite culori. Nu confundați LED-urile cu becurile! În timp ce becurile emit lumina prin încalzirea unui filament de tungsten la temperaturi foarte mari, LED-urile emit lumina trecând un curent printr-un material semiconductor (joncțiune p-n). Spre deosebire de becuri, al căror randament este de sub 5% - majoritatea energiei primite de ele se pierde prin efect caloric -, LED-urile au un randament de transformare a energiei electrice în energie luminoasă mult mai mare.


LED-urile pot fi utilizate pe post de indicator luminos (adesea utilizate în diferite aparate pentru a semnaliza faptul că aparatul este pornit și realizează un anumit lucru), sau pentru iluminare, caz în care sunt utilizate LED-uri de putere. În cadrul laboratorului LED-urile sunt utilizate pentru a indica starea unui pin.

Calculul rezistenței de limitare a curentului

LED-urile sunt diode, așadar, curentul prin acestea crește exponențial cu creșterea tensiunii aplicate.

Pentru a utiliza un LED cu scopul de a indica starea unui pin (mai degrabă spus pentru a indica prezența de tensiune), curentul prin LED trebuie limitat. Acest lucru se poate realiza în cel mai simplu mod prin înserierea unei rezistențe cu LED-ul.

Un LED este proiectat să opereze la un curent nominal (ex: 10mA). Căderea de tensiune la acest curent pe LED-urile indicatoare, de mică putere, este dată de chimia LED-ului (aceasta dă și culoarea LED-ului). În cadrul laboratorului, deoarece folosim un LED de un curent atât de mic, putem să îl alimentăm direct de pe pinii logici ai µC-ului.

Schema utilizată este următoarea:

 Schema de lucru și calculul rezistenței de limitare a curentului prin LED

Soluție: Dacă alimentarea microcontroller-ului este de 5V pentru un LED roșu ce dorim să îl folosim la 10mA, specificat de producător cu o cădere de tensiune de 1.7V, trebuie să folosim o rezistență de 330 de ohmi.

3.1.2. Butoane

Cel mai simplu mod de interacțiune al utilizatorului cu un microcontroller îl constituie folosirea butoanelor. Modul de conectare al unui push-button în acest laborator este descris în figura de mai jos:

 Conectarea unui push-button: a) incorect, cu intrare flotantă, b) corect, cu rezistență de pull-up

Conectarea unui push-button: a) incorect, cu intrare flotantă, b) corect, cu rezistență de pull-up

a) Arată un buton conectat la pinul PD0 al µC. La apăsarea butonului, intrarea PD0 va fi legată la GND, deci va fi în starea logică “0”. Acest mod de legare este incorect deoarece atunci când butonul nu este apăsat, intrarea se află într-o stare nedefinită (ca și cum ar fi lăsată în aer), ea nefiind conectată nici la GND, nici la Vcc! Această stare se numește stare de impedanță mărită. În practică, dacă am citi acum valoarea pinului, se va produce un rezultat de 1 sau 0 în funcție de condițiile de mediu. Spre exemplu, dacă apropiem degetul de acea intrare, citirea va fi 1, iar, daca îndepărtăm degetul, citirea va fi 0.

b) Arată modul corect de conectare al butonului, folosind o rezistență de pull-up între pinul de intrare și Vcc. Această rezistență are rolul de a aduce intrarea în starea “1” logic atunci când butonul este liber prin “ridicarea” potențialului liniei la Vcc. Alternativ, se poate folosi o rezistență de pull-down (conectată la GND), caz în care intrarea este ținută in starea logică “0” cât timp butonul nu este apăsat.

La laborator: Pentru a economisi spațiu exterior, în µC-ul ATmega328P, aceste rezistențe au fost incluse în interiorul circuitului integrat. Inițial ele sunt dezactivate iar activarea acestora se poate face prin software.

3.2. Lucrul cu registrele

Acesta poate fi considerat cel mai important pas atunci când dorim să folosim un µC. Trebuie să învățăm cum să configurăm intern µC-ul pentru ca acesta să îndeplinească funcțiile dorite de noi. În acest laborator vom configura pinii pentru a fi de I/O: unii pini să citească dacă se află tensiune pe ei (input) sau alții să dea 0 volți sau 5 volți în funcție de comenzile noastre din software (output).

Pentru a clarifica terminologia: acum când spunem că setăm un registru sau scriem într-un registru, nu ne referim la registrele de uz general din procesor cu care ați lucrat la IOCLA. Ne referim la adrese de memorie rezervate în µC. Vom repeta iarăși împreună: “Prin registru ne referim la o adresă de memorie”. Practic cum merg lucrurile “under the hood”, la acești bytes sunt legături fizice și dacă scriem un bit de 1 sau de 0 în anumite poziții, activăm sau dezactivăm elemente din µC.

Mereu pentru a afla cum să configurați un periferic, datasheet-ul µC-ului este cea mai bună locație să aflați exact fiecare configurare unde se află și ce face. Deoarece nu este deloc plăcut sa scrii în cod *(0x04) = 0b0000 0001, producătorii de µC oferă biblioteci ( avr-libc) pentru a da nume acestor adrese. Următorul cheatsheet vă arată cum sa configurați un anumit bit de la o anumită adresă folosind macrouri (care sunt considerate și best practice).

Pentru a scrie o valoare într-un registru se poate face direct atribuirea unei valori, însă acest mod nu face codul foarte ușor de înteles. Recomandarea noastră este de a folosi măștile pe biți ((1 << x)) sau macro-ul _BV(x). De asemenea recomandăm folosirea numelui pinului în loc de indexul acestuia, pentru că numele acestora sunt sugestive pentru funcția pe care o îndeplinesc (spre exemplu, în registrul ADCSRA al convertorului analog-digital, bitul ADEN este bitul de enable). Numele pinilor, ca și în cazul registrelor, sunt deja definite în avr-libc.

Operație Formă
Scriere bit pe 1
 macro |= (1 << bit_index) 
Scriere bit pe 0
 macro &= ~(1 << bit_index) 
Toggle bit
 macro ^= (1 << bit_index) 
Citire bit
 macro & (1 << bit_index) 

Exemplu: Lucrul cu registre

DDRB = 8;               // AȘA NU.
DDRB = (1 << 3);        // Nici așa, este hardcodat indexul pinului.
DDRB |= (1 << PB3);     // AȘA DA.
DDRB |= _BV(PB3);       // AȘA DA.

Detalii despre lucru cu biții din registre puteți citi și la secțiunea tutoriale de pe wiki.

Nu vă temeți, vom avea destule laboratoare în care să vă obișnuiți cu lucrul cu registre și configurarea µC-ului. Vă încurajăm să depuneți, acum, la început niște efort pentru un drum ușor în acest semestru.

3.3. Registrele de I/O

Pentru acest laborator v-am scutit de căutarea în datasheet, lucru ce poate părea complicat la început și am sintetizat, pentru voi, ce adrese de memorie (registre) trebuie să modificați pentru lucrul în acest laborator.

Microntroller-ul ATmega324 oferă 4 porturi I/O a câte 8 pini, iar intern, fiecare port are asociate trei registre a câte 8 biți prin care utilizatorul poate controla la nivel de pin fluxul datelor: poate scrie/citi date în/din portul respectiv. Aceste trei registre sunt:

  • DDRn - Data Direction Register
    • stabilește direcţia pinilor portului
    • dacă bitul x are valoarea 0 atunci pinul x este de intrare
    • dacă bitul x are valoarea 1 atunci pinul x este de ieșire
  • PORTn - Data Register
    • stabilește valorile de ieşire ale pinilor sau activează/dezactivează rezistenţele de pull-up
    • dacă bitul x are valoarea 0 atunci
      • dacă pinul x este de ieșire el va avea valoarea LOW
      • daca pinul x este de intrare rezistența de pull-up va fi dezactivată
    • data bitul x are valoarea 1 atunci
      • daca pinul x este de ieșire el va avea valoarea HIGH
      • dacă pinul x este de intrare rezistența de pull-up va fi activată
  • PINn - Input Pins Address
    • daca pinul este de input, putem citi date de pe portul respectiv
      • dacă pinul x are valoarea LOW atunci bitul x va avea valoarea 0
      • dacă pinul x are valoarea HIGH atunci bitul x va avea valoarea 1
    • dacă pinul este de output, putem face toggle automat
      • dacă scriem la bitul x valoarea 1, bitul echivalent din PORTn se va nega automat (adică facem toggle la starea pinului automat)

n poate să fie A, B, C sau D în funcţie de portul selectat. x poate să fie între 0 și 7.

Descrierea detaliată a porturilor şi registrelor corespunzătoare acestora se găseşte în datasheet-ul ATmega324, în capitolul I/O Ports.

3.3.1. Exemplu de lucru cu ieșiri

Să presupunem că avem un LED legat la pinul 1 al portului B (numit PORTB1 sau PB1). Pentru a aprinde sau stinge LED-ul trebuie să urmăm următorii pași:

  • Pinul PB1 trebuie configurat ca ieșire
    • Bitul 1 (PB1) din registrul DDRB va fi 1
    • DDRB |= (1 « PB1);
  • Pentru a aprinde LED-ul trebuie ca pinul PB1 să ia valoarea HIGH
    • Bitul 1 (PB1) din registrul PORTB va fi 1
    • PORTB |= (1 « PB1);
  • Pentru a stinge LED-ul trebuie ca pinul PB1 să ia valoarea LOW
    • Bitul 1 (PB1) din registrul PORTB va fi 0
    • PORTB &= ~(1 « PB1);

3.3.2. Exemple de lucru cu intrări

Să presupunem ca avem un buton legat la pinul 4 al portului D (numit PORTD4 sau PD4), din cazul b) prezentat anterior. Pentru a determina starea butonului (apăsat sau liber) trebuie să urmăm următorii pași:

  • Pinul PD4 trebuie configurat ca intrare
    • Bitul 4 (PD4) din registrul DDRD va fi 0
    • DDRD &= ~(1 « PD4);
  • Pentru a determina starea de apăsare a butonului trebuie să citim valoarea pinului la care este atașat. Acesta va fi 1 atunci când butonul este liber și 0 atunci când butonul este apăsat
    • Citim valoarea bitului 4 (PD4) din registrul PIND
    • char val = PIND & (1 « PD4);


4. Dezvoltarea programelor pentru AVR

4.1. Dezvoltare, compilare

Pentru dezvoltarea programelor putem folosi orice editor de text.

În cadrul laboratoarelor vom scrie cod C, nu şi assembly (AVRASM), compilatorul fiind avr-gcc. Acesta poate fi folosit atât pe sisteme Linux/Unix cât şi pe sisteme Windows (WinAVR). WinAVR include şi biblioteca de C, avr-libc, pe sistemele Linux/Unix ea trebuie instalată separat.

Procesul de compilare cu AVR-GCC

Deși microcontroller-ul nostru este pe 8 biți, în codul C putem folosi variabile întregi pe 16/32/64 de biţi şi chiar și în virgulă mobilă. Compilatorul este cel care se va ocupa de translatarea instrucţiunilor în cod asamblare ce lucrează pe 8 biţi.

Utilitare MacOS

Utilitare MacOS

Ca și în cazul sistemelor Linux, pentru a putea programa AVR vom avea nevoie de câteva utilitare: compilatorul avr-gcc, avr-libc și AVRDUDE. Pentru a putea obține aceste utilitare se recomandă folosirea Homebrew utilizând următorul set de comenzi:

brew install avrdude
xcode-select --install
brew tap osx-cross/avr
brew install avr-gcc

Pentru a putea rula pe procesoarele M1/M2/M3 este necesar să instalați minim versiunea 11 a avr-gcc. Mai multe exemple se pot găsi aici

4.2. Programarea microcontroller-ului

Pentru programarea unui microcontroller putem folosi diverse metode, cum ar fi programarea pe interfaţă serială, folosirea unui programator ISP (In-System Programming) ce foloseşte interfaţa serială SPI sau folosirea unui bootloader.

În cadrul acestui laborator vom folosi ultima variantă, deoarece astfel nu avem nevoie de nici-o altă componentă externa pentru a încarca fișierul hex. Un bootloader este un program încărcat (folosind, spre exemplu, un programator ISP) la sfârşitul memoriei de program a microcontroller-ului. Execuţia codului încărcat astfel va începe din zona de boot. Dezavantajul acestei metode este spaţiul ocupat de bootloader în memoria de program.

Execuţia programelor folosind un bootloader

Folosirea bootloader-ului presupune îndeplinirea unei condiții la pornirea microcontroller-ului. Pe plăcile de laborator acesta este rulat la fiecare RESET, însă putem pune orice condiție pe care o poate deduce procesorul (spre exemplu, dacă un buton este apăsat sau nu). Unele microcontrollere au o memorie ROM dedicată bootloader-ului, cu care acestea sunt prevăzute din fabrică (ex: STM32).

Pentru a încărca programul pe controller trebuie să folosim un utilitar de pe calculator. Un exemplu de folosire a utilitarului avrdude pe Linux și pe Windows găsiți mai jos.

$ avrdude -c arduino -P /dev/ttyUSB0 -b 57600 -p atmega324p -U flash:w:lab0.hex:a

C:/> avrdude -c arduino -P COM12 -b 57600 -p atmega324p -U flash:w:lab0.hex:a

4.3. PlatformIO

Pentu o soluție care înglobează tot toolchain-ul și IDE-ul, instalați-vă direct PlatformIO. După instalarea extensiei PlatformIO în VSCode, creați un nou proiect cu target ATmega324P ca platformă/microcontroler și adăugați în platformio.ini linia:

 upload_protocol = urclock 

4.3.1 Alternativă la PlatformIO: instalare separată avr-gcc toolchain

OK, sunteți software developers hardcore și vreți să instalați direct toolchain-ul cu IDE-ul vostru preferat (pe cine păcălesc eu aici, lucrați direct în vim), aveți și opțiunea asta, dar cu câteva dureri de cap incluse. Dacă vreți să vă instalați doar toolchain-ul, fără IDE, aveți nevoie de avr-gcc, make și avrdude pentru a compila și programa placa de laborator. Vă recomandăm următoarele ghiduri de instalare:

Este posibil ca instalarea implicită de avrdude să nu aibă suport pentru bootloader-ul urclock de pe placă și să primiți un mesaj de eroare când apelați make upload. Pentru a remedia problema trebuie să vă instalați avrdude 7.2-arduino.1 (sau să vă instalați direct PlatformIO care vine cu versiunea corectă de avrdude.

De asemenea, vă recomandăm să folosiți un IDE pentru dezvoltarea de cod. Dacă preferați VSCode (fără extensia PlatformIO) există acest tutorial.

Atenție: Suportul pentru programatorul (bootloaderul) urclock (zis și urprotocol) folosit de plăcuțele noastre a fost adăugat abia în avrdude >= 7.1. Asigurați-vă că instalați o versiune recentă (e.g., 7.3)! Notabil, pe Ubuntu 22.04 găsiți doar versiunea 6.3: descărcați versiunea precompilată de pe Github sau folosiți PlatformIO dacă nu întruniți această cerință minimă de versiune! Desigur, dacă descărcați binarul manual, nu uitați să-l faceți executabil și să-l puneți undeva în PATH (e.g. /usr/local/bin/ sau C:\Windows\System32 pe Windows + copiat avrdude.conf manual dacă se plânge că nu există)!

4.4. Hello World

Vom scrie un program care stinge și aprinde un LED la intervale de 500 ms. LED-ul vizat este cel verde de pe placa de laborator. Acest lucru se face modificând tensiunea unuia dintre pinii microcontroller-ului, în cazul nostru pinul 7 din portul D (PD7).

main.c
#include <avr/io.h>
#include <util/delay.h>
 
int main() {
	/* Setăm pinul 7 al portului D ca pin de ieșire. */
	DDRD |= (1 << PD7);
 
	while(1) {
                /* Inversăm starea pinului. */
		PORTD ^= (1 << PD7);
                _delay_ms(500);
	}
 
	return 0;
}

Pentru compilare cu PlatformIO apăsați Ctrl+Alt+B apoi Ctrl+Alt+U pentru upload.

Dacă v-ați instalat toolchain-ul separat, trebuie să apelați la următorul Makefile:

Makefile
# Linux
PORT ?= /dev/ttyUSB0
# Windows
#PORT ?= COM1
 
all: main.hex
 
main.hex: main.elf
	avr-objcopy  -j .text -j .data -O ihex $^ $@
	avr-size main.elf
 
main.elf: main.c
	avr-gcc -mmcu=atmega324p -DF_CPU=12000000 -Os -Wall -o $@ $^
 
upload: main.hex
	avrdude -c urclock -P $(PORT) -b 57600 -p atmega324p -D -xnometadata -U flash:w:$<:a
 
clean:
	rm -rf main.elf main.hex

Compilatorul folosit este avr-gcc. Flag-urile au următoarea semnificație:

  • -mmcu: Informează compilatorul despre tipul microcontroller-ului pentru care trebuie să genereze codul
  • -DF_CPU=12000000: Definește macro-ul F_CPU care indică frecvența de lucru la microcontroller-ului
  • -Os: Optimizează programul în privința memoriei ocupate (destul de folositor având în vedere memoria limitată prezentă pe chip)
  • -Wall: Activează toate mesajele de avertisment

Fișierul care poate fi programat pe placă trebuie să fie în formatul ihex. De aceea este necesară extragerea secțiunilor de date și cod din fișierul elf obținut în urma compilării și integrarea lor într-un fișier ihex. Acest pas folosește utilitarul avr-objcopy.

Comanda avr-size arată câtă memorie ocupă diverse secțiuni de cod ale programului. Trebuie avut în vedere că în memoria SRAM de date, în afară de secțiunea .data, o să fie pusă și stiva. Pentru a putea rula programul pe microcontroller-ul ATmega324 trebuie ca secțiunea .text să fie <32 KB și secțiunea .data să fie <2 KB.

Rezultatul compilării este fișierul main.hex. Acesta urmează a fi încărcat în microcontroller folosind regula upload.

5. Exerciții

Task 0 Începem prin a verifica setup-ul.

  • Instalați IDE-ul dorit/folosit și rulați exemplul Hello Word pe placa de dezvoltare din laborator.

Task 1

  • Modificați exemplul Hello World încât LED-ul aprins să fie cel de culoare roșie. Hint: căutați pinul și portul la care e legat acest LED (parte a LED-ului RGB) în schema plăcii / documentația plăcii pe GitHub. Atenție: LED-ul RGB are anodul comun, așa că scrierea unui 1 logic pe pinul de GPIO corespunzător o să stingă LED-ul.

Task 2

  • Modificați exemplul Hello World încât LED-ul să își schimbe culoarea la apăsarea butonului BTN 1 (PB2).
    • Mențineți LED-ul verde aprins
    • Configurați registrele pentru a face pinul PB2 de input
    • Configurați LED-ul să adauge și altă culoare (roșu/albastru) atunci când butonul este apăsat. (nu uitați să activați rezistența de pull-up internă a µC-ului pentru PB2)

Task 3

  • Plecând de la aplicația rezultată la Task 2, schimbați utilitatea butonului BTN1 pentru a schimba culoarea LED-ului prin apăsare succesivă (prima apăsare - roșu, a doua apăsare - verde, a treia apăsare - albastru șamd.).
  • Cu ajutorul BTN2 stabiliți un comportament de clipire (blink) al LED-ului sau de luminozitate deplină (o apăsare - blink, a doua apăsare - aprins continuu, următoarea apăsare - blink șamd.).

7. Responsabili laborator

pm/lab/lab0-2023.txt · Last modified: 2024/03/03 13:11 by florin.stancu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0