Προγραμματίζοντας το Arduino με τον εύκολο αλλά και τον δύσκολο τρόπο
- Δευτέρα, 26 Σεπτεμβρίου 2016 23:38
Το Arduino αποτελει μία από τις αγαπημένες μου Development Boards και πάνω σε αυτήν έχω βασίσει και τον έλεγχο όλου μου του σπιτιού.
Ο προγραμματισμός του μικροελεγκτή του Arduino μπορεί να γίνει είτε με τον "εύκολο" τρόπο και την χρήση των έτοιμων συναρτήσεων του abstraction layer, είτε με τον δύσκολο και την χρήση καθαρής "C", αλλάζοντας την τιμή διαφόρων Registers.
Ένα από τα πρώτα παραδείγματα που θα τρέξει κάποιος που εισάγεται στον προγραμματισμό μικροελεγκτών αφορά την ενεργοποίηση και απενεργοποίηση ενός κυκλώματος με τον έλεγχο ενός Pin. Συνήθως το κύκλωμα για ευκολία αυτό είναι ένα LED, το οποίο συνδέεται στο Pin 13 της Development Board, το οποίο συνδέεται με το GND μέσω αντίστασης.
Ο ορισμός του Pin 13 ως έξοδο μπορεί να γίνει εύκολα μέσω της συνάρτησης pinMode(), ενώ η ενεργοποίηση και απενεργοποίηση του LED μπορεί να γίνει μέσω της συνάρτησης digitalWrite(), ως εξής:
void setup() { pinMode(13,OUTPUT); } void loop() { digitalWrite(13,HIGH); delay(1000); digitalWrite(13,LOW); delay(1000); }
Ο εν λόγω τρόπος προγραμματισμού προσφέρει ταχύτατο prototyping διαφόρων projects, και είναι ένας βασικός λόγος που έκανε το Arduino να πετύχει: Στην ουσία άνοιξε τον δρόμο για τον προγραμματισμό των μικροελεγκτών στο ευρύ κοινό.
Παρ' όλα αυτά δύναται να προγραμματίσουμε τον μικροελεγκτή ενός Arduino (ενδεικτικά τον ATMega328) χρησιμοποιώντας καθαρή C, χωρίς τις άνωθεν έτοιμες συναρτήσεις.
Στο παρακάτω βίντεο δίνονται επίσης σημαντικά points και επεξηγήσεις και των δύο sketches.
Για να ορίσουμε ένα Pin ως έξοδο χρησιμοποιούμε τους Registers DDRB, DDRC και DDRD. Ο έλεγχος του Pin13 στο οποίο είναι συνδεδεμένο το LED, γίνεται μέσω του Register DDRB. Ο εν λόγω Register είναι 8bit, και κάθε bit του αντιστοιχεί σε ένα εκ των Pins 8-13, (τα bits για το 14 και το 15 αφορούν τον κρύσταλλο και δεν χρησιμοποιούνται). Συγκεκριμένα για να ορίσω το Pin 8 ως έξοδο, θα ορίσω στον DDRB την τιμή σε binary B00000001. Για να ορίσω τα Pins 8 και 9 ως εξόδους θα βάλω στον Register DDRB την τιμή B00000011 κτλ. Συνεπώς για να ορίσω μόνο το Pin13 ως έξοδο, θα κάνω set τον DDRB σε B00100000 (0x20 σε HEX).
Αντίστοιχα γίνεται και η χρήση των Registers PORTB, PORTC και PORTD. Για να αλλάξω την κατάσταση ενός PIN από LOW σε HIGH (λογικό 0 ή 1) θα γράψω στον αντίστοιχο Register. Συνεπώς για να δώσω 5V στο PIN 13 αρκεί να γράψω στον PORTB την τιμή B00100000. Για να σβήσω το LED (να δώσω 0V στο PIN 13), θα γράψω στον PORTB την τιμή B00000000 (0x00 σε HEX).
Σε περίπτωση που δεν θέλουμε να χρησιμοποιήσουμε την συνάρτηση _delay_ms(), η οποία περιέχεται στην βιβλιοθήκη <util/delay.h> μπορούμε να γράψουμε την δική μας συνάρτηση για καθυστέρηση εκτέλεσης του κώδικα. Φυσικά αυτό προϋποθέτει να μην αφήσουμε τον compiler να κάνει optimize το συγκεκριμένο κομμάτι κώδικα.
#include <avr/io.h> int main (void){ //DDRB D8-D13 //DDRC A0-A5 (kai A6 kai A7) //DDRD D0-D7 DDRB |= 0x20; //B00100000; for(;;){ PORTB |=0x20; //B00100000; delaymine(1000000); PORTB &=0x00; //B00000000; delaymine(1000000); } return 0; } void delaymine(long cycles){ for (long i=0;i<=cycles;i++){ __asm__ __volatile__("nop"); } }