ΑΣΚΗΣΗ 2 (29 Νοεμβρίου 2016) Περιγραφή της Άσκησης Στόχος της άσκησης είναι η δημιουργία ενός συστήματος διαχείρισης φωτισμού. Μία φωτομεταβαλλόμενη αντίσταση (LDR) θα διαπιστώνει την ποσότητα του φωτός στο χώρο, ενώ στη συνέχεια, το Arduino θα αναλαμβάνει να ενεργοποιήσει ή να απενεργοποιήσει μία φωτιστική μονάδα με τη βοήθεια ενός ρελέ. Μία LCD οθόνη θα αναλαμβάνει να εμφανίζει τις τιμές που διαβάζει το Arduino από το LDR, ταυτόχρονα με την κατάσταση του ρελέ. Τα ίδια δεδομένα, θα εμφανίζονται και στο Serial Monitor του Arduino IDE. Ενα πλήκτρο (push-button) θα παρακάμπτει το σύστημα, και θα ενεργοποιεί τη φωτιστική μονάδα με το πάτημά του, με χρήση εξωτερικών διακοπών (external interrupts). Ιδανικά, στην LCD οθόνη θα θέλαμε να εμφανίζεται κάτι τέτοιο: L D R : 2 5 0 L A M P : O F F Περί του LDR Το εξάρτημα που θα χρησιμοποιήσουμε (LDR - Light-Dependent Resistor, Photo-Resistor ή photocell ) δεν είναι κάποιο αναλογικό ή ψηφιακό αισθητήριο. Στην πραγματικότητα είναι ένας ειδικός τύπος μεταβλητής αντίστασης, η τιμή της οποία μεταβάλλεται ανάλογα με την ένταση του φωτός που πέφτει πάνω της. Λόγω του ότι η μεταβολή της τιμής της αντίστασης δεν είναι γραμμική, αλλά και η ακρίβειά του είναι αρκετά χαμηλή, δε προτιμάται σε εφαρμογές μέτρησης της έντασης του φωτός. Αντιθέτως, χάρη στο χαμηλό του κόστος, χρησιμοποιείται κατά κόρον όπου ζητείται απλά να διαπιστωθεί το κατά πόσο ένας χώρος είναι φωτεινός ή όχι. ΣΧ. (1) Για τη διασύνδεση με το Arduino, επιστρατεύεται το LDR σε συνδεσμολογία διαιρέτη τάσης, όπως παρουσιάζεται στο σχηματικό (1). 4,7KΩ Όπως σε οποιαδήποτε άλλη περίπτωση αναλογικής ανάγνωσης, η συνάρτηση analogread() θα μας επιστρέψει μία τιμή στο εύρος [0 1023]. ANALOG INPUT
Περί του Relay Module Σε αντίθεση με το LOGO! της Siemens που χρησιμοποιήσαμε, το Arduino δεν ενσωματώνει κάποιον εύκολο τρόπο διαχείρισης μεγάλων φορτίων. Όταν λοιπόν θέλουμε να διαχειριστούμε τάση δικτύου (230V) ή ακόμα και χαμηλή τάση μεγάλης έντασης, είναι απαραίτητο να χρησιμοποιήσουμε ένα εξωτερικό ρελέ, ή άλλο παρόμοιο εξάρτημα (π.χ. TRIAC, κλπ). Τα ηλεκτρομαγνητικά ρελέ, λόγω των ηλεκτρικών ιδιαιτεροτήτων τους, χρειάζονται ένα ξεχωριστό κύκλωμα οδήγησης. Το Arduino δε μπορεί να τα διαχειριστεί κατευθείαν μέσω των ψηφιακών εξόδων του. Για ευκολία, αντί να σχεδιάσουμε και να υλοποιήσουμε το συγκεκριμένο κύκλωμα οδήγησης στο breadboard, θα χρησιμοποιήσουμε το ε ι κ ο ν ι ζ ό μ ε ν ο r e l a y m o d u l e, π ο υ ενσωματώνει 2 ηλεκτρομαγνητικά ρελέ, μαζί με τα περιφερειακά που απαιτούνται για τη λειτουργία τους. Περί της LCD Οθόνης Στο εργαστήριο χρησιμοποιούμε μια LCD οθόνη 2 γραμμών και 16 χαρακτήρων (1602) βασισμένη στο IC HD44780 της Hitachi (του οποίου η ιστορία ξεκινάει το 1987), που πιθανώς να είναι ο πιο κοινός τύπος οθόνης στην κοινότητα του Arduino. Τα VSS, VCC τροφοδοτούν την οθόνη (GND, 5V), ενώ το V0 ρυθμίζει την αντίθεσή της μέσω ενός ποτενσιόμετρου (συνδεσμολογία διαιρέτη τάσης). Τα RS, R/W και E χρησιμεύουν για το χειρισμό της οθόνης, ή με άλλα λόγια, την αποστολή εντολών προς το ολοκληρωμένο που τη διαχειρίζεται. Τα DB0 DB7 είναι οι είσοδοι δεδομένων, ενώ τέλος, τα LED+ και LED- είναι η τροφοδοσία του οπίσθιου φωτισμού (backlight). Για να λειτουργήσει η οθόνη με το Arduino, συνδέουμε τα pins 11, 12 με τις ακίδες RS, E της LCD
(ώστε να μεταφέρονται οι εντολές του προγράμματος) και τα pins 5, 4, 3, 2 με τις ακίδες D4 D7 της οθόνης. Επιπλέον, συνδέουμε την οθόνη στις ακίδες 1, 16 και 2, 15 με την γείωση (GND) και την τροφοδοσία (5V) του Arduino. Ολόκληρη η συνδεσμολογία παρουσιάζεται στο σχηματικό (2): ΣΧ. (2) Στον κώδικά μας, περιλαμβάνουμε τη βιβλιοθήκη <LiquidCrystal.h>. Η βιβλιοθήκη αυτή κάνει ευκολότερη τη διεπαφή με την οθόνη, καθώς αναλαμβάνει να εκτελέσει τις εγγραφές / αναγνώσεις των registers της οθόνης στο παρασκήνιο. Απαραίτητο είναι να δημιουργήσουμε ένα αντικείμενο lcd, της κλάσης LiquidCrystal, ως εξής: LiquidCrystal lcd(12, 11, 5, 4, 3, 2); Εννοείται πως εάν δεν έχουμε χρησιμοποιήσει αυτά τα pins, πρέπει στη δημιουργία του αντικειμένου να δηλώσουμε τα αντίστοιχα pins. Τέλος, στη συνάρητηση setup() δηλώνουμε το μέγεθος της οθόνης, ως εξής: lcd.begin(16, 2); Για την εμφάνιση δεδομένων στην οθόνη, είναι απαραίτητο να δηλώσουμε σε ποιο σημείο της θέλουμε να γράψουμε. Αυτό γίνεται εύκολα με τη συνάρτηση: lcd.setcursor(στήλη, γραµµή); Τέλος, η εγγραφή δεδομένων, γίνεται με τη συνάρτηση lcd.print(). Για παράδειγμα, η εντολή lcd.print( Hello, world! ); θα εμφανίσει στην LCD οθόνη το μήνυμα Hello, world!. Περισσότερες πληροφορίες για τη χρήση της LCD, στη διεύθυνση: http://arduino.cc/en/tutorial/liquidcrystal
Περί των Διακοπών (Interrupts) Οι εξωτερικές διακοπές ειδοποιούν τον μικροελεγκτή του Arduino για μία αλλαγή κατάστασης (συνήθως, επείγουσα). Αυτός στη συνέχεια θα παγώσει τις διεργασίες που εκτελεί για να δώσει άμεση προτεραιότητα στο interrupt handler (ή ISR interrupt service routine) ή αλλιώς, στην διαδικασία που καλείται να εκτελέσει όταν εμφανιστεί η διακοπή. Με την ολοκλήρωση της εκτέλεσης του interrupt handler, ο μικροελεγκτής θα συνεχίσει να εκτελεί όποια διεργασία είχε προηγουμένως παύσει, αφού επαναφέρει την κατάστασή της. Στο Arduino UNO, έχουμε δύο εξωτερικά interrupts (INT0 και INT1) που αντιστοιχούν στις φυσικές θύρες 2 και 3 πάνω στο αναπτυξιακό. Η συνάρτηση attachinterrupt(intx, ISR, MODE); θα αναθέσει την ρουτίνα ISR στη θύρα που αντιστοιχεί στο interrupt INTx, με την επιλογή MODE να δίνει τις παρακάτω επιλογές: LOW CHANGE RISING FALLING HIGH Ενεργοποιεί το interrupt όταν η θύρα είναι LOW (0V). Ενεργοποιεί το interrupt όταν η θύρα αλλάξει κατάσταση από LOW σε HIGH, ή από HIGH σε LOW. Ενεργοποιεί το interrupt όταν η θύρα αλλάξει κατάσταση από LOW σε HIGH. Ενεργοποιεί το interrupt όταν η θύρα αλλάξει κατάσταση από HIGH σε LOW. Ενεργοποιεί το interrupt όταν η θύρα είναι HIGH (5V). Η συνάρτηση detachinterrupt(intx); θα τερματίσει την ανάθεση του συγκεκριμένου interrupt, έτσι ώστε η συγκεκριμένη θύρα, να πάψει να εκτελεί το interrupt. Η συνάρτηση interrupts(); ενεργοποιεί τα interrupts (καθολικά) ενώ η nointerrupts(); τα απενεργοποιεί. Είναι σημαντικό να απενεργοποιούμε τα interrupts όταν έχουμε να κάνουμε μετρήσεις χρόνου μεγάλης ακρίβεια. Παρουσιάζεται ένα σύντομο παράδειγμα χρήσης των interrupts: INTERRUPTS DEMO const byte interrupt = 2; volatile byte state = LOW; void setup() / / Ο ρ ι σ µ ό ς τ ο υ p i n 1 3 σ α ν έ ξ ο δ ο. p i n M o d e ( 1 3, O U T P U T ) ;
/ / Ο ρ ι σ µ ό ς τ ο υ p i n i n t e r r u p t ( 2 ) σ α ν ε ί σ ο δ ο, µ ε τ α υ τ ό χ ρ ο ν η σ ύ ν δ ε σ ή / / τ ο υ σ τ α + 5 V µ έ σ ω ε ν σ ω µ α τ ο µ έ ν η ς α ν τ ί σ τ α σ η ς. p i n M o d e ( i n t e r r u p t, I N P U T _ P U L L U P ) ; / / Α ν ά θ ε σ η τ ο υ interrupt. a t t a c h I n t e r r u p t ( d i g i t a l P i n T o I n t e r r u p t ( i n t e r r u p t ), I S R, C H A N G E ) ; void loop() d i g i t a l W r i t e ( 1 3, s t a t e ) ; // Η ρουτίνα του interrupt. void ISR() s t a t e =! s t a t e ;