Πίνακας περιεχομένων:
- Βήμα 1: Κατασκευή του κυκλώματος
- Βήμα 2: Γιατί χρειαζόμαστε τα σχόλια και το αρχείο M328Pdef.inc;
- Βήμα 3: Blink.asm
- Βήμα 4:.org Οδηγίες Assembler
- Βήμα 5: Χρονόμετρο/Μετρητής 0
- Βήμα 6: Διαχειριστής υπερχείλισης
- Βήμα 7: Καθυστέρηση
- Βήμα 8: Αναβοσβήνει
- Βήμα 9: Συμπέρασμα
Βίντεο: Φροντιστήριο AVR Assembler 3: 9 Βήματα
2024 Συγγραφέας: John Day | [email protected]. Τελευταία τροποποίηση: 2024-01-30 08:31
Καλώς ορίσατε στο φροντιστήριο νούμερο 3!
Πριν ξεκινήσουμε θέλω να κάνω ένα φιλοσοφικό σημείο. Μην φοβάστε να πειραματιστείτε με τα κυκλώματα και τον κώδικα που κατασκευάζουμε σε αυτά τα σεμινάρια. Αλλάξτε καλώδια τριγύρω, προσθέστε νέα εξαρτήματα, αφαιρέστε εξαρτήματα, αλλάξτε γραμμές κώδικα, προσθέστε νέες γραμμές, διαγράψτε γραμμές και δείτε τι συμβαίνει! Είναι πολύ δύσκολο να σπάσεις οτιδήποτε και αν το κάνεις, ποιος νοιάζεται; Τίποτα που χρησιμοποιούμε, συμπεριλαμβανομένου του μικροελεγκτή, δεν είναι πολύ ακριβό και είναι πάντα εκπαιδευτικό να δούμε πώς μπορούν να αποτύχουν τα πράγματα. Όχι μόνο θα μάθετε τι να μην κάνετε την επόμενη φορά, αλλά, το πιο σημαντικό, θα ξέρετε γιατί να μην το κάνετε. Αν είσαι κάτι σαν εμένα, όταν ήσουν παιδί και είχες ένα καινούργιο παιχνίδι, δεν άργησε να το πάρεις κομμάτια για να δεις τι το έκανε να τσιμπήσει σωστά; Μερικές φορές το παιχνίδι κατέληξε σε ανεπανόρθωτη ζημιά, αλλά όχι μεγάλη υπόθεση. Επιτρέποντας σε ένα παιδί να εξερευνήσει την περιέργειά του ακόμη και σε σημείο που έχει σπάσει παιχνίδια είναι αυτό που το μετατρέπει σε επιστήμονα ή μηχανικό αντί για πλυντήριο πιάτων.
Σήμερα θα συνδέσουμε ένα πολύ απλό κύκλωμα και στη συνέχεια θα ασχοληθούμε λίγο με τη θεωρία. Λυπάμαι για αυτό, αλλά χρειαζόμαστε τα εργαλεία! Υπόσχομαι ότι θα το αναπληρώσουμε στο φροντιστήριο 4 όπου θα κάνουμε πιο σοβαρή κατασκευή κυκλώματος και το αποτέλεσμα θα είναι αρκετά δροσερό. Ωστόσο, ο τρόπος που πρέπει να κάνετε όλα αυτά τα μαθήματα είναι με πολύ αργό, στοχαστικό τρόπο. Εάν απλά περάσετε, δημιουργήσετε το κύκλωμα, αντιγράψτε και επικολλήστε τον κώδικα και εκτελέστε τον τότε, σίγουρα, θα λειτουργήσει, αλλά δεν θα μάθετε τίποτα. Πρέπει να σκεφτείτε κάθε γραμμή. Παύση. Πείραμα. Εφευρίσκω. Αν το κάνετε με αυτόν τον τρόπο, μέχρι το τέλος του 5ου σεμιναρίου δεν θα χτίσετε υπέροχα πράγματα και δεν χρειάζεστε άλλο φροντιστήριο. Διαφορετικά, απλά παρακολουθείτε και όχι μαθαίνετε και δημιουργείτε.
Σε κάθε περίπτωση, αρκετή φιλοσοφία, ας ξεκινήσουμε!
Σε αυτό το σεμινάριο θα χρειαστείτε:
- τον πίνακα πρωτοτύπων σας
- ένα LED
- καλώδια σύνδεσης
- μια αντίσταση περίπου 220 έως 330 ohms
- Εγχειρίδιο συνόλου οδηγιών: www.atmel.com/images/atmel-0856-avr-instruction-se…
- Το φύλλο δεδομένων: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
- διαφορετικός ταλαντωτής κρυστάλλων (προαιρετικά)
Ακολουθεί ένας σύνδεσμος για την πλήρη συλλογή σεμιναρίων:
Βήμα 1: Κατασκευή του κυκλώματος
Το κύκλωμα σε αυτό το σεμινάριο είναι εξαιρετικά απλό. Ουσιαστικά πρόκειται να γράψουμε το πρόγραμμα "blink", οπότε το μόνο που χρειαζόμαστε είναι το ακόλουθο.
Συνδέστε ένα LED σε PD4, στη συνέχεια σε μια αντίσταση 330 ohm, στη συνέχεια στη γείωση. δηλ.
PD4 - LED - R (330) - GND
και αυτό είναι!
Ωστόσο, η θεωρία θα είναι δύσκολη…
Βήμα 2: Γιατί χρειαζόμαστε τα σχόλια και το αρχείο M328Pdef.inc;
Νομίζω ότι πρέπει να ξεκινήσουμε δείχνοντας γιατί το αρχείο συμπερίληψης και τα σχόλια είναι χρήσιμα. Κανένα από αυτά δεν είναι πραγματικά απαραίτητο και μπορείτε να γράψετε, να συναρμολογήσετε και να ανεβάσετε κώδικα με τον ίδιο τρόπο χωρίς αυτά και θα λειτουργήσει τέλεια (αν και χωρίς το αρχείο συμπερίληψης μπορεί να λάβετε κάποια παράπονα από τον συναρμολογητή - αλλά χωρίς σφάλματα)
Εδώ είναι ο κώδικας που πρόκειται να γράψουμε σήμερα, εκτός από το ότι έχω αφαιρέσει τα σχόλια και το αρχείο συμπερίληψης:
.συσκευή ATmega328P
.org 0x0000 jmp a.org 0x0020 jmp ea: ldi r16, 0x05 out 0x25, r16 ldi r16, 0x01 sts 0x6e, r16 sei clr r16 out 0x26, r16 sbi 0x0a, 0x04 sbi 0x0b, 0x04 b, sbi 0x0b, 0x04 b, sbi 0x0b cbi 0x0b, 0x04 rcall c rjmp bc: clr r17 d: cpi r17, 0x1e brne d ret e: inc r17 cpi r17, 0x3d brne PC+2 clr r17 reti
αρκετά απλό σωστά; Χαχα. Εάν συναρμολογήσετε και ανεβάσετε αυτό το αρχείο, θα κάνετε το LED να αναβοσβήνει με ρυθμό 1 αναβοσβήνει ανά δευτερόλεπτο με το αναβοσβήσιμο να διαρκεί 1/2 δευτερόλεπτο και η παύση μεταξύ των αναλαμπών να διαρκεί 1/2 δευτερόλεπτο.
Ωστόσο, η εξέταση αυτού του κώδικα δεν είναι σχεδόν διαφωτιστική. Αν επρόκειτο να γράψετε έναν τέτοιο κώδικα και θέλετε να τον τροποποιήσετε ή να τον επαναπροσδιορίσετε στο μέλλον, θα δυσκολευόσασταν.
Ας βάλουμε λοιπόν τα σχόλια και συμπεριλάβουμε το αρχείο ξανά ώστε να μπορέσουμε να το καταλάβουμε.
Βήμα 3: Blink.asm
Ακολουθεί ο κώδικας που θα συζητήσουμε σήμερα:
;************************************
? γραμμένο από: 1o_o7; ημερομηνία: έκδοση: 1.0; το αρχείο αποθηκεύτηκε ως: blink.asm; για AVR: atmega328p; συχνότητα ρολογιού: 16MHz (προαιρετικό); ********************************** Λειτουργία προγράμματος: ---------------------; μετράει δευτερόλεπτα αναβοσβήνοντας ένα LED. ? PD4 - LED - R (330 ohm) - GND;; --------------------------------------. μητρώο. Συμπεριλάβετε "./m328Pdef.inc". λίστα; ============== Δηλώσεις:.def temp = r16.def ξεχειλίζει = r17.org 0x0000; μνήμη (Η / Υ) θέση επαναφοράς χειριστή rjmp Επαναφορά; Το jmp κοστίζει 2 κύκλους cpu και το rjmp κοστίζει μόνο 1. Επομένως, εκτός εάν χρειαστεί να πηδήξετε περισσότερα από 8k byte. χρειάζεστε μόνο rjmp. Επομένως, ορισμένοι μικροελεγκτές μόνο. έχουν rjmp και όχι jmp.org 0x0020? θέση μνήμης του Timer0 overflow handler rjmp overflow_handler? μεταβείτε εδώ εάν προκύψει διακοπή υπερχείλισης timer0; ============ Επαναφορά: ldi temp, 0b00000101 out TCCR0B, temp? ορίστε τα Ρυθμιστικά bit επιλογής CS00, CS01, CS02 σε 101. Αυτό θέτει το Timer Counter0, TCNT0 σε λειτουργία FCPU/1024. Τσιμπάει στη συχνότητα CPU/1024 ldi temp, 0b00000001 sts TIMSK0, temp. ρυθμίστε το bit του Timer Overflow Interrupt Enable (TOIE0). του Timer Interrupt Mask Register (TIMSK0) sei; ενεργοποίηση καθολικών διακοπών - ισοδύναμου με "sbi SREG, I" clr temp out TCNT0, temp? προετοιμάστε το χρονόμετρο/μετρητή σε 0 sbi DDRD, 4. ορίστε το PD4 στην έξοδο; ===================== Κύριο σώμα του προγράμματος: αναβοσβήνει: sbi PORTD, 4; ενεργοποιήστε το LED στο PD4 rcall καθυστέρηση? η καθυστέρηση θα είναι 1/2 δευτερόλεπτο cbi PORTD, 4? απενεργοποιήστε το LED στο PD4 rcall καθυστέρηση? Η καθυστέρηση θα είναι 1/2 δευτερόλεπτο αναβοσβήνει rjmp. επιστρέψτε στην καθυστέρηση έναρξης: το clr ξεχειλίζει. ορίστε τις υπερχειλίσεις σε 0 sec_count: το cpi ξεχειλίζει, 30; σύγκριση αριθμού υπερχειλίσεων και 30 δευτερολέπτων sec_count. διακλάδωση προς τα πίσω στο sec_count αν δεν είναι ίσο ret? εάν έχουν συμβεί 30 υπερχειλίσεις επιστρέφουν στο αναβοσβήνουν overflow_handler: inc overflows? προσθέστε 1 στις υπερχειλίσεις μεταβλητής cpi υπερχειλίσεις, 61 · σύγκριση με 61 brne PC+2? Πρόγραμμα μετρητή + 2 (παράβλεψη επόμενης γραμμής), αν δεν ισούται με υπερχείλιση clr. εάν εμφανιστούν 61 υπερχειλίσεις επαναφέρετε τον μετρητή στο μηδέν reti. επιστροφή από τη διακοπή
Όπως μπορείτε να δείτε, τα σχόλιά μου είναι λίγο πιο σύντομα τώρα. Μόλις μάθουμε ποιες είναι οι εντολές στο σύνολο οδηγιών, δεν χρειάζεται να το εξηγήσουμε στα σχόλια. Αρκεί να εξηγήσουμε τι συμβαίνει από την άποψη του προγράμματος.
Θα συζητήσουμε τι κάνει όλο αυτό κομμάτι κομμάτι, αλλά πρώτα ας προσπαθήσουμε να αποκτήσουμε μια παγκόσμια προοπτική. Το κύριο σώμα του προγράμματος λειτουργεί ως εξής.
Αρχικά ορίσαμε το bit 4 του PORTD με "sbi PORTD, 4" αυτό στέλνει ένα 1 στο PD4 το οποίο θέτει την τάση στα 5V σε αυτόν τον πείρο. Αυτό θα ανάψει το LED. Στη συνέχεια, πηγαίνουμε στην υπορουτίνα "καθυστέρηση" που μετρά 1/2 το δευτερόλεπτο (θα εξηγήσουμε πώς το κάνει αυτό αργότερα). Στη συνέχεια επιστρέφουμε στο αναβοσβήνει και καθαρίζουμε το bit 4 στο PORTD που θέτει το PD4 σε 0V και ως εκ τούτου κλείνει το LED. Κατόπιν καθυστερούμε για άλλο 1/2 δευτερόλεπτο και μετά επιστρέφουμε στην αρχή του αναβοσβήματος ξανά με "rjmp blink".
Θα πρέπει να εκτελέσετε αυτόν τον κώδικα και να δείτε ότι κάνει αυτό που πρέπει.
Και εκεί το έχετε! Αυτό είναι το μόνο που κάνει αυτός ο κώδικας φυσικά. Οι εσωτερικοί μηχανισμοί του τι κάνει ο μικροελεγκτής εμπλέκονται λίγο περισσότερο και γι 'αυτό κάνουμε αυτό το σεμινάριο. Ας συζητήσουμε λοιπόν κάθε τμήμα με τη σειρά.
Βήμα 4:.org Οδηγίες Assembler
Γνωρίζουμε ήδη τι κάνουν οι οδηγίες.nolist,.list,.include και.def assembler από τα προηγούμενα σεμινάρια μας, οπότε ας ρίξουμε πρώτα μια ματιά στις 4 γραμμές κώδικα που έρχονται μετά από αυτό:
.org 0x0000
jmp Επαναφορά.org 0x0020 jmp overflow_handler
Η δήλωση.org λέει στον συναρμολογητή πού βρίσκεται στην "Μνήμη προγράμματος" για να τοποθετήσει την επόμενη πρόταση. Καθώς εκτελείται το πρόγραμμά σας, ο "Μετρητής προγράμματος" (που μειώθηκε ως υπολογιστής) περιέχει τη διεύθυνση της τρέχουσας γραμμής που εκτελείται. Σε αυτήν την περίπτωση, όταν ο υπολογιστής βρίσκεται στο 0x0000, θα δει την εντολή "jmp Reset" που βρίσκεται στη συγκεκριμένη θέση μνήμης. Ο λόγος που θέλουμε να θέσουμε το jmp Reset σε αυτήν τη θέση είναι επειδή όταν ξεκινά το πρόγραμμα ή επαναφέρεται το τσιπ, ο υπολογιστής αρχίζει να εκτελεί κώδικα σε αυτό το σημείο. Έτσι, όπως μπορούμε να δούμε, μόλις του είπαμε να "μεταβεί" αμέσως στην ενότητα με την ένδειξη "Επαναφορά". Γιατί το κάναμε αυτό; Αυτό σημαίνει ότι οι δύο τελευταίες γραμμές παραπάνω παραλείπονται! Γιατί;
Λοιπόν, εκεί τα πράγματα γίνονται ενδιαφέροντα. Τώρα θα πρέπει να ανοίξετε ένα πρόγραμμα προβολής pdf με το πλήρες φύλλο δεδομένων ATmega328p που έδειξα στην πρώτη σελίδα αυτού του σεμιναρίου (γι 'αυτό είναι το στοιχείο 4 στην ενότητα "θα χρειαστείτε"). Εάν η οθόνη σας είναι πολύ μικρή ή έχετε ήδη ανοίξει πάρα πολλά παράθυρα (όπως συμβαίνει με μένα), μπορείτε να κάνετε ό, τι κάνω και να την τοποθετήσετε σε ένα Ereader ή στο τηλέφωνό σας Android. Θα το χρησιμοποιείτε συνεχώς εάν σκοπεύετε να γράψετε κώδικα συναρμολόγησης. Το ωραίο είναι ότι όλοι οι μικροελεγκτές οργανώνονται με παρόμοιους τρόπους και έτσι μόλις συνηθίσετε να διαβάζετε φύλλα δεδομένων και να κωδικοποιείτε από αυτά, θα θεωρήσετε σχεδόν ασήμαντο να κάνετε το ίδιο για διαφορετικό μικροελεγκτή. Έτσι μαθαίνουμε στην πραγματικότητα πώς να χρησιμοποιούμε όλους τους μικροελεγκτές κατά μία έννοια και όχι μόνο το atmega328p.
Εντάξει, γυρίστε στη σελίδα 18 στο φύλλο δεδομένων και ρίξτε μια ματιά στο Σχήμα 8-2.
Έτσι ρυθμίζεται η Μνήμη Προγράμματος στον μικροελεγκτή. Μπορείτε να δείτε ότι ξεκινά με τη διεύθυνση 0x0000 και χωρίζεται σε δύο ενότητες. ένα τμήμα flash εφαρμογής και ένα τμήμα flash εκκίνησης. Αν ανατρέξετε εν συντομία στη σελίδα 277 πίνακα 27-14, θα δείτε ότι η ενότητα φλας εφαρμογών καταλαμβάνει τις θέσεις από 0x0000 έως 0x37FF και η ενότητα φλας εκκίνησης καταλαμβάνει τις υπόλοιπες θέσεις από 0x3800 έως 0x3FFF.
Άσκηση 1: Πόσες τοποθεσίες υπάρχουν στη μνήμη του Προγράμματος; Δηλ. μετατρέπουμε το 3FFF σε δεκαδικό και προσθέτουμε 1 αφού αρχίζουμε να μετράμε στο 0. Δεδομένου ότι κάθε θέση μνήμης έχει πλάτος 16 bits (ή 2 bytes) ποιος είναι ο συνολικός αριθμός byte μνήμης; Τώρα μετατρέψτε το σε kilobytes, θυμηθείτε ότι υπάρχουν 2^10 = 1024 byte σε ένα kilobyte. Η ενότητα φλας εκκίνησης πηγαίνει από 0x3800 σε 0x37FF, πόσα κιλομπάιτ είναι αυτό; Πόσα κιλομπάιτ μνήμης απομένουν για να χρησιμοποιήσουμε για την αποθήκευση του προγράμματός μας; Με άλλα λόγια, πόσο μεγάλο μπορεί να είναι το πρόγραμμά μας; Τέλος, πόσες γραμμές κώδικα μπορούμε να έχουμε;
Εντάξει, τώρα που γνωρίζουμε τα πάντα για την οργάνωση της μνήμης του προγράμματος flash, ας συνεχίσουμε με τη συζήτησή μας για τις δηλώσεις.org. Βλέπουμε ότι η πρώτη θέση μνήμης 0x0000 περιέχει την οδηγία μας για μετάβαση στην ενότητα που ονομάσαμε Επαναφορά. Τώρα βλέπουμε τι κάνει η δήλωση ".org 0x0020". Λέει ότι θέλουμε η εντολή στην επόμενη γραμμή να τοποθετηθεί στη θέση μνήμης 0x0020. Η οδηγία που έχουμε τοποθετήσει είναι μια μετάβαση σε μια ενότητα στον κωδικό μας που έχουμε χαρακτηρίσει "overflow_handler" … τώρα γιατί στο καλό θα απαιτούσαμε να τοποθετηθεί αυτό το άλμα στη θέση μνήμης 0x0020; Για να το μάθετε, γυρίζουμε στη σελίδα 65 στο φύλλο δεδομένων και ρίχνουμε μια ματιά στον Πίνακα 12-6.
Ο πίνακας 12-6 είναι ένας πίνακας "Επαναφορά και διακοπή διανυσμάτων" και δείχνει ακριβώς πού θα πάει ο υπολογιστής όταν λάβει "διακοπή". Για παράδειγμα, αν κοιτάξετε τον αριθμό του Διανύσματος 1. Η "πηγή" της διακοπής είναι "ΕΠΑΝΑΦΟΡΑ", η οποία ορίζεται ως "Εξωτερική καρφίτσα, Επαναφορά ενεργοποίησης, Επαναφορά Brown-out και Επαναφορά συστήματος Watchdog", εάν υπάρχει Αυτά συμβαίνουν στον μικροελεγκτή μας, ο υπολογιστής θα αρχίσει να εκτελεί το πρόγραμμά μας στη θέση μνήμης προγράμματος 0x0000. Τι γίνεται με την οδηγία μας.org τότε; Λοιπόν, τοποθετήσαμε μια εντολή στη θέση μνήμης 0x0020 και αν κοιτάξετε προς τα κάτω τον πίνακα θα δείτε ότι εάν συμβεί υπερχείλιση χρονομέτρου/μετρητή (προέρχεται από το TIMER0 OVF) θα εκτελέσει ό, τι βρίσκεται στη θέση 0x0020. Έτσι, όποτε συμβεί αυτό, ο υπολογιστής θα μεταβεί στο σημείο που ονομάσαμε "overflow_handler". Δροσερό σωστά; Θα δείτε σε ένα λεπτό γιατί το κάναμε αυτό, αλλά πρώτα ας ολοκληρώσουμε αυτό το βήμα του σεμιναρίου με μια άκρη.
Αν θέλουμε να κάνουμε τον κωδικό μας πιο προσεγμένο και τακτοποιημένο, θα πρέπει πραγματικά να αντικαταστήσουμε τις 4 γραμμές που συζητάμε αυτήν τη στιγμή με τις ακόλουθες (δείτε σελίδα 66):
.org 0x0000
rjmp Επαναφορά; PC = 0x0000 reti; PC = 0x0002 reti; PC = 0x0004 reti; PC = 0x0006 reti; PC = 0x0008 reti; PC = 0x000A… reti; PC = 0x001E jmp overflow_handler: PC = 0x0020 reti: PC = 0x0022… reti; PC = 0x0030 reti; PC = 0x0032
Έτσι, εάν συμβεί μια συγκεκριμένη διακοπή, θα "reti" που σημαίνει "επιστροφή από τη διακοπή" και δεν συμβαίνει τίποτα άλλο. Αλλά αν δεν "ενεργοποιήσουμε" ποτέ αυτές τις διάφορες διακοπές, τότε δεν θα χρησιμοποιηθούν και μπορούμε να βάλουμε κώδικα προγράμματος σε αυτά τα σημεία. Στο τρέχον πρόγραμμα "blink.asm" θα ενεργοποιήσουμε μόνο τη διακοπή υπερχείλισης timer0 (και φυσικά τη διακοπή επαναφοράς που είναι πάντα ενεργοποιημένη) και έτσι δεν θα ασχοληθούμε με τα άλλα.
Πώς «ενεργοποιούμε» τότε τη διακοπή υπερχείλισης timer0; … Αυτό είναι το θέμα του επόμενου βήματος σε αυτό το σεμινάριο.
Βήμα 5: Χρονόμετρο/Μετρητής 0
Ρίξτε μια ματιά στην παραπάνω εικόνα. Αυτή είναι η διαδικασία λήψης αποφάσεων του "Η / Υ" όταν κάποια εξωτερική επιρροή "διακόπτει" τη ροή του προγράμματός μας. Το πρώτο πράγμα που κάνει όταν λαμβάνει σήμα από έξω ότι έχει συμβεί διακοπή είναι να ελέγξει αν έχουμε ορίσει το bit "ενεργοποίησης διακοπής" για αυτόν τον τύπο διακοπής. Εάν δεν το έχουμε κάνει, τότε απλώς συνεχίζει να εκτελεί την επόμενη γραμμή κώδικα. Εάν έχουμε ορίσει το συγκεκριμένο bit ενεργοποίησης διακοπής (έτσι ώστε να υπάρχει 1 σε αυτήν τη θέση bit αντί για 0), τότε θα ελέγξει αν έχουμε ενεργοποιήσει ή όχι "καθολικές διακοπές", αν όχι, θα μεταβεί ξανά στην επόμενη γραμμή του κώδικα και συνεχίστε. Εάν έχουμε ενεργοποιήσει επίσης καθολικές διακοπές, τότε θα μεταβεί στη θέση μνήμης προγράμματος αυτού του τύπου διακοπής (όπως φαίνεται στον πίνακα 12-6) και θα εκτελέσει οποιαδήποτε εντολή έχουμε τοποθετήσει εκεί. Ας δούμε λοιπόν πώς τα έχουμε εφαρμόσει όλα αυτά στον κώδικά μας.
Η ενότητα με την ετικέτα Επαναφορά του κώδικα ξεκινά με τις ακόλουθες δύο γραμμές:
Επαναφορά:
ldi temp, 0b00000101 out TCCR0B, θερμ
Όπως ήδη γνωρίζουμε, αυτό φορτώνει στη θερμοκρασία (δηλαδή R16) τον αμέσως αμέσως επόμενο αριθμό, ο οποίος είναι 0b00000101. Στη συνέχεια γράφει αυτόν τον αριθμό στο μητρώο που ονομάζεται TCCR0B χρησιμοποιώντας την εντολή "out". Τι είναι αυτό το μητρώο; Λοιπόν, ας μεταβούμε στη σελίδα 614 του φύλλου δεδομένων. Αυτό βρίσκεται στη μέση ενός πίνακα που συνοψίζει όλους τους καταχωρητές. Στη διεύθυνση 0x25 θα βρείτε το TCCR0B. (Τώρα ξέρετε από πού προήλθε η γραμμή "out 0x25, r16" στην ανεκτίμητη έκδοση του κώδικα μου). Βλέπουμε από το τμήμα κώδικα παραπάνω ότι έχουμε ορίσει το 0ο και το 2ο bit και έχουμε καθαρίσει όλα τα υπόλοιπα. Κοιτάζοντας τον πίνακα μπορείτε να δείτε ότι αυτό σημαίνει ότι έχουμε ορίσει CS00 και CS02. Τώρα ας περάσουμε στο κεφάλαιο στο φύλλο δεδομένων που ονομάζεται "Χρονοδιακόπτης 8-bit/Counter0 με PWM". Ειδικότερα, μεταβείτε στη σελίδα 107 αυτού του κεφαλαίου. Θα δείτε την ίδια περιγραφή του μητρώου "Timer/Counter Control Register B" (TCCR0B) που μόλις είδαμε στον συνοπτικό πίνακα μητρώου (έτσι θα μπορούσαμε να είχαμε έρθει κατευθείαν εδώ, αλλά ήθελα να δείτε πώς να χρησιμοποιήσετε τους συνοπτικούς πίνακες για μελλοντική αναφορά). Το φύλλο δεδομένων συνεχίζει να δίνει μια περιγραφή για κάθε ένα από τα δυαδικά ψηφία σε αυτόν τον καταχωρητή και τι κάνουν. Θα τα παραλείψουμε προς το παρόν και θα γυρίσουμε τη σελίδα στον Πίνακα 15-9. Αυτός ο πίνακας εμφανίζει την ένδειξη "Περιγραφή επιλογής ρολογιού επιλογής ρολογιού". Τώρα κοιτάξτε προς τα κάτω αυτόν τον πίνακα μέχρι να βρείτε τη γραμμή που αντιστοιχεί στα bits που μόλις ορίσαμε σε αυτόν τον καταχωρητή. Η γραμμή λέει "clk/1024 (από prescaler)". Αυτό σημαίνει ότι θέλουμε το Timer/Counter0 (TCNT0) να σημειωθεί με ρυθμό που είναι η συχνότητα της CPU διαιρούμενη με 1024. Δεδομένου ότι ο μικροελεγκτής μας τροφοδοτείται από έναν ταλαντωτή κρυστάλλων 16MHz σημαίνει ότι ο ρυθμός που εκτελεί ο CPU μας είναι 16 εκατομμύρια οδηγίες ανά δευτερόλεπτο. Έτσι, το ποσοστό που θα σημειώσει ο μετρητής TCNT0 είναι τότε 16 εκατομμύρια/1024 = 15625 φορές ανά δευτερόλεπτο (δοκιμάστε το με διαφορετικά κομμάτια επιλογής ρολογιού και δείτε τι συμβαίνει - θυμηθείτε τη φιλοσοφία μας;). Ας κρατήσουμε τον αριθμό 15625 στο πίσω μέρος του μυαλού μας για αργότερα και προχωρούμε στις επόμενες δύο γραμμές κώδικα:
ldi temp, 0b00000001
sts TIMSK0, θερμ
Αυτό ορίζει το 0ο bit ενός καταχωρητή που ονομάζεται TIMSK0 και διαγράφει όλα τα υπόλοιπα. Αν ρίξετε μια ματιά στη σελίδα 109 στο φύλλο δεδομένων, θα δείτε ότι το TIMSK0 σημαίνει "Timer/Counter Interrupt Mask Register 0" και ο κωδικός μας έχει ορίσει το 0ο bit που ονομάζεται TOIE0 και σημαίνει "Timer/Counter0 Overflow Interrupt Enable" … Εκεί! Τώρα βλέπετε περί τίνος πρόκειται. Έχουμε τώρα το "set interrupt enable bit set" όπως θέλαμε από την πρώτη απόφαση στην εικόνα μας στην κορυφή. Έτσι, το μόνο που έχουμε να κάνουμε είναι να ενεργοποιήσουμε τις "παγκόσμιες διακοπές" και το πρόγραμμά μας θα είναι σε θέση να ανταποκριθεί σε τέτοιου είδους διακοπές. Θα ενεργοποιήσουμε σύντομα καθολικές διακοπές, αλλά πριν το κάνουμε αυτό μπορεί να έχετε μπερδευτεί με κάτι.. γιατί στο καλό χρησιμοποίησα την εντολή "sts" για αντιγραφή στο μητρώο TIMSK0 αντί για το συνηθισμένο "out";
Κάθε φορά που με βλέπετε να χρησιμοποιώ μια οδηγία που δεν έχετε δει πριν, το πρώτο πράγμα που πρέπει να κάνετε είναι να μεταβείτε στη σελίδα 616 στο φύλλο δεδομένων. Αυτή είναι η "Περίληψη συνόλου οδηγιών". Τώρα βρείτε την οδηγία "STS" που είναι αυτή που χρησιμοποίησα. Λέει ότι παίρνει έναν αριθμό από ένα μητρώο R (χρησιμοποιήσαμε R16) και "Αποθήκευση απευθείας στο SRAM" θέση k (στην περίπτωσή μας που δόθηκε από το TIMSK0). Γιατί λοιπόν έπρεπε να χρησιμοποιήσουμε το "sts" που χρειάζεται 2 κύκλους ρολογιού (βλ. Τελευταία στήλη στον πίνακα) για αποθήκευση στο TIMSK0 και χρειαζόμασταν μόνο το "out", το οποίο χρειάζεται μόνο έναν κύκλο ρολογιού, για αποθήκευση στο TCCR0B πριν; Για να απαντήσουμε σε αυτήν την ερώτηση πρέπει να επιστρέψουμε στον συνοπτικό πίνακα μητρώου στη σελίδα 614. Βλέπετε ότι ο καταχωρητής TCCR0B βρίσκεται στη διεύθυνση 0x25 αλλά και στη διεύθυνση (0x45) σωστά; Αυτό σημαίνει ότι είναι ένας καταχωρητής στο SRAM, αλλά είναι επίσης ένας συγκεκριμένος τύπος καταχωρητή που ονομάζεται "θύρα" (ή καταχωρητής i/o). Αν κοιτάξετε τον συνοπτικό πίνακα οδηγιών δίπλα στην εντολή "out", θα δείτε ότι παίρνει τιμές από τους "καταχωρητές εργασίας" όπως το R16 και τις αποστέλλει σε μια PORT. Μπορούμε λοιπόν να χρησιμοποιήσουμε το "out" όταν γράφουμε στο TCCR0B και να σώσουμε έναν κύκλο ρολογιού. Αλλά τώρα αναζητήστε το TIMSK0 στον πίνακα καταχώρισης. Βλέπετε ότι έχει διεύθυνση 0x6e. Αυτό είναι έξω από το εύρος των θυρών (οι οποίες είναι μόνο οι πρώτες θέσεις 0x3F του SRAM) και έτσι πρέπει να επιστρέψετε στη χρήση της εντολής sts και να κάνετε δύο κύκλους ρολογιού CPU για να το κάνετε. Διαβάστε τη Σημείωση 4 στο τέλος του συνοπτικού πίνακα οδηγιών στη σελίδα 615 τώρα. Σημειώστε επίσης ότι όλες οι θύρες εισόδου και εξόδου, όπως το PORTD, βρίσκονται στο κάτω μέρος του πίνακα. Για παράδειγμα, το PD4 είναι το bit 4 στη διεύθυνση 0x0b (τώρα βλέπετε από πού προήλθαν όλα τα στοιχεία 0x0b στον κωδικό μου χωρίς σχολιασμό!).. εντάξει, γρήγορη ερώτηση: αλλάξατε τα "sts" σε "out" και δείτε τι συμβαίνει; Θυμηθείτε τη φιλοσοφία μας! σπάστο! μην παίρνεις μόνο τον λόγο μου για πράγματα.
Εντάξει, προτού προχωρήσουμε, γυρίστε στη σελίδα 19 στο φύλλο δεδομένων για ένα λεπτό. Βλέπετε μια εικόνα της μνήμης δεδομένων (SRAM). Οι πρώτοι 32 καταχωρητές στο SRAM (από 0x0000 έως 0x001F) είναι οι "καταχωρητές εργασίας γενικής χρήσης" R0 έως R31 που χρησιμοποιούμε συνεχώς ως μεταβλητές στον κωδικό μας. Οι επόμενοι 64 καταχωρητές είναι οι θύρες εισόδου/εξόδου έως 0x005f (δηλαδή αυτές για τις οποίες μιλούσαμε που έχουν εκείνες τις μη αγκυλωμένες διευθύνσεις δίπλα τους στον πίνακα καταχωρητή για τις οποίες μπορούμε να χρησιμοποιήσουμε την εντολή "out" αντί για "sts") το επόμενο τμήμα του SRAM περιέχει όλους τους άλλους καταχωρητές στον συνοπτικό πίνακα έως τη διεύθυνση 0x00FF, και τέλος το υπόλοιπο είναι εσωτερικό SRAM. Τώρα γρήγορα, ας γυρίσουμε στη σελίδα 12 για ένα δευτερόλεπτο. Εκεί βλέπετε έναν πίνακα με τα "μητρώα εργασίας γενικής χρήσης" που χρησιμοποιούμε πάντα ως μεταβλητές μας. Βλέπετε την παχιά γραμμή μεταξύ των αριθμών R0 έως R15 και στη συνέχεια R16 έως R31; Αυτή η γραμμή είναι ο λόγος που χρησιμοποιούμε πάντα το R16 ως το μικρότερο και θα ασχοληθώ λίγο περισσότερο με το επόμενο σεμινάριο όπου θα χρειαστούμε επίσης τους τρεις έμμεσους καταχωρητές διευθύνσεων 16-bit, X, Y και Z. Δεν θα το κάνω μπείτε σε αυτό ακόμα, αν και δεν το χρειαζόμαστε τώρα και βυθιζόμαστε αρκετά εδώ.
Γυρίστε πίσω μία σελίδα στη σελίδα 11 του φύλλου δεδομένων. Θα δείτε ένα διάγραμμα του μητρώου SREG επάνω δεξιά; Βλέπετε ότι το bit 7 αυτού του καταχωρητή ονομάζεται "I". Τώρα κατεβείτε στη σελίδα και διαβάστε την περιγραφή του Bit 7…. ναι! Είναι το bit Global Interrupt Enable. Αυτό πρέπει να ορίσουμε για να περάσουμε από τη δεύτερη απόφαση στο παραπάνω διάγραμμα και να επιτρέψουμε διακοπές υπερχείλισης χρονομέτρου/μετρητή στο πρόγραμμά μας. Επομένως, η επόμενη γραμμή του προγράμματός μας πρέπει να είναι:
sbi SREG, Ι
που ορίζει το bit που ονομάζεται "I" στο μητρώο SREG. Ωστόσο, αντί για αυτό, χρησιμοποιήσαμε την οδηγία
sei
αντι αυτου. Αυτό το bit ρυθμίζεται τόσο συχνά σε προγράμματα που απλώς έκαναν έναν απλούστερο τρόπο για να το κάνουν.
Εντάξει! Τώρα έχουμε έτοιμες τις διακοπές υπερχείλισης έτσι ώστε το "jmp overflow_handler" να εκτελείται όποτε συμβεί.
Πριν προχωρήσουμε, ρίξτε μια γρήγορη ματιά στο μητρώο SREG (Status Register) γιατί είναι πολύ σημαντικό. Διαβάστε τι αντιπροσωπεύει κάθε σημαία. Συγκεκριμένα, πολλές από τις οδηγίες που χρησιμοποιούμε θα ρυθμίζουν και θα ελέγχουν αυτές τις σημαίες συνεχώς. Για παράδειγμα, αργότερα θα χρησιμοποιούμε την εντολή "CPI" που σημαίνει "άμεση σύγκριση". Ρίξτε μια ματιά στον συνοπτικό πίνακα οδηγιών για αυτήν την οδηγία και παρατηρήστε πόσες σημαίες ορίζει στη στήλη "σημαίες". Αυτές είναι όλες οι σημαίες στο SREG και ο κώδικας μας θα τις ρυθμίζει και θα τις ελέγχει συνεχώς. Σύντομα θα δείτε παραδείγματα. Τέλος, το τελευταίο κομμάτι αυτού του τμήματος κώδικα είναι:
clr temp
έξω TCNT0, temp sbi DDRD, 4
Η τελευταία γραμμή εδώ είναι αρκετά προφανής. Απλώς ορίζει το 4ο bit του καταχωρητή κατεύθυνσης δεδομένων για το PortD προκαλώντας την έξοδο του PD4.
Το πρώτο θέτει τη μεταβλητή θερμοκρασία στο μηδέν και στη συνέχεια το αντιγράφει στον καταχωρητή TCNT0. Το TCNT0 είναι το χρονόμετρο/μετρητής0 μας. Αυτό το θέτει στο μηδέν. Μόλις ο υπολογιστής εκτελέσει αυτήν τη γραμμή, ο χρονοδιακόπτης 0 θα ξεκινήσει από μηδέν και θα μετρήσει με ρυθμό 15625 φορές κάθε δευτερόλεπτο. Το πρόβλημα είναι αυτό: Το TCNT0 είναι μητρώο "8-bit" σωστά; Ποιος είναι λοιπόν ο μεγαλύτερος αριθμός που μπορεί να χωρέσει ένας καταχωρητής 8 bit; Λοιπόν 0b11111111 είναι. Αυτός είναι ο αριθμός 0xFF. Ποιο είναι το 255. Βλέπεις λοιπόν τι συμβαίνει; Ο χρονοδιακόπτης αυξάνεται 15625 φορές το δευτερόλεπτο και κάθε φορά που φτάνει τα 255 "ξεχειλίζει" και επιστρέφει ξανά στο 0. Την ίδια στιγμή που επιστρέφει στο μηδέν στέλνει ένα σήμα διακοπής υπερχείλισης χρονοδιακόπτη. Ο υπολογιστής το παίρνει αυτό και ξέρετε τι κάνει μέχρι τώρα σωστά; Ναι Πηγαίνει στη θέση μνήμης προγράμματος 0x0020 και εκτελεί την εντολή που βρίσκει εκεί.
Μεγάλος! Αν είσαι ακόμα μαζί μου, τότε είσαι ένας ακούραστος υπερήρωας! Ας συνεχίσουμε…
Βήμα 6: Διαχειριστής υπερχείλισης
Ας υποθέσουμε λοιπόν ότι ο καταχωρητής timer/counter0 μόλις ξεχείλισε. Γνωρίζουμε τώρα ότι το πρόγραμμα λαμβάνει ένα σήμα διακοπής και εκτελεί 0x0020 το οποίο λέει στον Μετρητή Προγράμματος, PC να μεταβεί στην ετικέτα "overflow_handler", ο ακόλουθος είναι ο κώδικας που γράψαμε μετά από αυτήν την ετικέτα:
overflow_handler:
inc υπερχειλίζει cpi υπερχειλίζει, 61 brne PC+2 clr υπερχειλίζει reti
Το πρώτο πράγμα που κάνει είναι να αυξήσει τη μεταβλητή "overflows" (που είναι το όνομά μας για τον καταχωρητή εργασίας γενικής χρήσης R17), στη συνέχεια "συγκρίνει" το περιεχόμενο των υπερχειλίσεων με τον αριθμό 61. Ο τρόπος με τον οποίο λειτουργεί η εντολή cpi είναι ότι απλά αφαιρεί τους δύο αριθμούς και αν το αποτέλεσμα είναι μηδέν, ορίζει τη σημαία Ζ στο μητρώο SREG (σας είπα ότι θα βλέπουμε αυτόν τον καταχωρητή όλη την ώρα). Εάν οι δύο αριθμοί είναι ίσοι τότε η σημαία Ζ θα είναι 1, αν οι δύο αριθμοί δεν είναι ίσοι τότε θα είναι 0.
Η επόμενη γραμμή λέει "brne PC+2" που σημαίνει "διακλάδωση αν δεν είναι ίση". Ουσιαστικά, ελέγχει τη σημαία Z στο SREG και αν ΔΕΝ είναι ένα (δηλαδή οι δύο αριθμοί δεν είναι ίσοι, εάν ήταν ίσοι, η μηδενική σημαία θα οριστεί) ο υπολογιστής διακλαδίζεται σε PC+2, δηλαδή παραλείπει το επόμενο γραμμή και πηγαίνει κατευθείαν στο "reti" το οποίο επιστρέφει από τη διακοπή σε όποιο μέρος ήταν στον κώδικα όταν έφτασε η διακοπή. Εάν η εντολή brne έβρισκε ένα 1 στο bit μηδενικής σημαίας, δεν θα διακλαδιζόταν και αντίθετα θα συνέχιζε στην επόμενη γραμμή, η οποία θα υπερχειλίσει το cr, επαναφέροντάς το στο 0.
Ποιο είναι το καθαρό αποτέλεσμα όλων αυτών;
Λοιπόν, βλέπουμε ότι κάθε φορά που υπάρχει υπερχείλιση χρονοδιακόπτη, αυτός ο χειριστής αυξάνει την τιμή των "υπερχειλίσεων" κατά μία. Έτσι, η μεταβλητή "υπερχειλίσεις" μετρά τον αριθμό των υπερχειλίσεων καθώς εμφανίζονται. Κάθε φορά που ο αριθμός φτάνει στο 61 τον επαναφέρουμε στο μηδέν.
Τώρα γιατί στον κόσμο θα το κάνουμε αυτό;
Ας δούμε. Θυμηθείτε ότι η ταχύτητα ρολογιού μας για τον επεξεργαστή μας είναι 16MHz και την "προ -κλιμακώσαμε" χρησιμοποιώντας το TCCR0B, έτσι ώστε ο χρονοδιακόπτης να μετράει μόνο με ρυθμό 15625 μετρήσεις ανά δευτερόλεπτο σωστά; Και κάθε φορά που το χρονόμετρο φθάνει σε αριθμό 255 ξεχειλίζει. Αυτό σημαίνει ότι ξεχειλίζει 15625/256 = 61,04 φορές το δευτερόλεπτο. Παρακολουθούμε τον αριθμό των υπερχειλίσεων με τη μεταβλητή μας "υπερχειλίσεις" και συγκρίνουμε αυτόν τον αριθμό με 61. Έτσι βλέπουμε ότι οι "υπερχειλίσεις" θα είναι 61 κάθε δευτερόλεπτο! Έτσι, ο χειριστής μας θα μηδενίζει τις "υπερχειλίσεις" μία φορά κάθε δευτερόλεπτο. Έτσι, εάν παρακολουθήσουμε απλώς τη μεταβλητή "υπερχειλίσεις" και λάβουμε υπόψη κάθε φορά που επαναφέρεται στο μηδέν, θα μετρούσαμε δευτερόλεπτο σε πραγματικό χρόνο (Σημειώστε ότι στο επόμενο σεμινάριο θα δείξουμε πώς να αποκτήσετε μια πιο ακριβή καθυστέρηση σε χιλιοστά του δευτερολέπτου με τον ίδιο τρόπο που λειτουργεί η ρουτίνα Arduino "καθυστέρησης").
Τώρα έχουμε "χειριστεί" τις διακοπές υπερχείλισης του χρονοδιακόπτη. Βεβαιωθείτε ότι έχετε καταλάβει πώς λειτουργεί αυτό και, στη συνέχεια, προχωρήστε στο επόμενο βήμα όπου θα χρησιμοποιήσουμε αυτό το γεγονός.
Βήμα 7: Καθυστέρηση
Τώρα που είδαμε ότι η ρουτίνα χειριστή διακοπής υπερχείλισης χρονοδιακόπτη "overflow_handler" θα θέσει τη μεταβλητή "υπερχείλιση" στο μηδέν μία φορά κάθε δευτερόλεπτο, μπορούμε να χρησιμοποιήσουμε αυτό το γεγονός για να σχεδιάσουμε μια υπορουτίνα "καθυστέρησης".
Ρίξτε μια ματιά στον ακόλουθο κώδικα κάτω από την καθυστέρηση: ετικέτα
καθυστέρηση:
clr ξεχειλίζει sec_count: cpi ξεχειλίζει, 30 brne sec_count ret
Θα καλέσουμε αυτό το υποπρόγραμμα κάθε φορά που χρειαζόμαστε καθυστέρηση στο πρόγραμμά μας. Ο τρόπος με τον οποίο λειτουργεί είναι ότι πρώτα θέτει τη μεταβλητή "υπερχειλίσεις" στο μηδέν. Στη συνέχεια, εισέρχεται σε μια περιοχή με την ένδειξη "sec_count" και συγκρίνει τις υπερχειλίσεις με 30, αν δεν είναι ίσες, διακλαδίζεται πίσω στην ετικέτα sec_count και συγκρίνει ξανά, και ξανά, κ.λπ. έως ότου τελικά είναι ίσες (θυμηθείτε ότι όλο στο χρονόμετρο, ο χειριστής διακοπών συνεχίζει να αυξάνει τις μεταβλητές υπερχείλισης και έτσι αλλάζει κάθε φορά που πηγαίνουμε εδώ. Όταν οι υπερχειλίσεις ισούται τελικά με 30, βγαίνει από τον βρόχο και επιστρέφει όπου κι αν ονομάσαμε καθυστέρηση: από. Το καθαρό αποτέλεσμα είναι καθυστέρηση 1/2 δευτερολέπτου
Άσκηση 2: Αλλάξτε τη ρουτίνα overflow_handler στα ακόλουθα:
overflow_handler:
inc υπερχειλίζει reti
και τρέξτε το πρόγραμμα. Είναι κάτι διαφορετικό; Γιατί ή γιατί όχι?
Βήμα 8: Αναβοσβήνει
Τέλος, ας δούμε τη ρουτίνα αναλαμπής:
αναβοσβήνω:
sbi PORTD, 4 rcall delay cbi PORTD, 4 rcall delay rjmp blink
Αρχικά ενεργοποιούμε το PD4 και μετά καλούμε το υποπρόγραμμα καθυστέρησης. Χρησιμοποιούμε το rcall έτσι ώστε όταν ο υπολογιστής φτάσει σε μια δήλωση "ret" να επιστρέψει στη γραμμή μετά το rcall. Στη συνέχεια, η ρουτίνα καθυστέρησης καθυστερεί για 30 μετρήσεις στη μεταβλητή υπερχείλισης όπως έχουμε δει και αυτό είναι σχεδόν 1/2 δευτερόλεπτο, στη συνέχεια απενεργοποιούμε το PD4, καθυστερούμε άλλο 1/2 δευτερόλεπτο και μετά επιστρέφουμε ξανά στην αρχή.
Το καθαρό αποτέλεσμα είναι ένα LED που αναβοσβήνει!
Νομίζω ότι τώρα θα συμφωνήσετε ότι το "blink" μάλλον δεν είναι το καλύτερο πρόγραμμα "hello world" στη γλώσσα συναρμολόγησης.
Άσκηση 3: Αλλάξτε τις διάφορες παραμέτρους του προγράμματος έτσι ώστε η λυχνία LED να αναβοσβήνει με διαφορετικούς ρυθμούς, όπως ένα δευτερόλεπτο ή 4 φορές το δευτερόλεπτο κ.λπ. Για παράδειγμα, ενεργοποιημένο για 1/4 δευτερόλεπτο και στη συνέχεια απενεργοποιημένο για 2 δευτερόλεπτα ή κάτι παρόμοιο. Άσκηση 5: Αλλάξτε τα επιλεγμένα bit ρολογιού TCCR0B σε 100 και, στη συνέχεια, συνεχίστε να ανεβαίνετε τον πίνακα. Σε ποιο σημείο γίνεται δυσδιάκριτο από το πρόγραμμα "hello.asm" από το σεμινάριο 1; Άσκηση 6 (προαιρετικά): Εάν έχετε διαφορετικό ταλαντωτή κρυστάλλων, όπως 4 MHz ή 13,5 MHz ή οτιδήποτε άλλο, αλλάξτε τον ταλαντωτή σας 16 MHz στο breadboard σας για το νέο και δείτε πώς αυτό επηρεάζει το ρυθμό αναλαμπής του LED. Θα πρέπει τώρα να μπορείτε να περάσετε από τον ακριβή υπολογισμό και να προβλέψετε πώς ακριβώς θα επηρεάσει το ποσοστό.
Βήμα 9: Συμπέρασμα
Για όσους από εσάς τους σκληροτράχηλους που τα καταφέρατε μέχρι εδώ, συγχαρητήρια!
Συνειδητοποιώ ότι είναι αρκετά δύσκολο να βυθίζεσαι όταν διαβάζεις και κοιτάς ψηλά από ό, τι κάνεις και πειραματίζεσαι, αλλά ελπίζω να έχεις μάθει τα ακόλουθα σημαντικά πράγματα:
- Πώς λειτουργεί η μνήμη προγράμματος
- Πώς λειτουργεί το SRAM
- Πώς να αναζητήσετε μητρώα
- Πώς να αναζητήσετε οδηγίες και να μάθετε τι κάνουν
- Πώς να εφαρμόσετε τις διακοπές
- Πώς το CP εκτελεί τον κώδικα, πώς λειτουργεί το SREG και τι συμβαίνει κατά τη διάρκεια διακοπών
- Πώς να κάνετε βρόχους και άλματα και να αναπηδήσετε στον κώδικα
- Πόσο σημαντικό είναι να διαβάζετε το φύλλο δεδομένων!
- Μόλις ξέρετε πώς να τα κάνετε όλα αυτά για τον μικροελεγκτή Atmega328p, θα είναι μια σχετική βόλτα με κέικ για να μάθετε τυχόν νέα χειριστήρια που σας ενδιαφέρουν.
- Πώς να αλλάξετε χρόνο CPU σε πραγματικό χρόνο και να τον χρησιμοποιήσετε σε ρουτίνες καθυστέρησης.
Τώρα που έχουμε πολλές θεωρίες από τον τρόπο που μπορούμε να γράψουμε καλύτερο κώδικα και να ελέγξουμε πιο περίπλοκα πράγματα. Έτσι, το επόμενο σεμινάριο θα κάνουμε ακριβώς αυτό. Θα δημιουργήσουμε ένα πιο περίπλοκο, πιο ενδιαφέρον, κύκλωμα και θα το ελέγξουμε με διασκεδαστικούς τρόπους.
Άσκηση 7: "Σπάστε" τον κώδικα με διάφορους τρόπους και δείτε τι συμβαίνει! Επιστημονική περιέργεια μωρό μου! Κάποιος άλλος μπορεί να πλύνει τα πιάτα σωστά; Άσκηση 8: Συγκεντρώστε τον κώδικα χρησιμοποιώντας την επιλογή "-l" για να δημιουργήσετε ένα αρχείο λίστας. Δηλ. "avra -l blink.lst blink.asm" και ρίξτε μια ματιά στο αρχείο λίστας. Extra Credit: Ο κωδικός χωρίς σχόλια που έδωσα στην αρχή και ο κωδικός που σχολιάσαμε και συζητάμε αργότερα διαφέρουν! Υπάρχει μια γραμμή κώδικα που είναι διαφορετική. Μπορείτε να το βρείτε; Γιατί δεν έχει σημασία αυτή η διαφορά;
Ελπίζω να διασκεδάσατε! Τα λέμε την επόμενη φορά…
Συνιστάται:
Φροντιστήριο AVR Assembler 2: 4 Βήματα
AVR Assembler Tutorial 2: Αυτό το σεμινάριο είναι συνέχεια του " AVR Assembler Tutorial 1 " Εάν δεν έχετε περάσει από το Σεμινάριο 1, θα πρέπει να σταματήσετε τώρα και να το κάνετε πρώτα. Σε αυτό το σεμινάριο θα συνεχίσουμε τη μελέτη του προγραμματισμού της γλώσσας συναρμολόγησης του atmega328p u
Φροντιστήριο AVR Assembler 1: 5 Βήματα
AVR Assembler Tutorial 1: Αποφάσισα να γράψω μια σειρά σεμιναρίων για τον τρόπο γραφής προγραμμάτων γλώσσας συναρμολόγησης για το Atmega328p που είναι ο μικροελεγκτής που χρησιμοποιείται στο Arduino. Εάν οι άνθρωποι παραμείνουν ενδιαφερόμενοι, θα συνεχίσω να βγάζω ένα την εβδομάδα περίπου, μέχρι να εξαντληθώ
Φροντιστήριο AVR Assembler 6: 3 Βήματα
AVR Assembler Tutorial 6: Καλώς ορίσατε στο Tutorial 6! Το σημερινό σεμινάριο θα είναι σύντομο, όπου θα αναπτύξουμε μια απλή μέθοδο για την επικοινωνία δεδομένων μεταξύ ενός atmega328p και ενός άλλου χρησιμοποιώντας δύο θύρες που τους συνδέουν. Στη συνέχεια, θα πάρουμε τον κύκλο ζαριών από το Tutorial 4 και το Register
Φροντιστήριο AVR Assembler 7: 12 Βήματα
AVR Assembler Tutorial 7: Καλώς ορίσατε στο Tutorial 7! Σήμερα θα δείξουμε πρώτα πώς να καθαρίσουμε ένα πληκτρολόγιο και στη συνέχεια θα δείξουμε πώς να χρησιμοποιούμε τις αναλογικές θύρες εισόδου για επικοινωνία με το πληκτρολόγιο. Αυτό θα το κάνουμε χρησιμοποιώντας διακοπές και ένα μόνο καλώδιο ως εισαγωγή. Θα συνδέσουμε το πληκτρολόγιο ώστε να
Φροντιστήριο AVR Assembler 9: 7 Βήματα
AVR Assembler Tutorial 9: Καλώς ορίσατε στο Tutorial 9. Σήμερα θα δείξουμε πώς να ελέγχετε τόσο μια οθόνη 7 τμημάτων όσο και μια 4ψήφια οθόνη χρησιμοποιώντας τον κωδικό γλώσσας συναρμολόγησης ATmega328P και AVR. Κατά τη διάρκεια αυτής της προσπάθειας, θα πρέπει να κάνουμε εκτροπές σχετικά με τον τρόπο χρήσης της στοίβας