- Γιατί χρονομετρητής όταν έχουμε καθυστέρηση ();
- Χρονοδιακόπτες μικροελεγκτή PIC:
- Προγραμματισμός και εξήγηση εργασίας:
- Διάγραμμα κυκλώματος και προσομοίωση πρωτεϊνών:
Αυτό θα είναι το πέμπτο σεμινάριο στη σειρά εκμάθησης PIC, το οποίο θα σας βοηθήσει να μάθετε και να χρησιμοποιήσετε χρονοδιακόπτες στο PIC16F877A. Στα προηγούμενα σεμινάριά μας, είχαμε ξεκινήσει με το Εισαγωγή στο PIC και το MPLABX IDE, στη συνέχεια γράψαμε το πρώτο μας πρόγραμμα PIC για να αναβοσβήνει το LED χρησιμοποιώντας PIC και στη συνέχεια φτιάξαμε μια ακολουθία LED που αναβοσβήνει χρησιμοποιώντας τη λειτουργία καθυστέρησης στον Μικροελεγκτή PIC. Τώρα ας χρησιμοποιήσουμε την ίδια ακολουθία LED που αναβοσβήνει που χρησιμοποιήσαμε σε προηγούμενο υλικό εκμάθησης και με αυτό θα μάθουμε πώς να χρησιμοποιούμε χρονοδιακόπτες στο PIC MCU μας. Μόλις προσθέσαμε ένα ακόμη κουμπί στην πλακέτα LED για αυτό το σεμινάριο. Διαβάστε το σεμινάριο για να μάθετε περισσότερα.
Οι χρονοδιακόπτες είναι ένα από τα σημαντικά εργαλεία για έναν ενσωματωμένο προγραμματιστή. Κάθε εφαρμογή που σχεδιάζουμε θα περιλαμβάνει κατά κάποιο τρόπο μια εφαρμογή χρονισμού, όπως το ON ή OFF κάτι μετά από ένα καθορισμένο χρονικό διάστημα. Εντάξει, αλλά γιατί χρειαζόμαστε χρονόμετρα όταν έχουμε ήδη μακροεντολές καθυστέρησης (__delay_ms ()) που κάνουν το ίδιο πράγμα !!
Γιατί χρονομετρητής όταν έχουμε καθυστέρηση ();
Μια μακροεντολή καθυστέρησης ονομάζεται καθυστέρηση "dump". Διότι κατά τη διάρκεια της εκτέλεσης της λειτουργίας καθυστέρησης, το MCU κάθεται dump με τη δημιουργία καθυστέρησης. Κατά τη διάρκεια αυτής της διαδικασίας, το MCU δεν μπορεί να ακούσει τις τιμές ADC του ή να διαβάσει τίποτα από τα Μητρώα του. Ως εκ τούτου, δεν συνιστάται η χρήση λειτουργιών καθυστέρησης εκτός από εφαρμογές όπως το LED που αναβοσβήνει όπου η καθυστέρηση χρόνου δεν χρειάζεται να είναι ακριβής ή μεγάλη.
Οι μακροεντολές καθυστέρησης έχουν επίσης τις ακόλουθες σύντομες εμφανίσεις,
- Η τιμή της καθυστέρησης πρέπει να είναι μια σταθερά για μακροεντολές καθυστέρησης. Δεν μπορεί να αλλάξει κατά την εκτέλεση του προγράμματος. Ως εκ τούτου, παραμένει ο προγραμματιστής καθορίζεται.
- Η καθυστέρηση δεν θα είναι ακριβής σε σύγκριση με τη χρήση χρονομέτρων.
- Δεν μπορούν να δημιουργηθούν μεγαλύτερες τιμές καθυστερήσεων χρησιμοποιώντας μακροεντολές, για παράδειγμα δεν μπορεί να δημιουργηθεί καθυστέρηση μισής ώρας με καθυστέρηση μακροεντολών. Η μέγιστη καθυστέρηση που μπορεί να χρησιμοποιηθεί βασίζεται στον Crystal ταλαντωτή που χρησιμοποιείται.
Χρονοδιακόπτες μικροελεγκτή PIC:
Φυσικά, ο χρονοδιακόπτης είναι ένας καταχωρητής του οποίου η τιμή αυξάνεται συνεχώς σε 255 και στη συνέχεια ξεκινά ξανά από την αρχή: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……και τα λοιπά.
Το PIC16F877A PIC MCU διαθέτει τρεις μονάδες χρονοδιακόπτη. Είναι ονόματα ως Timer0, Timer1 και Timer2. Ο χρονοδιακόπτης 0 και ο χρονοδιακόπτης 2 είναι χρονοδιακόπτες 8-bit και ο χρονοδιακόπτης 1 είναι χρονοδιακόπτης 16-bit. Σε αυτό το σεμινάριο θα χρησιμοποιήσουμε το χρονόμετρο 0 για την εφαρμογή μας. Μόλις καταλάβουμε το Χρονοδιακόπτη 0 θα είναι εύκολο να δουλέψουμε και στο Χρονοδιακόπτη 1 και στο Χρονοδιακόπτη 2.
Ο χρονοδιακόπτης / μετρητής μονάδας Timer0 έχει τα ακόλουθα χαρακτηριστικά:
- Χρονοδιακόπτης / μετρητής 8-bit
- Αναγνώσιμο και εγγράψιμο
- Προγραμματιζόμενο πρόγραμμα επεξεργασίας λογισμικού 8-bit
- Επιλέξτε εσωτερικό ή εξωτερικό ρολόι
- Διακοπή κατά την υπερχείλιση από FFh έως 00h
- Επιλέξτε Edge για εξωτερικό ρολόι
Για να αρχίσουμε να χρησιμοποιούμε ένα χρονοδιακόπτη, πρέπει να κατανοήσουμε μερικούς από τους φανταστικούς όρους, όπως ο χρονοδιακόπτης 8-bit / 16-bit, το Prescaler, οι διακοπές χρονοδιακόπτη και τα Focs. Τώρα, ας δούμε τι πραγματικά σημαίνει ο καθένας. Όπως ειπώθηκε προηγουμένως, υπάρχουν και οι 8-bit και 16-bit Timers στο PIC MCU μας, η κύρια διαφορά μεταξύ τους είναι ότι ο 16-bit Timer έχει πολύ καλύτερη ανάλυση από το 8-bit Timer.
Το Prescaler είναι ένα όνομα για το μέρος ενός μικροελεγκτή που διαιρεί το ρολόι ταλαντωτών πριν φτάσει στη λογική που αυξάνει την κατάσταση του χρονοδιακόπτη. Το εύρος του αναγνωριστικού prescaler είναι από 1 έως 256 και η τιμή του Prescaler μπορεί να οριστεί χρησιμοποιώντας το OPTION Register (Το ίδιο με αυτό που χρησιμοποιήσαμε για pull up αντιστάσεις). Για παράδειγμα, εάν η τιμή του prescaler είναι 64, τότε για κάθε 64 ου παλμό το χρονοδιακόπτη θα αυξάνεται κατά 1.
Καθώς ο χρονοδιακόπτης αυξάνεται και όταν φτάσει στη μέγιστη τιμή του 255, θα ενεργοποιήσει μια διακοπή και θα αρχικοποιηθεί ξανά στο 0 ξανά. Αυτή η διακοπή ονομάζεται διακοπή χρονοδιακόπτη. Αυτή η διακοπή ενημερώνει το MCU ότι έχει παρέλθει ο συγκεκριμένος χρόνος.
Το Fosc σημαίνει Συχνότητα του Ταλαντωτή, είναι η συχνότητα του Κρυστάλλου που χρησιμοποιείται. Ο χρόνος που απαιτείται για το μητρώο χρονοδιακόπτη εξαρτάται από την τιμή του Prescaler και την τιμή του Fosc.
Προγραμματισμός και εξήγηση εργασίας:
Σε αυτό το σεμινάριο θα ορίσουμε δύο κουμπιά ως δύο εισόδους και 8 LED ως 8 εξόδους. Το πρώτο κουμπί θα χρησιμοποιηθεί για να ρυθμίσετε την καθυστέρηση χρόνου (500ms για κάθε ώθηση) και το δεύτερο κουμπί θα χρησιμοποιηθεί για να ξεκινήσει να αναβοσβήνει η ακολουθία χρονοδιακόπτη. Για παράδειγμα, εάν πατηθεί το πρώτο κουμπί τρεις φορές (500 * 3 = 1500ms), η καθυστέρηση θα ρυθμιστεί για 1,5 δευτερόλεπτο και όταν πατηθεί το κουμπί δύο, κάθε LED θα ανάψει και θα απενεργοποιηθεί με την προκαθορισμένη καθυστέρηση χρόνου. Ελέγξτε το βίντεο επίδειξης στο τέλος αυτού του οδηγού.
Τώρα, έχοντας υπόψη αυτά τα βασικά, ας δούμε το πρόγραμμά μας που δίνεται στο τέλος στην ενότητα Κώδικας.
Είναι εντάξει αν δεν λάβατε το πρόγραμμα, αλλά αν το κάνατε !! Δώστε στον εαυτό σας ένα cookie και πετάξτε το πρόγραμμα για να απολαύσετε την παραγωγή σας. Για άλλους θα χωρίσω το πρόγραμμα σε ουσιαστικά μέρη και θα σας εξηγήσω τι συμβαίνει σε κάθε μπλοκ.
Όπως πάντα οι πρώτες γραμμές του κώδικα είναι οι ρυθμίσεις παραμέτρων και τα αρχεία κεφαλίδας, δεν πρόκειται να το εξηγήσω, αφού το έχω ήδη κάνει στα προηγούμενα σεμινάρια μου.
Στη συνέχεια, ας παρακάμψουμε όλες τις γραμμές και να πηδήσουμε κατευθείαν στην κενή λειτουργία κενής, μέσα στην οποία έχουμε τη διαμόρφωση PORT για το Timer0.
void main () {/ ***** Διαμόρφωση θύρας για χρονοδιακόπτη ****** / OPTION_REG = 0b00000101; // Timer0 με εξωτερικό freq και 64 ως prescalar // Ενεργοποιεί επίσης PULL UPs TMR0 = 100; // Φορτώστε την τιμή χρόνου για 0,0019968s. delayValue μπορεί να είναι μεταξύ 0-256 μόνο TMR0IE = 1; // Ενεργοποίηση bit διακοπής χρονοδιακόπτη στο μητρώο PIE1 GIE = 1; // Ενεργοποίηση καθολικής διακοπής PEIE = 1; // Ενεργοποίηση της περιφερειακής διακοπής / *********** ______ *********** /
Για να το καταλάβουμε αυτό πρέπει να κοιτάξουμε το OPTION Register στο δελτίο δεδομένων PIC.
Όπως συζητήθηκε στο προηγούμενο σεμινάριο, το bit 7 χρησιμοποιείται για να επιτρέψει την αδύναμη έλξη αντίστασης για το PORTB. Κοιτάξτε την παραπάνω εικόνα, το bit 3 έχει δημιουργηθεί 0 για να δώσει εντολή στο MCU ότι το ακόλουθο prescaler που ρυθμίζεται πρέπει να χρησιμοποιείται για το χρονόμετρο και όχι για το WatchDogTimer (WDT). Η λειτουργία χρονοδιακόπτη επιλέγεται διαγράφοντας το bit 5 T0CS
(ΕΠΙΛΟΓΗ_REG <5>)
Τώρα, το bits2-0 χρησιμοποιείται για τον ορισμό της τιμής prescaler για το χρονόμετρο. Όπως φαίνεται στον παραπάνω πίνακα για να ορίσετε μια τιμή προεπιλογής 64, τα bit πρέπει να οριστούν ως 101.
Στη συνέχεια, ας δούμε τα Μητρώα που σχετίζονται με το Timer0
Ο Χρονοδιακόπτης θα αρχίσει να αυξάνεται μόλις οριστεί και ξεχειλίσει αφού φτάσει στην τιμή των 256, για να επιτρέψει στο Διακόπτη να διακόψει κατά τη διάρκεια αυτού του σημείου, ο καταχωρητής TMR0IE πρέπει να οριστεί ψηλά. Επειδή ο ίδιος ο Χρονοδιακόπτης 0 είναι περιφερειακό, πρέπει να ενεργοποιήσουμε την Περιφερειακή Διακοπή κάνοντας PEIE = 1. Τέλος, πρέπει να ενεργοποιήσουμε την Παγκόσμια Διακοπή, ώστε το MCU να ειδοποιηθεί για τη Διακοπή κατά τη διάρκεια οποιασδήποτε λειτουργίας, αυτό γίνεται κάνοντας το GIE = 1.
Καθυστέρηση = ((256-REG_val) * (Prescal * 4)) / Fosc
Ο παραπάνω τύπος χρησιμοποιείται για τον υπολογισμό της τιμής της καθυστέρησης.
Οπου
REG_val = 100;
Prescal = 64
Fosc = 20000000
Αυτό στον υπολογισμό δίνει, Καθυστέρηση = 0,0019968s
Το επόμενο σύνολο γραμμών είναι να ορίσετε τις θύρες εισόδου / εξόδου.
/ ***** Διαμόρφωση θύρας για I / O ****** / TRISB0 = 1; // Διδάξτε στο MCU ότι ο ακροδέκτης PORTB 0 χρησιμοποιείται ως είσοδος για το κουμπί 1. TRISB1 = 1; // Διδάξτε στο MCU ότι ο ακροδέκτης PORTB 1 χρησιμοποιείται ως είσοδος για το κουμπί 1. TRISD = 0x00; // Διδάξτε στο MCU ότι όλες οι ακίδες στο PORT D έχουν έξοδο PORTD = 0x00; // Αρχικοποιήστε όλες τις καρφίτσες στο 0 / *********** ______ *********** /
Αυτό είναι ίδιο με αυτό του προηγούμενου σεμιναρίου μας, καθώς χρησιμοποιούμε το ίδιο υλικό. Εκτός ότι έχουμε προσθέσει ένα άλλο κουμπί ως εισαγωγή. Αυτό γίνεται με τη γραμμή TRISB1 = 1.
Στη συνέχεια, μέσα στο άπειρο, ενώ βρόχος έχουμε δύο μπλοκ κώδικα. Το ένα χρησιμοποιείται για τη λήψη του χρονοδιακόπτη από τον χρήστη και το άλλο για την εκτέλεση της ακολουθίας καθυστέρησης πάνω από τα LED Τους εξήγησα χρησιμοποιώντας σχόλια σε κάθε γραμμή.
ενώ (1) {count = 0; // Μην εκτελείτε χρονοδιακόπτη ενώ βρίσκεστε στον κύριο βρόχο // ******* Λάβετε την καθυστέρηση αριθμού από τον χρήστη **** ////// if (RB0 == 0 && flag == 0) // Πότε η είσοδος δόθηκε {get_scnds + = 1; // get_scnds = get_scnds + http: // Σημαία μεταβλητής αύξησης = 1; } if (RB0 == 1) // Για να αποφευχθεί η συνεχής αύξηση της σημαίας = 0; / *********** ______ *********** /
Μια μεταβλητή που ονομάζεται get_scnds αυξάνεται κάθε φορά που ο χρήστης πιέζει το κουμπί 1. Μια μεταβλητή flag (καθορισμένη από λογισμικό) χρησιμοποιείται για να κρατήσει τη διαδικασία αύξησης έως ότου ο χρήστης αφαιρέσει το δάχτυλό του από το κουμπί.
// ******* Εκτέλεση ακολουθίας με καθυστέρηση **** ////// ενώ (RB1 == 0) {PORTD = 0b00000001 <
Το επόμενο μπλοκ τίθεται σε λειτουργία εάν πατηθεί το κουμπί δύο. Επειδή ο χρήστης έχει ήδη ορίσει την απαιτούμενη χρονική καθυστέρηση χρησιμοποιώντας το κουμπί ένα και έχει αποθηκευτεί στη μεταβλητή get_scnds. Χρησιμοποιούμε μια μεταβλητή που ονομάζεται hscnd, αυτή η μεταβλητή ελέγχεται από το ISR (ρουτίνα διακοπής υπηρεσίας).
Η ρουτίνα υπηρεσίας διακοπής είναι μια διακοπή που καλείται κάθε φορά που ο Χρονοδιακόπτης0 ξεχειλίζει. Ας δούμε πώς ελέγχεται από το ISR στο επόμενο μπλοκ, όπως θέλουμε να αυξήσουμε τη χρονική καθυστέρηση κατά μισό δευτερόλεπτο (0,5 δευτερόλεπτα) σε κάθε πάτημα κουμπιού, τότε πρέπει να αυξήσουμε τη μεταβλητή hscnd για κάθε μισό δευτερόλεπτο. Καθώς έχουμε προγραμματίσει το χρονοδιακόπτη μας να υπερβαίνει τη ροή για κάθε 0,0019968 δευτερόλεπτα (~ 2ms), έτσι ώστε να μετράμε τη μεταβλητή μέτρησης μισού δευτερολέπτου πρέπει να είναι 250 επειδή 250 * 2ms = 0,5 δευτερόλεπτο. Έτσι, όταν η μέτρηση παίρνει 250 (250 * 2ms = 0,5 δευτερόλεπτο), σημαίνει ότι έχει περάσει μισό δευτερόλεπτο, οπότε αυξάνουμε το hscnd κατά 1 και αρχικοποιούμε τον αριθμό στο μηδέν.
void interrupt timer_isr () {if (TMR0IF == 1) // Η σημαία χρονοδιακόπτη ενεργοποιήθηκε λόγω υπερχείλισης χρονοδιακόπτη {TMR0 = 100; // Φορτώστε το χρονόμετρο Τιμή TMR0IF = 0; // Εκκαθάριση πλήθους σημαίας διακοπής χρονοδιακόπτη ++; } εάν (μέτρηση == 250) {hscnd + = 1; // hscnd θα αυξάνεται για κάθε μισό δευτερόλεπτο μέτρηση = 0; }}
Χρησιμοποιούμε λοιπόν αυτήν την τιμή και τη συγκρίνουμε με το hscnd μας και μετατοπίζουμε το LED μας με βάση τον καθορισμένο χρόνο από τον χρήστη. Είναι επίσης πολύ παρόμοιο με το τελευταίο σεμινάριο.
Αυτό είναι που το πρόγραμμά μας κατανοεί και λειτουργεί.
Διάγραμμα κυκλώματος και προσομοίωση πρωτεϊνών:
Όπως συνήθως ας επαληθεύσουμε πρώτα την έξοδο χρησιμοποιώντας το Proteus, έχω συνδέσει εδώ τα σχηματικά αρχεία του Proteus.
Προσθέστε ένα κουμπί στην προηγούμενη πλακέτα LED και το υλικό μας είναι έτοιμο να ξεκινήσει. Θα πρέπει να μοιάζει με αυτό:
Αφού ολοκληρωθεί η σύνδεση, Ανεβάστε τον κωδικό και επαληθεύστε την έξοδο. Εάν έχετε κάποιο πρόβλημα, χρησιμοποιήστε την ενότητα σχολίων. Ελέγξτε επίσης το παρακάτω βίντεο για να κατανοήσετε ολόκληρη τη διαδικασία.