Interruptions in microcontrollers

Τα πάντα για υπολογιστές και πληροφορική.
Άβαταρ μέλους
itteithe
Extreme poster
Extreme poster
Δημοσιεύσεις: 2348
Τοποθεσία: Τρίπολη

Interruptions in microcontrollers

Δημοσίευσηαπό itteithe » 30 Δεκ 2019, 19:13

Περιληπτικά (και χοντρικά για να κάνουμε μια μικρή εισαγωγή), σε ένα microcontroller όπου τρέχει αποκλειστικά το firmware του (το οποίο μπορεί να είναι είτε ένα λογισμικό, είτε ένα RTOS - real time operating system που εκτελεί συγκεκριμένα tasks), ο επεξεργαστής τρέχει στον προκαθορισμένο χρόνο του ρολογιού του ένα ατέρμονα βρόχο στον οποίο εκτελούνται βήμα βήμα οι οδηγίες που έχει προγραμματίσει ο προγραμματιστής του (είτε στο loop function αν πρόκειται για microcontroller που προγραμματίστηκε με το arduino sdk, είτε στο task που προγραμμάτισε για το RTOS).

Σ' αυτόν τον ατέρμονα βρόχο διαβάζουμε τις τιμές των εισόδων του microcontroller (που είναι προκαθορισμένα από εμάς "ποδαράκια", pins πάνω στον microcontroller) και αναλόγως τις τιμές που παίρνουμε και τον αλγόριθμο για το FSM (finite state machine) που θα υλοποιήσουμε, δίνουμε αντίστοιχες τιμές στις εξόδους του microcontroller (οι οποίες είναι πάλι "ποδαράκια" πάνω στον microcontroller).

Αν π.χ., έχουμε ένα push button κουμπωμένο πάνω σε ένα ποδαράκι του microcontroller που όταν το πατάμε θέλουμε να ανάβει ένα ledάκι που έχουμε κουμπωμένο πάνω σε ένα άλλο ποδαράκι του microcontroller, θα έπρεπε σ' αυτόν τον ατέρμονα βρόχο, σε κάθε κύκλο εκτέλεσής του, να κοιτούσαμε πρώτα την κατάσταση του κουμπιού (αν είναι πατημένο, ή όχι) και αναλόγως να δίναμε ρεύμα ή όχι στο led. Όπως καταλαβαίνεται, αυτό φαίνεται προβληματικό με μια δεύτερη σκέψη. Τι θα γίνει αν στο κύκλο εκτέλεσής μας, δεν μπορέσουμε να πιάσουμε το πάτημα του κουμπιού; Εκτός αυτού, το να διαβάζεις την κατάσταση ενός pin σε κάθε κύκλο εκτέλεσης, "κοστίζει" σε επεξεργαστικό χρόνο. Μπορεί στο παραπάνω παράδειγμα να φαίνεται γελοίο, αλλά στα περιορισμένης ισχύς κυκλώματα που έχουν πάνω τους κουμπωμένους διάφορους αισθητήρες και κουμπιά, αυτός ο φαινομενικά ελάχιστος χρόνος είναι πολύτιμος.

Γι αυτές τις περιπτώσεις, οι διάφοροι microcontrollers έχουν συγκεκριμένα pin (αν όχι όλα) που μπορούν με τον κατάλληλο προγραμματισμό να διακόψουν την λειτουργία του ατέρμονα βρόχου, να εκτελέσουν μια μικρής επεξεργαστικής διάρκειας ρουτίνα και όταν τελειώσουν να αφήσουν τον ατέρμονα βρόχο να συνεχίσει. Κατά συνέπεια, στο παραπάνω παράδειγμα, αντί να κοιτάζουμε συνέχεια σε κάθε πέρασμα του ατέρμονα βρόχου την κατάσταση του κουμπιού, μπορούμε να γράψουμε μια μικρή ρουτίνα η οποία θα αλλάζει την τιμή μια μεταβλητής και με βάση αυτήν την μεταβλητή να παίρνουμε τις κατάλληλες αποφάσεις στον ατέρμονα βρόχο. Έτσι μέσα στον ατέρμονα βρόχο, εκτελούμε μόνο κώδικα που έχει πραγματική αξία, ενώ η αλλαγή της κατάστασης του κουμπιού θα επηρεάσει την εκτέλεσή του μόνο όταν πατηθεί το κουμπί.

Ας περάσουμε στον κώδικα. Για την δική μου ευκολία, αλλά και για την δική σας, θα παραθέσω κώδικα από arduino sdk (το RTOS απαιτεί να θέσεις και προτεραιότητες στα interruptions κάτι που το κάνει ελαφρώς πιο πολύπλοκο).

Κώδικας: Επιλογή όλων

/*
 * Το ποδαράκι του led μας. Για την ακρίβεια το
 * pin 13 είναι το led που έχει ήδη πάνω του ένας
 * arduino. Χρησιμοποιούμε το πρόθεμα const
 * για να πούμε στον compiler (στο πρόγραμμα
 * που θα μεταγλωττίσει αυτόν τον κώδικα σε
 * γλώσσα μηχανής, σε 0 και 1 που να μπορεί
 * να τα διαβάζει ο επεξεργαστής) οτι αυτή η
 * τιμή και ο τύπος της δεν πρόκειται να αλλάξει
 * κατά την εκτέλεση.
*/
const int ledPin = 13;

/*
 * Το ποδαράκι του κουμπιού μας.
*/
const int interruptPin = 2;

/*
 * Το flag που θα χρησιμοποιήσουμε για να
 * αποφασίσουμε αν θα ανάψουμε το led ή όχι.
 * Χρησιμοποιούμε το πρόθεμα volatile, γιατί ο
 * compiler προσπαθεί πάντα να βελτιστοποιήσει
 * τον κώδικα γλώσσας μηχανής που παράγει
 * και επειδή δεν βλέπει να μεταβάλλεται αυτή
 * η τιμή στη ρουτίνα loop() παρακάτω, αν δεν
 * βάλλουμε το πρόθεμα volatile, θα αντικαταστήσει
 * την τιμή στο if που υπάρχει στην ρουτίνα loop()
 * με false.
 */
volatile int state = 0;

/*
 * Αυτή η ρουτίνα εκτελείται μόνο μια φορά κατά
 * την εκκίνηση του conrtoller (αλλά και όποτε
 * πατάμε το reset button) και σ' αυτήν την ρουτίνα
 * προκαθορίζουμε είτε τι κάνει κάθε pin που έχουμε
 * συνδεδεμένο στον controller μας, είτε αρχικοποιούμε
 * κάποιες μεταβλητές και βιβλιοθήκες που θα χρησιμο-
 * ποιήσουμε παρακάτω στην loop(()
*/
void setup() {
    // Εδώ ορίζουμε πως το ποδαράκι 13 θα χρησιμοποιηθεί
    // σαν έξοδος.
    pinMode(ledPin, OUTPUT);
   
    // Εδώ ορίζουμε πως το ποδαράκι 2 θα χρησιμοποιηθεί
    // σαν είσοδος, η οποία θα χρησιμοποιεί τις εσωτερικές
    // αντιστάσεις του επεξεργαστή μας (διορθώστε με αν
    // κάνω λάθος, γι αυτό δεν είμαι και τόσο σίγουρος).
    pinMode(interruptPin, INPUT_PULLUP);
   
    // Εδώ ορίζουμε πως το ποδαράκι δύο, μπορεί να πραγματο-
    // ποιήσει ένα interrupt όποτε αλλάξει κατάσταση το pin (το
    // CHANGE που του έχουμε δώσει σαν παράμετρο), το οποίο
    // θα καλέσει και θα εκτελέσει την ρουτίνα stateChange().
    attachInterrupt(digitalPinToInterrupt(interruptPin), stateChange, CHANGE);
}

/*
 * Ο ατέρμον βρόχος μας
*/
void loop() {
    if (state) { // Αν το state είναι 1, άναψε το led
         digitalWrite(ledPin, HIGH);
    } else { // αλλιώς σβήσ' το.
        digitalWrite(ledPin, LOW);
    }
}

/*
 * Η ρουτίνα που θα εκτελεστεί κατά το interruption.
 * Βλέπετε πως είναι "μικρή" ρουτίνα. Δεν πρέπει
 * να κάνει "βαριά" πράγματα, όπως π.χ. ένα network
 * call. Επίσης, η ρουτίνα που εκτελείται κατά το
 * interruption δεν πρέπει να επιστρέφει τίποτα (δεν
 * μπορεί να είναι συνάρτηση δηλαδή).
*/
void stateChange() {
    // Δώσε την αντίθετη τιμή από αυτήν που είχε
    // η μεταβλητή state, στην μεταβλητή state.
    // Προγραμματιστικά, το αντίθετο του 1 είναι το
    // 0 και το αντίθετο του 0 το 1.
    state = !state;
}
1 .
Δῶς μοι πᾶ στῶ καὶ τὰν γᾶν κινάσω

Habemus filium

vallon
Supreme poster
Supreme poster
Δημοσιεύσεις: 13683

Re: Interruptions in microcontrollers

Δημοσίευσηαπό vallon » 31 Δεκ 2019, 06:40

πρώτα να πω ότι δεν ασχολούμαι και πάρα πολύ με το programming
ίσως όχι τόσο σε μικροσυστήματα, περισσότερο η γνώση που έχω είναι σε άλλους τομείς , os400 , system κλπ

πολύ σωστή όμως η λογική του προγραματισμού με interrupts
να κι ένα άλλο παράδειγμα..
https://www.arduino.cc/en/Tutorial/InputPullupSerial

κοίτα τέλος το attachment
αυτό έχει μέσα την άσκηση με το led
είναι σχολικό βοήθημα
0 .
Αν ο κομπλεξισμός ήταν άθλημα, κάποιοι θα είχαν πάρει πανηγυρικά το πρωτάθλημα.

Άβαταρ μέλους
itteithe
Extreme poster
Extreme poster
Δημοσιεύσεις: 2348
Τοποθεσία: Τρίπολη

Re: Interruptions in microcontrollers

Δημοσίευσηαπό itteithe » 31 Δεκ 2019, 09:08

Εν τω μεταξύ, interrupts μπορείς να χρησιμοποιήσεις και με άλλα components εκτός από τα απλά push buttons, π.χ. με ποτενσιόμετρα, αν θες να πιάνεις με ακρίβεια την κάθε μεταβολή του ρότορα (ή με φωτοδιόδους, κτλπ.). Επίσης, ξέχασα να αναφέρω πως ο αριθμός του pin στο οποίο έχεις κάνει attach ένα ISR (interruption service routine - την ρουτίνα που θα εκτελεστεί όταν γίνει η διακοπή), είναι και ο αριθμός προτεραιότητας εκτέλεσης σε περίπτωση ταυτόχρονων interrupts.

Πάντως οι μικροελεγκτές είναι ιδανικό εργαλείο για να μάθει κανείς πως να προγραμματίζει, αλλά και πως λειτουργεί ένας υπολογιστής γενικά (btw και οι υπολογιστές ευρείας χρήσης, όπως τα κινητά, είναι interrupt-driven μόνο που οι διακοπές είναι πιο περίπλοκες εκεί, υπάρχουν dispatcher και schedulers και διάφοροι άλλοι μηχανισμοί για να χειρίζονται τις διακοπές και να μπορούν να κάνουν multitasking). Κατ' αρχάς μαθαίνεις να κάνεις οικονομία στην χρήση της RAM και του επεξεργαστή, κάτι που στον προγραμματισμό για υπολογιστές ευρείας χρήσης δεν σε απασχολεί ιδιαίτερα (μέχρι να έρθει η στιγμή που θα αναγκαστείς -ή θα σε αναγκάσουν- να κάνεις refactor τον κώδικά σου).
1 .
Δῶς μοι πᾶ στῶ καὶ τὰν γᾶν κινάσω

Habemus filium


Επιστροφή σε “Πληροφορική”