0
Έχει μια βάση αυτό που έγραψες αλλά το πρόβλημα είναι ότι θα καταναλώνεις κύκλους σε κάθε loop για να γράψεις στον register το state ενώ μπορεί να είναι ίδιος.
Μια ποιο σωστή προσέγγιση θα ήταν να είναι κάπως έτσι:
Όταν θα έρθει το interrupt θα ανεβεί μια σημαία να αλλάξει κατάσταση. Και στην loop που υποτίθεται δεν έχει κάτι καλύτερο να κάνει θα ελέγχει την σημαία και αν την βρει σηκωμένη θα αλλάζει κατάσταση και θα την κατεβάζει. Έτσι σε κάθε loop απλώς θα κάνει έλεγχο αν κάτι χρειάζεται ενημέρωση και μόνο τότε θα το ενημερώνει. Σε κάτι τόσο απλό μπορείς και απευθείας απ' το interrupt να αλλάζεις κατάσταση, το να κρατάς τα interrupt μικρά είναι ένας γενικός κανόνας για να αποφύγεις δυσάρεστες καταστάσεις αλλά εφόσον γνωρίζεις τι κάνεις μπορείς να κάνεις και άλλα πράγματα εκτός από σημαίες.Κώδικας:const byte ledPin = 13; const byte interruptPin = 2; byte state = LOW; volatile bool Change_State= False; void setup() { pinMode(ledPin, OUTPUT); pinMode(interruptPin, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE); } void loop() { if(Change_State){ state=!state; digitalWrite(ledPin, state); Change_State= False; } } void blink() { Change_State= True; }
Το ποιο σημαντικό είναι να ξέρεις ποια είναι τα ευπαθή σημεία του κώδικά σου που δεν σηκώνουν να τα διακόψεις όπως για παράδειγμα πολύ συνηθισμένο η μεταφορά δεδομένων όπου ο χρονισμός είναι σημαντικός, σε αυτές τις περιπτώσεις πριν στείλουμε κάτι κλείνουμε τελείως τα interrupt για όσο χρόνο στέλνουμε τα δεδομένα και μόλις τελειώσει τα ξανά ενεργοποιούμε και αν έχει έρθει κάποιο interrupt κατά τον χρόνο που στέλναμε τα δεδομένα το εξυπηρετεί τότε ανάλογα με την σειρά προτεραιότητας.
Πολλές βιβλιοθήκες το λαμβάνουν υπόψιν αυτό, άλλες πάλι όχι οπότε πρέπει να είσαι πολύ προσεκτικός γιατί είναι ένα bug που δεν θα εμφανίζεται συνέχεια, 10 θα δουλεύει, 1 όχι.
Επίσης, αν έχεις είσοδο κάποιο κουμπί, τα interrupt είναι γρήγορα και το bounce το αντιλαμβάνονται οπότε με αυτόν τον κώδικα θα σου έρθουν πολλά interrupt το ένα πίσω απ' το άλλο, όταν έχεις έξοδο στην σειριακή αυτή θα καθυστερεί τον έλεγχο της σημαίας και δεν θα βλέπεις να φλικάρει. Πολλά παλαβά μπορεί να προκύψουν. Αν πχ το Serial.print το βάλεις κάτω απ' το Change_State= False; πολύ πιθανό έτσι όπως το βλέπω να μην αλλάζει κατάσταση το led γιατί κατά την εκτύπωση στην σειριακή ένα interrupt να το ξανακάνει high και να ξανά αλλάξει το led στο επόμενο loop.
Και τα external interrupt είναι συγκεκριμένα σε κάθε μΕ και μπορεί να μην υποστηρίζουν όλα το CHANGE ή το HIGH, LOW κλπ, αυτά τα βλέπεις στο datasheet.
Η συνάρτηση του interrupt είναι μια απλή συνάρτηση, η οποία ξεκινάει σε μια θέση μνήμης, όταν έρχεται το interrupt ουσιαστικά εκτελεί μια εντολή τύπου GO_TO που το στέλνει σε αυτήν την θέση μνήμης. Μπορείς αυτήν την συνάρτηση να την καλέσεις κανονικά. Σε μερικούς μΕ μπορείς να προκαλέσεις interrupt μέσω software σηκώνοντας χειροκίνητα την σημαία που ελέγχει η CPU για να εξυπηρετήσει τα interrupt. Σε μερικούς δεν γίνεται γιατί είναι ρυθμισμένοι σε αυτήν την σημαία αν στέλνεις 1 να γράφεται 0 και αν στέλνεις 0 να μην γίνεται τίποτα (αν θυμάμαι καλά)
Τα interrupt λύνουν πολλά προβλήματα αλλά πρέπει να τα παίζεις στα δάχτυλα για να μην σου δημιουργήσουν άλλα προβλήματα που είναι δύσκολο να βρεις χωρίς in circuit debugger.
*Edit: Άλλαξα σε volatile την μεταβλητή που αλλάζει στο interrupt, by Savvas