- 08 Φεβ 2017, 01:06
#362162
Η καρδιά του Arduino UNO (η πιό συνιθισμένη παραλλαγή Arduino) είναι ο μικροελεγκτής της Atmel, ATMega328p.
Τους μικροελεγκτές γενικά τους ελέγχουμε αλλάζοντας τις δυαδικές τιμές των registers. Οι registers δέν είναι τίποτα άλλο απο μνήμες. Σε αντίθεση με την κανονική μνήμη, οπου μπορούμε να αποθηκεύουμε ότι μας καπνίσει, οι registers έχουν την ιδιαιτερότητα οτι αν τους μεταβάλλουμε τις τιμές, αλλάζει ανάλογα και η συμπεριφορά και λειτουργία του μικροελεγκτή.
Για παράδειγμα, έστω οτι θέλουμε να ρυθμίζουμε το pin 13 του Arduino (το οποίο έχει και ένα led συνδεδεμένο) έτσι ωστε να γίνει έξοδος και να το ρυθμίσουμε ως HIGH ωστε να βγάλει 5 Volt και να ανάψει το led.
Το πρώτο που πρέπει να κάνουμε είναι να βρούμε σε ποιό PORT ανήκει το pin που θέλουμε. Ο μικροελεγκτής είναι 8-bit, οπότε τα pins είναι ομαδοποιημένα σε οκτάδες, PORT A, PORT B, PORT C και PORT D, δέν υπάρχει τρόπος να γίνουν adressed αλλιώς όλα μαζί.
Οπότε βλέπουμε στην εικόνα οτι το pin 13 του Arduino αντιστοιχεί στο PB5 του μικροελεγκτή, ή 5ο πιν στο PORT B.
Οπότε το πρώτο register που θα πειράξουμε είναι το DDRx (Data Direction) οπου χ είναι το ανάλογο PORT. Δηλαδή υπάρχουν 4 registers, DDRA, DDRB, DDRC και DDRD, το καθενα απο τα οποία είναι 8 bit. Η default τιμή τους ή αμέσως μετά απο reset, είναι όλα μηδενικά, δηλαδή είσοδοι. Εμείς θέλουμε να κάνουμε το 5ο pin του PORT B έξοδο και θα του δώσουμε την τιμή 1.
Οπότε η εντολή στη C είναι
Δηλαδή ενώ το DDRB αρχικά είναι 00000000, του δίνουμε την τιμή 00100000. Το 0b στην αρχή της τιμής σημαίνει οτι το νούμερο που ακολουθεί είναι δυαδικό (binary).
Εδώ χρειάζεται προσοχή. Τα πάντα στα ψηφιακά κυκλώματα μετρούνται απο το μηδέν, όχι απο το ένα. Επομένως τα πιν σε ένα port πάνε απο 0 εώς 7 και όχι απο 1 εώς 8. Επίσης τα bit σε ένα register μετρούνται απο το LSB (least significant bit) προς το MSB (most significant bit) δηλαδή απο δεξιά προς τα αριστερά.
Έτσι το pin PB5 είναι ουσιαστικά το 6ο και όχι το 5ο. Οπότε βρίσκουμε το 6ο bit απο δεξια προς τα αριστερά και το κάνουμε 1.
Η παραπάνω εντολή θα μπορούσε να γραφτεί και έτσι:
Το 0x σημαίνει οτι η τιμή που ακολουθεί είναι δεκαεξαδική, και το δυαδικό 100000 είναι ίσο με 20 στο δεξαεξαδικό.
Το πρόβλημα εδώ είναι οτι αναγκαστικά πρέπει να δώσουμε τιμές σε όλα τα bit. Οπότε βάλαμε άσσο στο 6ο bit και μηδενίσαμε όλα τα υπόλοιπα. Όμως τί γίνεται αν τα υπόλοιπα bit έχουν κάποια τιμή απο πρίν, οπότε δέν πρέπει να τα πειράξουμε?
Εδώ βοηθούν τα λεγόμενα bitwise operations.
Οπότε η εντολή γίνεται:
Το παραπάνω σημαίνει οτι παίρνουμε ότι τιμή είχε πρίν το register DDRB και το κάνουμε bitwise OR με την τιμή 00100000. Η τιμή αυτή είναι η "μάσκα". Όπου έχει 0 τότε αφήνεται απείραχτο το αντίστοιχο bit του DDRB, ενώ όπου η μάσκα έχει 1 τότε το συγκεκριμένο bit γίνεται 1.
Έτσι αν το DDRB είχε αρχικά τιμή 10000100, η τελική τιμή θα γίνει 10100100, δηλαδή θα αλάξουμε το επιθυμητό bit χωρίς να πειράξουμε τα υπόλοιπα.
Αντίστοιχη λογική έχει το subnet mask (πχ 255.255.0.0) στις διευθύνσεις IP. 255 σημαίνει 8 άσσοι στο δυαδικό. Η διαφορά είναι οτι εκεί γίνεται η λογική πράξη bitwise AND.
Εδώ είναι ένα online bitwise calculator:
http://www.miniwebtool.com/bitwise-calculator/Τώρα αφού με τα πολλά ρυθμίσαμε το pin 13 του arduino σαν έξοδο, πρέπει να το ρυθμίσουμε ώς HIGH για να βγάλει τάση και να ανάψει το led.
Το register που ελέγχει αν μια έξξοδος είναι HIGH ή LOW είναι πάλι με την προηγούμενη λογική το PORTx.
Οπότε η εντολή για να ενεργοποιήσουμε το pin 5 του PORT B χωρίς να πειράξουμε τα υπόλοιπα είναι:
Στο datasheet του κάθε μικροελεγκτή περιγράφονται αναλυτικά όλα τα registers, ποιές είναι οι default τιμές τους, η διεύθυνση στην μνήμη του μικροελεγκτη και αν μπορούμε να γράψουμε ή είναι μόνο για διάβασμα: