This is an old revision of the document!
Ca în toate lucrările de inginerie, bug-uri pot și vor apărea si în sisteme încorporate.
Motivul pentru care depanarea embedded este mai dificilă decât depanarea obișnuită a software-ului provine din mai multe probleme:
Cu toate acestea, principiile de debugging sunt aceleasi ca si în cazul software-ul de nivel înalt: Trebuie sa comparați ce se dorește de la sistem (cod / circuit) cu ceea ce, de fapt, face si, pentru asta, ai nevoie de vizibilitate.
Vizibilitatea la nivel hardware se realizează printr-o formă de InputOutput (dacă este disponibilă):
Instrumente de măsurare:
Un exemplu de flux de depanare ar putea fi următorul:
Interfața serială este cel mai facil mod de a comunica cu microcontroller-ul vostru pentru citirea de date sau trimiterea de comenzi. Din perspectiva microcontroller-ului, comunicația serială se bazează pe doar două linii de date:
Comunicația este full-duplex, se poate transmite concomitent cu recepția.
Transmisia asincronă de date se face la nivel de cadre (frames), fiecare cadru fiind format din mai mulți biți, având formatul descris în figură.
Se transmite un bit de start, apoi un cuvânt de date. Urmează un bit de partitate, opțional, cu rolul de a face o verificare simplă a corectitudinii datelor, și unul sau doi biți de stop.
Microcontroller-ul Atmega328p include un periferic USART (Universal Synchronous-Asynchronous Receiver/Transmitter) pentru interfața serială. În partea de inițializare a acestui periferic trebuie efectuați următorii pași:
RX
și TX
.Ambele părți implicate în comunicație trebuie să aibă aceeași configurație! De exemplu, în terminalul serial folosit pe calculator, trebuie configurat același baud rate și același format al cadrului ca cel din codul de pe microcontroller.
Se gaseste în datasheet la capitolul 19. Registrele au un 'n' la sfârșit care distinge între cele două periferice USART de pe microcontroller-ul nostru. 'n' va lua valoarea 0 pentru USART0, respectiv 1 pentru USART1.
RXB
și TXB
sunt buffer-ele de recepție, respectiv transmisie. Ele folosesc aceeași adresă de I/O. Deci RXB
este accesat citind din UDRn
, TXB
scriind în UDRn
. Buffer-ul de transmisie poate fi scris numai atunci când bitul UDRE
(USART Data Register Empty) din portul UCSRnA
este 1. În caz contrar, scrierile vor fi ignorate.
UCSRnA
este registrul de stare al controller-ului de comunicație. Biții cei mai importanți sunt:
UCSRnB
este un registru de control. Biții importanți:
UCSZ1
și UCSZ0
din portul UCSRC
, selectează dimensiunea unui cuvânt de date
UCSRnC
este tot un registru de control. Biții importanți:
UCSZn2
din portul UCSRnB
, selectează dimensiunea cuvântului de date
UBRRn
este registrul care selectează baud rate-ul. Are 12 biți. Primii 4 se află în UBRRnH
, ceilalți 8 în UBRRnL
. Valoarea pe care o scriem în UBRRn
depinde de frecvența procesorului și de baud rate-ul dorit. În tabelul următor găsiți valorile pentru frecvența de 16 Mhz.
void USART0_init(unsigned int baud) { /* setează baud rate */ UBRR0 = baud; /* UBRR0 este un registru pe 16 biți, la nivel de compilator se vor face doua scrieri de 8 biti */ /* pornește transmițătorul */ UCSR0B = (1<<TXEN0); /* setează formatul frame-ului: 8 biți de date, 2 biți de stop, fără paritate */ UCSR0C = (1<<USBS0)|(3<<UCSZ00); } void USART0_transmit(unsigned char data) { /* așteaptă până când buffer-ul e gol */ while(!(UCSR0A & (1<<UDRE0))); /* pune datele în buffer; transmisia va porni automat în urma scrierii */ UDR0 = data; }
Scrieri pe 16 biți:
(3 << x)
Pentru biți de configurație care se găsesc întotdeauna unul după altul se folosește și o mască cu mai mulți biți shiftați cu index-ul celui mai din dreapta: (3 << UCSZ00)
înlocuiește astfel (1 << UCSZ01) | (1 << UCSZ00)
(1 << x) | (1 << y)
De cele mai multe ori o să facem măști compuse, pe care le vom aplica unui registru I/O în același timp.
Atenție! Pot doar să compun măști pentru aceeași operație, nu pot aplica o mască SAU în același timp cu o mască ȘI pentru că rezultatul ar fi complet eronat!
Arduino UNO se conecteaza la PC prin intermediul interfetei seriale, dar utilizeaza un convertor serial-to-USB integrat pe placa. Prin intermediul acestei interfete si utilizand IDE-ul dedicat Arduino se poate programa microprocesorul, dar se poate asigura si un canal de debug. Astfel, prin mesaje simple, se poate afla starea sistemului, se pot afisa valorile variabilelor, sau chiar se pot trimite comenzi, interfata functionand bidirectional. Mai multe detalii se pot gasi aici
Următorul program poate trimite mesaje de la Arduino către PC, prin USB (sau folosind emulatorul din Tinkercad)
void setup() { Serial.begin(9600); Serial.println("in function setup"); } void loop() { Serial.println("in function loop"); delay(1000); }
Următorul program poate primi mesaje trimise de PC, prin USB (sau folosind emulatorul din Tinkercad)
void setup() { Serial.begin(9600); Serial.println("astept comenzi"); } void loop() { if (Serial.available()){ char a = Serial.read(); char buf[20]; sprintf(buf, "%s: %c", "primit caracter", a); Serial.println(buf); } }
Task 0 Incercati voltmetrul
Task 1 Faceti un Arduino Uno sa seteze 1 si 0 pe un pin (echivalent cu blink la un led) si conectati voltmetrul.
Task 2 Studiati functia analogWrite
. Determinati de ce nu functioneaza schema de mai sus cu codul urmator:
void setup() { pinMode(12, OUTPUT); } void loop() { analogWrite(12, 200); }
Modificați codul astfel încât să obtineti o valoare de 2V la bornele voltmetrului.
Task 3 Folosind interfața serială, trimiteti următoarele comenzi catre placuta