Πίνακας περιεχομένων:

Φροντιστήριο AVR Assembler 2: 4 Βήματα
Φροντιστήριο AVR Assembler 2: 4 Βήματα

Βίντεο: Φροντιστήριο AVR Assembler 2: 4 Βήματα

Βίντεο: Φροντιστήριο AVR Assembler 2: 4 Βήματα
Βίντεο: Embedded Systems 2a 2024, Ιούλιος
Anonim
Φροντιστήριο AVR Assembler 2
Φροντιστήριο AVR Assembler 2

Αυτό το σεμινάριο είναι συνέχεια του "AVR Assembler Tutorial 1"

Εάν δεν έχετε περάσει από το Σεμινάριο 1, θα πρέπει να σταματήσετε τώρα και να το κάνετε πρώτα.

Σε αυτό το σεμινάριο θα συνεχίσουμε τη μελέτη του προγραμματισμού γλώσσας συναρμολόγησης του atmega328p που χρησιμοποιείται στο Arduino's.

Θα χρειαστείτε:

  1. ένα σανίδι Arduino ή απλά ένα κανονικό Arduino όπως στο Tutorial 1
  2. ένα LED
  3. μια αντίσταση 220 ohm
  4. ένα κουμπί
  5. συνδέοντας καλώδια για την κατασκευή του κυκλώματος στο breadboard σας
  6. Εγχειρίδιο σετ εγκατάστασης: www.atmel.com/images/atmel-0856-avr-instruction-s…
  7. Φύλλο δεδομένων: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…

Την πλήρη συλλογή των σεμιναρίων μου μπορείτε να τη βρείτε εδώ:

Βήμα 1: Δημιουργία κυκλώματος

Χτίζοντας το κύκλωμα
Χτίζοντας το κύκλωμα

Πρώτα πρέπει να φτιάξετε το κύκλωμα που θα μελετήσουμε σε αυτό το σεμινάριο.

Εδώ είναι ο τρόπος σύνδεσης:

PB0 (ψηφιακή ακίδα 8) - LED - R (220 ohm) - 5V

PD0 (ψηφιακός ακροδέκτης 0) - κουμπί - GND

Μπορείτε να ελέγξετε ότι η λυχνία LED είναι σωστά προσανατολισμένη συνδέοντάς την με GND αντί για PB0. Αν δεν συμβεί τίποτα, αντιστρέψτε τον προσανατολισμό και το φως θα ανάψει. Στη συνέχεια, συνδέστε το ξανά στο PB0 και συνεχίστε. Η εικόνα δείχνει πώς συνδέεται το arduino του breadboard.

Βήμα 2: Γράφοντας τον Κώδικα Συνέλευσης

Γράφοντας τον Κώδικα Συνέλευσης
Γράφοντας τον Κώδικα Συνέλευσης

Γράψτε τον ακόλουθο κώδικα σε ένα αρχείο κειμένου που ονομάζεται pushbutton.asm και μεταγλωττίστε το με avra όπως κάνατε στο Tutorial 1.

Παρατηρήστε ότι σε αυτόν τον κώδικα έχουμε πολλά σχόλια. Κάθε φορά που ο συναρμολογητής βλέπει ερωτηματικό θα παραλείψει την υπόλοιπη γραμμή και θα συνεχίσει στην επόμενη γραμμή. Είναι καλή πρακτική προγραμματισμού (ειδικά στη γλώσσα συναρμολόγησης!) Να σχολιάζετε έντονα τον κώδικά σας, ώστε όταν επιστρέψετε σε αυτόν στο μέλλον να ξέρετε τι κάνατε. Θα σχολιάσω αρκετά πράγματα στα πρώτα μαθήματα, ώστε να γνωρίζουμε ακριβώς τι συμβαίνει και γιατί. Αργότερα, μόλις γίνουμε λίγο καλύτεροι στην κωδικοποίηση συναρμολόγησης, θα σχολιάσω τα πράγματα με λίγο λιγότερη λεπτομέρεια.

;************************************

? γραμμένο από: 1o_o7; ημερομηνία: 23 Οκτωβρίου 2014; *********************************

.νολόγος

.συμπεριλάβετε "m328Pdef.inc".list.def temp = r16; ορίστε το μητρώο εργασίας r16 ως temp rjmp Init. εκτελέστηκε η πρώτη γραμμή

Μέσα σε αυτό:

ser temp? ορίστε όλα τα bit στη θερμοκρασία σε 1. έξω DDRB, θερμοκρασία ρυθμίζοντας ένα bit ως 1 στο Data Direction I/O. Εγγραφή στο PortB, το οποίο είναι DDRB, ορίζει αυτό. καρφίτσα ως έξοδο, ένα 0 θα ορίσει αυτό το pin ως είσοδο. έτσι εδώ, όλες οι ακίδες PortB είναι έξοδοι (ρυθμισμένες σε 1) ldi temp, 0b11111110; φορτώστε τον «άμεσο» αριθμό στον καταχωρητή θερμοκρασίας. αν ήταν απλά ld τότε το δεύτερο επιχείρημα? θα πρέπει να είναι μια θέση μνήμης αντί για DDRD, temp? mv temp στο DDRD, το αποτέλεσμα είναι ότι το PD0 είναι είσοδο. και τα υπόλοιπα είναι έξοδοι clr temp? όλα τα bit στη θερμοκρασία έχουν ρυθμιστεί σε 0 έξω PortB, temp. ρυθμίστε όλα τα bits (δηλ. καρφίτσες) στο PortB σε 0V ldi temp, 0b00000001. φορτώστε τον άμεσο αριθμό στο temp out PortD, temp. μετακίνηση θερμοκρασίας στο PortD. Το PD0 έχει αντίσταση έλξης. (δηλ. ρυθμισμένο σε 5V) αφού έχει 1 σε αυτό το bit. τα υπόλοιπα είναι 0V από 0's.

Κύριος:

σε θερμοκρασία, PinD; Το PinD διατηρεί την κατάσταση του PortD, αντιγράψτε το στο temp. αν το κουμπί είναι συνδεδεμένο στο PD0 αυτό θα είναι? 0 όταν πατάτε το κουμπί, 1 αλλιώς αφού? Το PD0 έχει αντίσταση έλξης είναι συνήθως στα 5V έξω PortB, θερμοκρασία? στέλνει τα 0 και 1 που διαβάστηκαν παραπάνω στο PortB. αυτό σημαίνει ότι θέλουμε το LED συνδεδεμένο στο PB0, όταν το PD0 είναι ΧΑΜΗΛΟ, ορίζει το PB0 σε LOW και γυρίζει. στη λυχνία LED (αφού η άλλη πλευρά της λυχνίας LED είναι συνδεδεμένη σε 5V και αυτό θα ρυθμίσει το PB0 σε 0V, έτσι θα ρέει ρεύμα) rjmp Main; επιστρέφει στην αρχή του Main

Παρατηρήστε ότι αυτή τη φορά όχι μόνο έχουμε πολλά περισσότερα σχόλια στον κώδικά μας, αλλά έχουμε επίσης μια ενότητα κεφαλίδας που δίνει κάποιες πληροφορίες σχετικά με το ποιος το έγραψε και πότε γράφτηκε. Ο υπόλοιπος κώδικας χωρίζεται επίσης σε τμήματα.

Αφού συντάξετε τον παραπάνω κώδικα, πρέπει να τον φορτώσετε στον μικροελεγκτή και να δείτε ότι λειτουργεί. Η λυχνία LED πρέπει να ανάψει ενώ πατάτε το κουμπί και στη συνέχεια να σβήσει ξανά όταν το αφήσετε. Έδειξα πώς φαίνεται στην εικόνα.

Βήμα 3: Ανάλυση γραμμικού κώδικα του κώδικα

Θα παραλείψω τις γραμμές που είναι απλώς σχόλια καθώς ο σκοπός τους είναι αυτονόητος.

.νολόγος

.συμπεριλάβετε τη λίστα "m328Pdef.inc"

Αυτές οι τρεις γραμμές περιλαμβάνουν το αρχείο που περιέχει τους ορισμούς Register και Bit για το ATmega328P που προγραμματίζουμε. Η εντολή.nolist λέει στον συναρμολογητή να μην συμπεριλάβει αυτό το αρχείο στο αρχείο pushbutton.lst που παράγει όταν το συναρμολογείτε. Απενεργοποιεί την επιλογή καταχώρισης. Αφού συμπεριλάβουμε το αρχείο, ενεργοποιούμε ξανά την επιλογή καταχώρισης με την εντολή.list. Ο λόγος που το κάνουμε αυτό είναι επειδή το αρχείο m328Pdef.inc είναι αρκετά μεγάλο και δεν χρειάζεται πραγματικά να το δούμε στο αρχείο λίστας. Ο συναρμολογητής μας, avra, δεν δημιουργεί αυτόματα ένα αρχείο λίστας και αν το θέλουμε, θα το συναρμολογήσουμε χρησιμοποιώντας την ακόλουθη εντολή:

avra -l pushbutton.lst pushbutton.asm

Εάν το κάνετε αυτό, θα δημιουργηθεί ένα αρχείο που ονομάζεται pushbutton.lst και αν εξετάσετε αυτό το αρχείο θα διαπιστώσετε ότι εμφανίζει τον κώδικα του προγράμματος σας μαζί με επιπλέον πληροφορίες. Αν κοιτάξετε τις επιπλέον πληροφορίες, θα δείτε ότι οι γραμμές ξεκινούν με ένα C: ακολουθούμενο από τη σχετική διεύθυνση στο εξάγωνο του σημείου όπου τοποθετείται ο κωδικός στη μνήμη. Ουσιαστικά ξεκινά στις 000000 με την πρώτη εντολή και αυξάνεται από εκεί με κάθε επόμενη εντολή. Η δεύτερη στήλη μετά τη σχετική θέση στη μνήμη είναι ο δεκαεξαδικός κώδικας για την εντολή που ακολουθείται από τον εξάγωνο κώδικα για το όρισμα της εντολής. Θα συζητήσουμε περαιτέρω αρχεία καταλόγων σε μελλοντικά σεμινάρια.

.def temp = r16; ορίστε το μητρώο εργασίας r16 ως θερμοκρασία

Σε αυτήν τη γραμμή χρησιμοποιούμε την οδηγία συναρμολόγησης ".def" για να ορίσουμε τη μεταβλητή "temp" ως ίση με τον καταχωρητή εργασίας r16. " Θα χρησιμοποιήσουμε τον καταχωρητή r16 ως αυτόν που αποθηκεύει τους αριθμούς που θέλουμε να αντιγράψουμε σε διάφορες θύρες και καταχωρητές (στους οποίους δεν είναι δυνατή η άμεση εγγραφή).

Άσκηση 1: Προσπαθήστε να αντιγράψετε έναν δυαδικό αριθμό απευθείας σε μια θύρα ή ειδικό μητρώο όπως το DDRB και δείτε τι συμβαίνει όταν προσπαθείτε να συγκεντρώσετε τον κώδικα.

Ένας καταχωρητής περιέχει ένα byte (8 bits) πληροφοριών. Ουσιαστικά είναι συνήθως μια συλλογή SR-Latches, το καθένα είναι ένα "bit" και περιέχει ένα 1 ή ένα 0. Μπορούμε να το συζητήσουμε (και μάλιστα να φτιάξουμε ένα!) Αργότερα σε αυτή τη σειρά. Mayσως αναρωτιέστε τι είναι ένα "μητρώο εργασίας" και γιατί επιλέξαμε το r16. Θα το συζητήσουμε σε ένα μελλοντικό σεμινάριο όταν βουτήξουμε στο τέλμα των εσωτερικών του τσιπ. Προς το παρόν θέλω να καταλάβετε πώς να κάνετε πράγματα όπως η εγγραφή κώδικα και το φυσικό υλικό του προγράμματος. Στη συνέχεια, θα έχετε ένα πλαίσιο αναφοράς από αυτήν την εμπειρία που θα κάνει ευκολότερη την κατανόηση της μνήμης και της καταχώρισης των ιδιοτήτων του μικροελεγκτή. Συνειδητοποιώ ότι τα περισσότερα εισαγωγικά εγχειρίδια και συζητήσεις το κάνουν αντίστροφα, αλλά διαπίστωσα ότι το να παίξεις ένα βιντεοπαιχνίδι για λίγο για να αποκτήσεις μια παγκόσμια προοπτική πριν διαβάσεις το εγχειρίδιο οδηγιών είναι πολύ πιο εύκολο από το να διαβάσεις πρώτα το εγχειρίδιο.

rjmp Init; εκτελέστηκε η πρώτη γραμμή

Αυτή η γραμμή είναι ένα "σχετικό άλμα" στην ετικέτα "Init" και δεν είναι πραγματικά απαραίτητο εδώ, καθώς η επόμενη εντολή είναι ήδη στο Init, αλλά την συμπεριλαμβάνουμε για μελλοντική χρήση.

Μέσα σε αυτό:

ser temp? ορίστε όλα τα bit στη θερμοκρασία σε 1.

Μετά την ετικέτα Init εκτελούμε μια εντολή "set register". Αυτό θέτει και τα 8 μπιτ του καταγραφέα "temp" (που θυμάστε ότι είναι r16) σε 1. Έτσι η θερμοκρασία περιέχει τώρα 0b11111111.

έξω DDRB, θερμοκρασία ορίζοντας ένα bit ως 1 στον καταχωρητή εισόδου/εξόδου δεδομένων κατεύθυνσης

? για το PortB, το οποίο είναι DDRB, ορίζει αυτό το pin ως έξοδο. Το 0 θα ορίσει αυτό το pin ως είσοδο. έτσι εδώ, όλες οι καρφίτσες PortB είναι έξοδοι (ορίζεται σε 1)

Ο καταχωρητής DDRB (Data Direction Register for PortB) αναφέρει ποιες ακίδες στο PortB (δηλαδή PB0 έως PB7) ορίζονται ως είσοδο και ποιες ορίζονται ως έξοδο. Δεδομένου ότι έχουμε τον πείρο PB0 συνδεδεμένο στο LED μας και τα υπόλοιπα δεν είναι συνδεδεμένα με τίποτα, θα θέσουμε όλα τα bits στο 1, δηλαδή όλα είναι έξοδοι.

ldi temp, 0b11111110; φορτώστε τον «άμεσο» αριθμό στον καταχωρητή temp

? αν ήταν απλά ld τότε το δεύτερο επιχείρημα θα? πρέπει να είναι θέση μνήμης

Αυτή η γραμμή φορτώνει τον δυαδικό αριθμό 0b11111110 στον καταχωρητή temp.

έξω DDRD, θερμοκρασία mv temp στο DDRD, το αποτέλεσμα είναι ότι το PD0 είναι είσοδος και

? τα υπόλοιπα είναι έξοδοι

Τώρα ρυθμίζουμε τον Καταχωρητή Κατεύθυνσης Δεδομένων για το PortD από τη θερμοκρασία, δεδομένου ότι η θερμοκρασία εξακολουθεί να περιέχει 0b11111110 βλέπουμε ότι το PD0 θα οριστεί ως ακίδα εισόδου (εφόσον υπάρχει 0 στο ακροδεξιό σημείο) και τα υπόλοιπα ορίζονται ως έξοδοι επειδή υπάρχουν 1 σε αυτά τα σημεία.

clr temp? όλα τα bit στη θερμοκρασία έχουν οριστεί σε 0

έξω PortB, temp? ρυθμίστε όλα τα bits (δηλ. τις ακίδες) στο PortB σε 0V

Αρχικά "καθαρίζουμε" την θερμοκρασία καταχωρητή που σημαίνει ότι θέτουμε όλα τα δυαδικά ψηφία στο μηδέν. Στη συνέχεια, το αντιγράφουμε στον καταχωρητή PortB ο οποίος ορίζει 0V σε όλες αυτές τις ακίδες. Το μηδέν σε ένα bit PortB σημαίνει ότι ο επεξεργαστής θα διατηρήσει αυτόν τον ακροδέκτη στα 0V, ενώ ένας σε ένα bit θα προκαλέσει τη ρύθμιση του pin σε 5V.

Άσκηση 2: Χρησιμοποιήστε ένα πολύμετρο για να ελέγξετε αν όλες οι ακίδες στο PortB είναι στην πραγματικότητα μηδενικές. Συμβαίνει κάτι περίεργο με το PB1; Καμιά ιδέα γιατί μπορεί να είναι αυτό; (παρόμοια με την Άσκηση 4 παρακάτω και ακολουθήστε τον κωδικό…) Άσκηση 3: Αφαιρέστε τις δύο παραπάνω γραμμές από τον κωδικό σας. Το πρόγραμμα εξακολουθεί να λειτουργεί σωστά; Γιατί;

ldi temp, 0b00000001; φορτώστε τον άμεσο αριθμό στη θερμοκρασία

έξω PortD, θερμοκρασία μετακίνηση θερμοκρασίας στο PortD. Το PD0 είναι στα 5V (έχει αντίσταση έλξης). αφού έχει 1 σε εκείνο το κομμάτι τα υπόλοιπα είναι 0V. Άσκηση 4: Αφαιρέστε τις δύο παραπάνω γραμμές από τον κωδικό σας. Το πρόγραμμα εξακολουθεί να λειτουργεί σωστά; Γιατί; (Αυτό διαφέρει από την Άσκηση 3 παραπάνω. Δείτε το διάγραμμα pin out. Ποια είναι η προεπιλεγμένη ρύθμιση DDRD για το PD0; (Δείτε τη σελίδα 90 του φύλλου δεδομένων

Αρχικά "φορτώνουμε άμεσα" τον αριθμό 0b00000001 στη θερμοκρασία. Το "άμεσο" μέρος είναι εκεί, επειδή φορτώνουμε έναν αριθμό επάνω στη θερμοκρασία και όχι έναν δείκτη σε μια θέση μνήμης που περιέχει τον αριθμό προς φόρτωση. Σε αυτή την περίπτωση θα χρησιμοποιούσαμε απλά το "ld" και όχι το "ldi". Στη συνέχεια, στέλνουμε αυτόν τον αριθμό στο PortD που ορίζει το PD0 σε 5V και το υπόλοιπο σε 0V.

Τώρα έχουμε ορίσει τις καρφίτσες ως είσοδο ή έξοδο και έχουμε ορίσει τις αρχικές τους καταστάσεις είτε ως 0V είτε ως 5V (ΧΑΜΗΛΗ ή Υ HIGHΗΛΗ) και έτσι εισάγουμε τώρα τον "βρόχο" του προγράμματος μας.

Κύρια: σε θερμοκρασία, PinD; Το PinD διατηρεί την κατάσταση του PortD, αντιγράψτε το στο temp

? αν το κουμπί είναι συνδεδεμένο στο PD0 τότε αυτό θα είναι? a 0 όταν πατάτε το κουμπί, 1 αλλιώς αφού? Το PD0 έχει αντίσταση έλξης, είναι κανονικά στα 5V

Ο καταχωρητής PinD περιέχει την τρέχουσα κατάσταση των ακίδων PortD. Για παράδειγμα, εάν συνδέσατε ένα καλώδιο 5V στο PD3, τότε στον επόμενο κύκλο ρολογιού (κάτι που συμβαίνει 16 εκατομμύρια φορές ανά δευτερόλεπτο αφού έχουμε συνδέσει τον μικροελεγκτή με σήμα ρολογιού 16MHz) το bit PinD3 (από την τρέχουσα κατάσταση PD3) θα γινόταν 1 αντί 0. Έτσι σε αυτήν τη γραμμή αντιγράφουμε την τρέχουσα κατάσταση των ακίδων στο temp.

έξω PortB, temp? στέλνει τα 0 και 1 που διαβάστηκαν παραπάνω στο PortB

? αυτό σημαίνει ότι θέλουμε το LED συνδεδεμένο στο PB0, οπότε? όταν το PD0 είναι ΧΑΜΗΛΟ, θα ρυθμίσει το PB0 σε LOW και θα γυρίσει. στο LED (η άλλη πλευρά της λυχνίας LED είναι συνδεδεμένη. σε 5V και αυτό θα ρυθμίσει το PB0 σε 0V έτσι ώστε να ρέει το ρεύμα)

Τώρα στέλνουμε την κατάσταση των ακίδων στο PinD στην έξοδο PortB. Ουσιαστικά, αυτό σημαίνει ότι το PD0 θα στείλει ένα 1 στο PortD0 εκτός αν πατηθεί το κουμπί. Σε αυτήν την περίπτωση, δεδομένου ότι το κουμπί είναι συνδεδεμένο στη γείωση, η καρφίτσα θα είναι στα 0V και θα στείλει ένα 0 στο PortB0. Τώρα, αν κοιτάξετε το διάγραμμα κυκλώματος, 0V στο PB0 σημαίνει ότι το LED θα ανάψει αφού η άλλη πλευρά του είναι στα 5V. Εάν δεν πατάμε το κουμπί, έτσι ώστε να αποσταλεί ένα 1 στο PB0, αυτό θα σημαίνει ότι έχουμε 5V στο PB0 και επίσης 5V στην άλλη πλευρά του LED και έτσι δεν υπάρχει πιθανή διαφορά και δεν θα ρέει ρεύμα και έτσι Η λυχνία LED δεν θα ανάψει (σε αυτή την περίπτωση είναι μια λυχνία LED που είναι μια δίοδος και έτσι το ρεύμα ρέει μόνο προς μία κατεύθυνση ανεξάρτητα από ό, τι και αν είναι).

rjmp Main; επιστρέφει στην Έναρξη

Αυτό το σχετικό άλμα μας επιστρέφει στην κύρια ετικέτα μας και ελέγχουμε ξανά το PinD και ούτω καθεξής. Ελέγχετε κάθε 16 εκατομμυριοστά του δευτερολέπτου εάν πιέζεται το κουμπί και ρυθμίζετε ανάλογα το PB0.

Άσκηση 5: Τροποποιήστε τον κωδικό σας έτσι ώστε το LED σας να είναι συνδεδεμένο στο PB3 αντί για PB0 και να δείτε ότι λειτουργεί. Άσκηση 6: Συνδέστε το LED σας σε GND αντί για 5V και τροποποιήστε τον κωδικό σας ανάλογα.

Βήμα 4: Συμπέρασμα

Σε αυτό το σεμινάριο ερευνήσαμε περαιτέρω τη γλώσσα συναρμολόγησης για το ATmega328p και μάθαμε πώς να ελέγχετε ένα LED με ένα κουμπί. Ειδικότερα μάθαμε τις ακόλουθες εντολές:

ser Register ορίζει όλα τα bits ενός καταχωρητή σε 1

Ο καταχωρητής clr ορίζει όλα τα bits ενός καταχωρητή σε 0

στο μητρώο, i/o register αντιγράφει τον αριθμό από ένα i/o μητρώο σε μητρώο εργασίας

Στο επόμενο σεμινάριο θα εξετάσουμε τη δομή του ATmega328p και τους διάφορους καταχωρητές, λειτουργίες και πόρους που περιέχονται σε αυτό.

Πριν συνεχίσω με αυτά τα σεμινάρια, θα περιμένω και θα δω το επίπεδο ενδιαφέροντος. Εάν υπάρχουν πολλοί άνθρωποι που πραγματικά απολαμβάνουν να μαθαίνουν πώς να κωδικοποιούν προγράμματα για αυτόν τον μικροεπεξεργαστή στη γλώσσα συναρμολόγησης, τότε θα συνεχίσω και θα κατασκευάσω πιο περίπλοκα κυκλώματα και θα χρησιμοποιήσω πιο ισχυρό κώδικα.

Συνιστάται: