Έλεγχος θυρών μέσω μητρώων atmega. Προγραμματισμός μικροελεγκτών AVR σε C. Θύρα Α καταχωρητής δεδομένων - PORTA

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Bit 7 - Ενεργοποίηση όλων των διακοπών. Για να ενεργοποιηθούν οι διακοπές, αυτό το bit πρέπει να οριστεί σε 1. Η ενεργοποίηση μιας συγκεκριμένης διακοπής ελέγχεται από τους καταχωρητές μάσκας διακοπής EIMSK και TIMSK. Εάν αυτό το bit διαγραφεί (=0), τότε καμία από τις διακοπές δεν αντιμετωπίζεται. Το bit διαγράφεται από το υλικό μετά από μια διακοπή και έχει ρυθμιστεί ώστε να ενεργοποιεί τη διακοπή αργότερα με την εντολή RETI.
· Bit 6 – Αποθήκευση bit αντιγράφου. Οι οδηγίες αντιγραφής bit BLD και BST χρησιμοποιούν αυτό το bit ως πηγή και προορισμό για λειτουργίες bit. Η εντολή BST αντιγράφει ένα bit του γενικού καταχωρητή στο bit T, η εντολή BLD αντιγράφει το bit T στο bit του γενικού καταχωρητή.
· Bit 5 – Half Carry Flag. Υποδεικνύει μια μεταφορά μεταξύ τετραδίων κατά την εκτέλεση ενός αριθμού αριθμητικών πράξεων.
· Bit 4 - Bit Sign. Το S bit έχει την τιμή του αποτελέσματος της λειτουργίας XOR (N(+)V) στις σημαίες αρνητικής τιμής (N) και το συμπλήρωμα των δύο της σημαίας υπερχείλισης (V).

· Bit 3 – Συμπλήρωμα δύο της σημαίας υπερχείλισης. Υποστηρίζει αριθμητική συμπλήρωμα δύο.
· Bit 2 – Αρνητική σημαία. Αυτή η σημαία υποδεικνύει ένα αρνητικό αποτέλεσμα ενός αριθμού αριθμητικών και λογικών πράξεων.
· Bit 1 – Σημαία μηδέν. Αυτή η σημαία υποδεικνύει το μηδενικό αποτέλεσμα ενός αριθμού αριθμητικών και λογικών πράξεων.
· Bit 0 – Σημαία μεταφοράς. Αυτή η σημαία υποδεικνύει μεταφορά κατά τη διάρκεια αριθμητικών και λογικών πράξεων.

Ο μικροελεγκτής AT90S8535 διαθέτει 4 παράλληλες θύρες I/O A, B, C και D.
Η θύρα Α είναι μια αμφίδρομη θύρα 8 bit. Η αλληλεπίδραση με τη θύρα Α πραγματοποιείται μέσω τριών καταχωρητών στο χώρο I/O της μνήμης δεδομένων: καταχωρητής δεδομένων - PORTA, $1B ($ 3B), καταχωρητής κατεύθυνσης δεδομένων - DDRA, $ 1A ($ 3A), καταχωρητής δεδομένων εισόδου - PINA, 19 $ (39 $). Ο καταχωρητής PINA είναι μόνο για ανάγνωση, ενώ οι καταχωρητές PORTA και DDRA είναι για ανάγνωση-εγγραφή. Το μητρώο PINA δεν είναι μητρώο με την πλήρη έννοια της λέξης. Η πρόσβαση σε αυτό παρέχει μια ανάγνωση της φυσικής κατάστασης κάθε pin θύρας. Η θύρα Α χρησιμοποιείται επίσης για την εισαγωγή αναλογικών σημάτων A/D.

Μητρώο δεδομένων Port A -ΠΟΡΤΑ

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Port A Data Direction Register -DDRA

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Καταχωρητής δεδομένων εισόδου Θύρα Α -PINA

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Η θύρα Β είναι μια αμφίδρομη θύρα εισόδου/εξόδου 8 bit. Όπως και με τη θύρα Α, η επικοινωνία με τη θύρα Β γίνεται μέσω τριών καταχωρητών στο χώρο I/O της μνήμης δεδομένων: καταχωρητής δεδομένων - PORTB, $18($38), καταχωρητής κατεύθυνσης δεδομένων - DDRB, $17($37) και καταχωρητής δεδομένων εισόδου - PINB, 16 $ (36 $). Ο καταχωρητής PINB είναι μόνο για ανάγνωση. Το μητρώο PINB δεν είναι μητρώο με την πλήρη έννοια της λέξης. Η πρόσβαση σε αυτό παρέχει μια ανάγνωση της φυσικής κατάστασης κάθε pin θύρας. Οι ακροδέκτες της θύρας B μπορούν να εκτελέσουν τις εναλλακτικές λειτουργίες που εμφανίζονται στον Πίνακα 1. 2.1.

Πίνακας 2.1. Εναλλακτικές λειτουργίες πείρου θύρας B

Καρφίτσα θύρας

Εναλλακτική λειτουργία

T0 - Είσοδος χρονοδιακόπτη/μετρητή ρολογιού 0

T1 - Είσοδος χρονοδιακόπτη/μετρητή 1 ρολογιού

AIN0 - θετικός ακροδέκτης του συγκριτή

AIN1 - αρνητικός ακροδέκτης του συγκριτή

– Είσοδος επιλογής υποτελούς SPI

MOSI - Ρύθμιση κύριας εξόδου/υποτελούς εισόδου SPI

Ρύθμιση κύριας εισόδου/εξόδου MISO - SPI

Σήμα ρολογιού SCK - SPI

Όταν χρησιμοποιείτε ακίδες για εναλλακτικές λειτουργίες, οι καταχωρητές PORTB, DDRB πρέπει να ρυθμιστούν ανάλογα.

Μητρώο δεδομένων λιμένασιPORTB

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Μητρώο Κατεύθυνσης Δεδομένων Θύρα Β –DDRB

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Θύρα Β Μητρώο δεδομένων εισόδου –PINB

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Η θύρα C είναι μια αμφίδρομη θύρα εισόδου/εξόδου 8 bit. Ακριβώς όπως οι θύρες A και B, η αλληλεπίδραση με τη θύρα C πραγματοποιείται μέσω τριών καταχωρητών στο χώρο I/O της μνήμης δεδομένων: ο καταχωρητής δεδομένων είναι PORTC, 15 $ (35 $), ο καταχωρητής κατεύθυνσης δεδομένων είναι DDRC, 14 $ (34 $ ) και ο καταχωρητής δεδομένων εισόδου είναι PINC, $13($33). Ο καταχωρητής PINC είναι μόνο για ανάγνωση, ενώ οι καταχωρητές PORTC και DDRC είναι για ανάγνωση-εγγραφή. Το μητρώο PINC δεν είναι μητρώο με την πλήρη έννοια της λέξης. Η πρόσβαση σε αυτό παρέχει μια ανάγνωση της φυσικής κατάστασης κάθε pin θύρας.
Η θύρα C έχει μόνο δύο ακίδες που μπορούν να εκτελέσουν εναλλακτικές λειτουργίες: οι ακίδες PC6 και PC7 εκτελούν τις λειτουργίες TOSC1 και TOSC2 του Timer/Counter 2.

Μητρώο δεδομένων λιμέναντοPORTC

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Port C Data Direction Register –DDRC

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Μητρώο δεδομένων εισόδου θύρας C -PINC

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Η θύρα D είναι μια αμφίδρομη θύρα εισόδου/εξόδου 8 bit. Όπως και με τις θύρες A, B και C, η επικοινωνία με τη θύρα D γίνεται μέσω τριών καταχωρητών στο χώρο I/O της μνήμης δεδομένων: ο καταχωρητής δεδομένων είναι PORTD, $12($32), ο καταχωρητής κατεύθυνσης δεδομένων είναι DDRD, $11($31), και ο καταχωρητής δεδομένων εισόδου – PIND, $10($30). Ο καταχωρητής PIND παρέχει δυνατότητα ανάγνωσης, ενώ οι καταχωρητές PORTD και DDRD παρέχουν δυνατότητα ανάγνωσης και εγγραφής. Ο καταχωρητής PIND δεν είναι μητρώο με την πλήρη έννοια της λέξης. Η πρόσβαση σε αυτό παρέχει μια ανάγνωση της φυσικής κατάστασης κάθε pin θύρας.
Οι ακροδέκτες της θύρας D μπορούν να εκτελέσουν τις εναλλακτικές λειτουργίες που εμφανίζονται στον Πίνακα 1. 2.2.

Πίνακας 2.2. Εναλλακτικές λειτουργίες ακίδας θύρας D

Καρφίτσα θύρας

Εναλλακτική λειτουργία

RxD - Είσοδος δέκτη UART

TxD - Έξοδος πομπού UART

INT0 - είσοδος εξωτερικής διακοπής 0

INT1 - είσοδος εξωτερικής διακοπής 1

OC1B - Πείρο σύγκρισης εξόδου χρονοδιακόπτη/μετρητή 1

OC1A - Έξοδος σύγκρισης εξόδου Α του χρονοδιακόπτη/μετρητή 1

ICP - Timer/Counter 1 Capture Trigger Input

OC2 - ακίδα σύγκρισης εξόδου χρονοδιακόπτη/μετρητή 2

Όταν χρησιμοποιείτε ακίδες για εναλλακτικές λειτουργίες, οι καταχωρητές PORTD, DDRD πρέπει να ρυθμιστούν ανάλογα.

Μητρώο δεδομένων λιμέναρεPORTD

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Καταχωρητής κατεύθυνσης δεδομένων λιμέναρεDDRD

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Καταχωρητής εισόδου θύραςρεPIND

Κομμάτι

Διαβάζω γράφω

Αρχική τιμή

Δεδομένου ότι η εργασία που εξετάζεται είναι η πρώτη, για να αποκτήσουν οι μαθητές τις δεξιότητες για να εργαστούν με το εργαστηριακό συγκρότημα, όλοι οι μαθητές κάνουν πρώτα την ίδια εργασία. Από τους χώρους εργασίας τους, εισάγουν στον Η/Υ την ίδια εργασία αφαίρεσης του αριθμού 3 από τον αριθμό 5, που δίνεται στην παράγραφο 1.5.3.1. Μετά τη σύνταξη του προγράμματος, γράφεται στον μικροελεγκτή του χώρου εργασίας και επιδεικνύεται η εργασία του στον εκπαιδευτικό.
Μετά από μια τέτοια γνωριμία με το συγκρότημα, ο μαθητής προχωρά στην εκτέλεση μιας ατομικής εργασίας. Εάν υπάρχει χρόνος, ο δάσκαλος μπορεί να περιπλέξει την ατομική εργασία.

Οι πράξεις bitwise βασίζονται σε λογικές πράξεις, τις οποίες έχουμε ήδη καλύψει νωρίτερα. Παίζουν βασικό ρόλο στον προγραμματισμό μικροελεγκτών AVR και άλλων τύπων. Σχεδόν κανένα πρόγραμμα δεν μπορεί να κάνει χωρίς τη χρήση πράξεων bitwise. Μέχρι στιγμής, τα έχουμε αποφύγει σκόπιμα για να διευκολύνουμε την εκμάθηση του προγραμματισμού MK.

Σε όλα τα προηγούμενα άρθρα, προγραμματίσαμε μόνο θύρες I/O και δεν χρησιμοποιήσαμε πρόσθετους ενσωματωμένους κόμβους, όπως χρονόμετρα, μετατροπείς αναλογικού σε ψηφιακό, διακοπές και άλλες εσωτερικές συσκευές χωρίς τις οποίες το MK χάνει όλη του την ισχύ.

Πριν προχωρήσετε στο mastering των ενσωματωμένων συσκευών MK, πρέπει να μάθετε πώς να ελέγχετε ή να ελέγχετε μεμονωμένα bit των καταχωρητών AVR MK. Προηγουμένως, πραγματοποιούσαμε έναν έλεγχο ή ορίσαμε τα bit ολόκληρου του καταχωρητή ταυτόχρονα. Ας δούμε ποια είναι η διαφορά και μετά συνεχίζουμε περαιτέρω.

Λειτουργίες bitwise

Τις περισσότερες φορές, κατά τον προγραμματισμό μικροελεγκτών AVR, το χρησιμοποιούσαμε, καθώς έχει μεγαλύτερη ευκρίνεια σε σύγκριση με και είναι καλά κατανοητό για αρχάριους προγραμματιστές MK. Για παράδειγμα, πρέπει να ορίσουμε μόνο το 3ο bit της θύρας D. Για αυτό, όπως ήδη γνωρίζουμε, μπορούμε να χρησιμοποιήσουμε τον ακόλουθο δυαδικό κώδικα:

PORTD = 0b00001000;

Ωστόσο, με αυτήν την εντολή, ορίζουμε το 3ο bit σε ένα και μηδενίζουμε όλα τα άλλα (0, 1, 2, 4, 5, 6 και 7ο). Και τώρα ας φανταστούμε την κατάσταση ότι το 6ο και το 7ο ψηφίο χρησιμοποιούνται ως είσοδοι ADC και αυτή τη στιγμή ένα σήμα από κάποια συσκευή φτάνει στις αντίστοιχες εξόδους του MK και επαναφέρουμε αυτά τα σήματα χρησιμοποιώντας την παραπάνω εντολή. Ως αποτέλεσμα, ο μικροελεγκτής δεν τα βλέπει και πιστεύει ότι τα σήματα δεν ήρθαν. Επομένως, αντί για μια τέτοια εντολή, θα πρέπει να χρησιμοποιήσουμε μια άλλη που θα ορίζει μόνο το 3ο bit σε ένα, ενώ δεν θα επηρεάζει τα υπόλοιπα bit. Για αυτό, συνήθως χρησιμοποιείται η ακόλουθη λειτουργία bitwise:

PORT |= (1<<3);

Θα αναλύσουμε αναλυτικά τη σύνταξή του παρακάτω. Και τώρα ένα άλλο παράδειγμα. Ας υποθέσουμε ότι πρέπει να ελέγξουμε την κατάσταση του 3ου bit του καταχωρητή PIND, ελέγχοντας έτσι την κατάσταση του κουμπιού. Εάν αυτό το bit μηδενιστεί, τότε γνωρίζουμε ότι το κουμπί είναι πατημένο και στη συνέχεια εκτελείται ο κωδικός εντολής, ο οποίος αντιστοιχεί στην κατάσταση του πατημένου κουμπιού. Προηγουμένως, θα χρησιμοποιούσαμε τον ακόλουθο συμβολισμό:

αν (πίνδ == 0b00000000)

(οποιοσδήποτε κωδικός)

Ωστόσο, με τη βοήθειά του, δεν ελέγχουμε ούτε ένα, - το 3ο, αλλά όλα τα bit του καταχωρητή PIND ταυτόχρονα. Επομένως, ακόμα κι αν πατηθεί το κουμπί και γίνει επαναφορά του επιθυμητού bit, αλλά εκείνη τη στιγμή λαμβάνεται ένα σήμα σε οποιαδήποτε άλλη ακίδα θύρας D, το αντίστοιχο bit θα οριστεί σε ένα και η συνθήκη στις παρενθέσεις θα είναι ψευδής. Ως αποτέλεσμα, ο κωδικός στα σγουρά άγκιστρα δεν θα εκτελεστεί ακόμη και όταν πατηθεί το κουμπί. Επομένως, για να ελέγξετε την κατάσταση ενός μεμονωμένου 3ου bit του καταχωρητή PIND, θα πρέπει να χρησιμοποιηθεί μια λειτουργία bitwise:

εάν (~PIND & (1<<3))

(οποιοσδήποτε κωδικός)

Για να εργαστείτε με μεμονωμένα bit του μικροελεγκτή, η γλώσσα προγραμματισμού C έχει στο οπλοστάσιό της, με την οποία μπορείτε να αλλάξετε ή να ελέγξετε την κατάσταση ενός ή περισσότερων μεμονωμένων bit ταυτόχρονα.

Ρύθμιση ενός μόνο bit

Για να ορίσετε ένα μεμονωμένο bit, όπως η θύρα D, χρησιμοποιείται μια λειτουργία bitwise OR. Αυτό χρησιμοποιήσαμε στην αρχή του άρθρου.

PORTD = 0b00011100; // αρχική τιμή

PORTD = PORTD | (ένας<<0); применяем побитовую ИЛИ

PORT |= (1<<0); // сокращенная форма записи

PORTD == 0b00011101; // αποτέλεσμα

Αυτή η εντολή θέτει το bit στο μηδέν και αφήνει τα υπόλοιπα αμετάβλητα.

Για παράδειγμα, ας ορίσουμε το 6ο bit της θύρας D.

PORTD = 0b00011100; // αρχική κατάσταση θύρας

PORT |= (1<<6); //

PORTD == 0b01011100; // αποτέλεσμα

Για να γράψετε ένα έως πολλά ξεχωριστά bit ταυτόχρονα, για παράδειγμα, μηδέν, έκτη και έβδομη θύρα σιισχύει ο ακόλουθος συμβολισμός.

PORTB = 0b00011100; // αρχική τιμή

PORTB |= (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101; // αποτέλεσμα

Επαναφορά (μηδενισμός) μεμονωμένων bit

Για να επαναφέρετε ένα bit, χρησιμοποιούνται τρεις εντολές που συζητήθηκαν προηγουμένως ταυτόχρονα: .

Ας επαναφέρουμε το 3ο bit του καταχωρητή PORTC και ας αφήσουμε το υπόλοιπο αμετάβλητο.

PORTC = 0b00011100;

PORTC &= ~(1<<3);

PORTC == 0b00010100;

Ας εκτελέσουμε παρόμοιες ενέργειες για το 2ο και το 4ο ψηφίο:

PORTC = 0b00111110;

PORTC &= ~((1<<2) | (1<<4));

PORTC == 0b00101010;

Εναλλαγή του ρυθμού

Εκτός από τη ρύθμιση και την επαναφορά, χρησιμοποιείται επίσης μια χρήσιμη εντολή που αλλάζει ένα bit στην αντίθετη κατάσταση: ένα στο μηδέν και αντίστροφα. Αυτή η λογική λειτουργία χρησιμοποιείται ευρέως στην κατασκευή διαφόρων εφέ φωτισμού, για παράδειγμα, όπως μια γιρλάντα Πρωτοχρονιάς. Σκεφτείτε το παράδειγμα της ΠΟΡΤΑ

ΠΟΡΤΑ = 0b00011111;

ΠΟΡΤΑ ^= (1<<2);

ΠΟΡΤΑ == 0b00011011;

Αλλάξτε την κατάσταση του μηδενικού, του δεύτερου και του έκτου bit:

ΠΟΡΤΑ = 0b00011111;

ΠΟΡΤΑ ^= (1<<0) | (1<<2) | (1<<6);

ΠΟΡΤΑ == 0b01011010;

Έλεγχος της κατάστασης ενός μεμονωμένου bit. Να σας υπενθυμίσω ότι ο έλεγχος (σε αντίθεση με την εγγραφή) μιας θύρας I/O πραγματοποιείται με την ανάγνωση δεδομένων από τον καταχωρητή PIN.

Η πιο κοινή δοκιμή εκτελείται με μία από τις δύο εντολές βρόχου: if και while. Γνωρίζουμε ήδη νωρίτερα αυτούς τους τελεστές.

Έλεγχος της εκφόρτισης για την παρουσία λογικού μηδενός (επαναφορά) με αν

εάν (0==(PIND & (1<<3)))

Εάν το τρίτο bit της θύρας D διαγραφεί, εκτελείται ο Code1. Διαφορετικά, εκτελείται ο Code2.

Παρόμοιες ενέργειες εκτελούνται με και με αυτήν τη μορφή εγγραφής:

εάν (~PIND & (1<<3))

Έλεγχος της εκφόρτισης για παρουσία λογικής μονάδας (ρύθμισης) με αν

εάν (0 != (PIND & (1<<3)))

εάν (PIND & (1<<3))

Οι δύο παραπάνω βρόχοι λειτουργούν παρόμοια, αλλά λόγω της ευελιξίας της γλώσσας προγραμματισμού C, μπορούν να γραφτούν διαφορετικά. Η πράξη != σημαίνει όχι ίση. Εάν το τρίτο bit της θύρας εισόδου/εξόδου PD έχει οριστεί (ένα), τότε εκτελείται το Code1, εάν όχι, το Code2.

Αναμονή για λίγη επαναφορά με ενώ

ενώ (PIND & (1<<5))

Ο Κώδικας1 θα εκτελεστεί όσο έχει οριστεί το 5ο bit του καταχωρητή PIND. Η επαναφορά του θα ξεκινήσει την εκτέλεση του Code2.

Αναμονή για τη ρύθμιση του bit ενώ

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

Για πολλή ώρα φύγαμε χωρίς προσοχή Μικροελεγκτές AVR, και τώρα ήρθε η ώρα να διορθωθεί αυτή η παρεξήγηση! Όσο για άλλους ελεγκτές, θα εξετάσουμε σταδιακά διάφορα περιφερειακά AVR, πρώτα τη θεωρία, κάθε είδους καταχωρητές και τέλος, μικρά παραδείγματα.

Ως IDE χρησιμοποιώ AVR Studio 5, η έκτη έκδοση AVR StudioΔεν το έχω δοκιμάσει καν, δεν έχω συναντήσει εργασίες για AVR τόσο συχνά τελευταία) Γενικά, δεν είναι κακό να έχετε εγκαταστήσει και το AVR Studio 4, γιατί μερικές φορές συμβαίνει να χρειάζεται να προγραμματίσετε τον ελεγκτή από AVR Studio 5δεν φαίνεται δυνατό. Μόλις πρόσφατα, ήθελα να αναβοσβήσω το ATMega2560 χρησιμοποιώντας τον προγραμματιστή STK500 και αυτό αποδείχθηκε αδύνατο μετά το Studio 5) Παρέμεινε καλά από τα παλιά του AVR Studio 4 και το πρόβλημα λύθηκε μέσα σε λίγα λεπτά.

Τι άλλο να πω; .. Ναι, καταρχήν, αυτό είναι όλο, μπορείτε να ασχοληθείτε;)

Φυσικά, θα ξεκινήσουμε με GPIO - θύρες εισόδου-εξόδου, γιατί χωρίς αυτά δεν υπάρχει πουθενά) Και πριν περιγράψω τα μητρώα που ελέγχουν τη λειτουργία των λιμανιών, θα σημειώσω μερικές «ηλεκτρικές» στιγμές.

Στην είσοδο κάθε σκέλους του μικροελεγκτή, οι προσεκτικοί προγραμματιστές βάζουν μερικές διόδους που θα πρέπει να σώσουν τον μικροελεγκτή σε περίπτωση υπέρβασης της επιτρεπόμενης τάσης. ΑΛΛΑ! Στην πραγματικότητα, όλα δεν είναι τόσο ρόδινα και αν, για παράδειγμα, εφαρμοστούν 7,5 Volt στην είσοδο του μικροελεγκτή, τότε κανείς και τίποτα δεν θα βοηθήσει τον ελεγκτή, έχει επαληθευτεί από τη δική μας εμπειρία. Επομένως, όλα τα πειράματα πρέπει να εκτελούνται προσεκτικά)

Τώρα για εγγραφές. Όλη η εργασία με θύρες I/O σε AVR συγκεντρώνεται σε τρεις καταχωρητές - DDRx, PORTx, PINx. Ο χαρακτήρας "x" αντικαθίσταται από το αντίστοιχο όνομα θύρας (A,B…). Δηλαδή, αν θέλουμε να δουλέψουμε με τη θύρα Α του μικροελεγκτή, τότε χρειαζόμαστε τους καταχωρητές DDRA, PORTA, PINA. Αν θέλουμε να δουλέψουμε με την πέμπτη ακίδα της θύρας Α (PA5), τότε μας ενδιαφέρει το πέμπτο bit των καταχωρητών που αναφέρθηκαν παραπάνω. Όπως μπορείτε να δείτε, όλα είναι πολύ απλά) Απομένει μόνο να καταλάβουμε τι και πού να γράψουμε, για τι είναι υπεύθυνο καθένα από αυτά τα μητρώα. Ξεκινήσαμε λοιπόν...

Καταχωρητής DDRx.

Το DDRx είναι υπεύθυνο για την κατεύθυνση λειτουργίας των αντίστοιχων ακίδων του μικροελεγκτή. Κάθε pin μπορεί να είναι είτε είσοδος είτε έξοδος, δεν υπάρχει τρίτο. Για να ρυθμίσετε τις παραμέτρους της εξόδου ώστε να λειτουργεί στη λειτουργία εισαγωγής καταχωρητή DDR, πρέπει να γράψετε 0 για αυτήν τη θύρα και 1 για την έξοδο. Ας υποθέσουμε ότι πρέπει να ρυθμίσουμε το PA6 ως είσοδο και το PA3 ως έξοδο. Τι κάνουμε? Σωστά, ορίσαμε το τρίτο bit του καταχωρητή DDRA σε 1 και γράφουμε 0 στο 6ο bit του ίδιου καταχωρητή DDRA. Τέλος!

Εγγραφή PINx.

Δεν μπορούμε να γράψουμε τίποτα σε αυτό το μητρώο, προορίζεται αποκλειστικά για την ανάγνωση δεδομένων. Αυτός ο καταχωρητής περιέχει πληροφορίες σχετικά με το επίπεδο σήματος στην αντίστοιχη θύρα. Όπως θυμόμαστε, ο μικροελεγκτής είναι μια ψηφιακή συσκευή και τα σήματα στα πόδια του μπορεί να είναι είτε υψηλά (λογικό 1) είτε χαμηλά (λογικό 0). Αν θέλουμε να μάθουμε τι έχουμε εκεί στην είσοδο PB4, τότε μας ενδιαφέρει το τέταρτο bit του καταχωρητή PINB.

Εγγραφή PORTx.

Αυτό το μητρώο είναι λίγο πιο περίπλοκο από τα προηγούμενα. Η λειτουργικότητά του εξαρτάται από την κατεύθυνση στην οποία λειτουργούν οι ακίδες του μικροελεγκτή. Εάν η ακίδα χρησιμοποιείται ως είσοδος, τότε ο καταχωρητής PORTx καθορίζει τον τύπο εισόδου. Υπάρχουν δύο πιθανές επιλογές εδώ:

PORTx = 1 - με αυτήν τη διαμόρφωση, λαμβάνουμε μια είσοδο με ένα pull up (PullUp)

PORTX = 0 - είσοδος υψηλής σύνθετης αντίστασης (Hi-Z) - αυτό σημαίνει ότι η αντίσταση της θύρας είναι τόσο υψηλή που μπορεί να θεωρηθεί άπειρη)

Ας συνεχίσουμε λοιπόν με τον καταχωρητή PORTx. Εάν η έξοδος λειτουργεί ως έξοδος και ο καταχωρητής PORTx είναι ένας, τότε η έξοδος θα είναι υψηλό επίπεδο σήματος, ομοίως, PORTx \u003d 0 - χαμηλό επίπεδο.

Ας πάρουμε ένα μικρό παράδειγμα για να το καταλάβουμε 😉

Ας διαμορφώσουμε τον ακροδέκτη PC4 ώστε να λειτουργεί σε λειτουργία εισόδου pull-up. Για να το κάνετε αυτό, γράψτε 0 (λειτουργία εισόδου) στο τέταρτο bit του καταχωρητή DDRC και ορίστε το τέταρτο bit στον καταχωρητή PORTC σε 1 (ανασύρετε). Αυτό είναι όλο.

Καταρχήν, αυτό είναι το μόνο που αφορά τη θεωρία, δεν θα εμβαθύνουμε περαιτέρω. Μένει να τηρήσουμε τις παραδόσεις και να παίξουμε με τη δίοδο. Αφήστε τη δίοδο να συνδεθεί στον ακροδέκτη PV5. Ας τον κάνουμε να αναβοσβήνει! Και πρώτα απ 'όλα, ας δημιουργήσουμε ένα έργο. Εγώ, όπως είπα ήδη, χρησιμοποιώ το AVR Studio 5 και ως χειριστήριο θα επιλέξω το αγαπημένο μου ATMega88)

// Συνδέστε το απαιτούμενο αρχείο#περιλαμβάνω /*******************************************************************/ // Μια απλή συνάρτηση για τη δημιουργία καθυστέρησης void delay (unsigned int time ) ( unsigned int i = 0 ; for (i = 0 ; i< time ; i++ ) ; } /*******************************************************************/ // Αρχικοποίηση της εξόδου μας, λειτουργεί στην έξοδο void initAll() (DDRB = 0b00100000 ;) /*******************************************************************/ // Το πραγματικό σώμα της συνάρτησης main(). int main(void ) ( initAll() ; while (1 ) ( // Ενεργοποιήστε τη δίοδο PORTB = 0b00100000 ; // Καθυστέρηση ανάπαυσης (50000 ) ; // Απενεργοποιήστε τη δίοδο PORTB = 0b00000000 ; καθυστέρηση (5000 )) /*******************************************************************/

Έτσι είναι η πρώτη μας επικοινωνία Μικροελεγκτές AVR. Σύντομα θα εξετάσουμε, αν είναι δυνατόν, ολόκληρη την περιφέρειά τους, και μετά μπορούμε να ανακινήσουμε κάτι πιο ενδιαφέρον 😉

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

Σε άλλα μαθήματα εκεί, σχεδόν από τις πρώτες γραμμές, κάνουν κάτι σημαντικό - αναβοσβήνουν με μια δίοδο και λένε ότι αυτό είναι το Hello World μας. Και εδώ? Gide;;;

Ναι, ναι, ναι, σε καταλαβαίνω. Επιπλέον, μάλλον έχετε ήδη τρέξει στους ανταγωνιστές σας και τους ανοιγοκλείσατε μια δίοδο;)))) Τίποτα, συγχωρέσιμο.

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

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

Εργαλεία
Η εργασία με θύρες συνήθως σημαίνει εργασία με bits. Αυτό είναι για να βάλεις λίγο, να επαναφέρεις λίγο, να αντιστρέψεις λίγο. Ναι, φυσικά, υπάρχουν βολικές εντολές στο assembler

cbi/sbi, αλλά λειτουργούν μόνο σε ένα μικρό εύρος διευθύνσεων (από 0 έως 1 F, οπότε ας γράψουμε πρώτα καθολικές μακροεντολές για να μπορούμε να τις χρησιμοποιήσουμε στο μέλλον και να μην ανησυχούμε για το χώρο διευθύνσεων.

Οι μακροεντολές θα ονομάζονται:

  • SETB byte, bit, θερμοκρασία
  • CLRB byte, bit, θερμοκρασία
  • INVB byte, bit, temp, temp2

Επιπλέον, όταν εργάζεστε με bit του κατώτερου RVV (διεύθυνση 0-1F), η τιμή της παραμέτρου TEMP ενδέχεται να μην προσδιορίζεται - δεν θα αντικατασταθεί ούτως ή άλλως. Με εξαίρεση τις εντολές αντιστροφής, εκεί θα χρειαστούν ενδιάμεσοι καταχωρητές.

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

  • SETBM byte, bit
  • CLRBM byte, bit
  • INVBM byte, bit

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

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 < 0x20 SBI @0,@1 .else .if @0<0x40 PUSH R17 IN R17,@0 ORI R17,1<<@1 OUT @0,R17 POP R17 .else PUSH R17 LDS R17,@0 ORI R17,1<<@1 STS @0,R17 POP R17 .endif .endif .ENDM ;SET BIT with REG .MACRO SETB .if @0 < 0x20 ; Low IO SBI @0,@1 .else .if @0<0x40 ; High IO IN @2,@0 ORI @2,1<<@1 OUT @0,@2 .else ; Memory LDS @2,@0 ORI @2,1<<@1 STS @0,@2 .endif .endif .ENDM ;............................................................. ;Clear BIT with REG .MACRO CLRB .if @0 < 0x20 ; Low IO CBI @0,@1 .else .if @0<0x40 ; High IO IN @2,@0 ANDI @2,~(1<<@1) OUT @0,@2 .else ; Memory LDS @2,@0 ANDI @2,~(1<<@1) STS @0,@2 .endif .endif .ENDM ;Clear BIT with STACK .MACRO CLRBM .if @0 < 0x20 CBI @0,@1 .else .if @0<0x40 PUSH R17 IN R17,@0 ANDI R17,~(1<<@1) OUT @0,R17 POP R17 .else PUSH R17 LDS R17,@0 ANDI R17,~(1<<@1) STS @0,R17 POP R17 .endif .endif .ENDM ;............................................................. .MACRO INVB .if @0 < 0x40 IN @2,@0 LDI @3,1<<@1 EOR @3,@2 OUT @0,@3 .else LDS @2,@0 LDI @3,1<<@1 EOR @2,@3 STS @0,@2 .endif .ENDM .MACRO INVBM .if @0 < 0x40 PUSH R16 PUSH R17 IN R16,@0 LDI R17,1<<@1 EOR R17,R16 OUT @0,R17 POP R17 POP R16 .else PUSH R16 PUSH R17 LDS R16,@0 LDI R17,1<<@1 EOR R17,R16 STS @0,R17 POP R17 POP R16 .endif .ENDM ;= End macro.inc ========================================

;= Έναρξη macro.inc ======================================== ;SET BIT με στοίβα .MACRO SETBM .αν @0< 0x20 SBI @0,@1 .else .if @0<0x40 PUSH R17 IN R17,@0 ORI R17,1<<@1 OUT @0,R17 POP R17 .else PUSH R17 LDS R17,@0 ORI R17,1<<@1 STS @0,R17 POP R17 .endif .endif .ENDM ;SET BIT with REG .MACRO SETB .if @0 < 0x20 ; Low IO SBI @0,@1 .else .if @0<0x40 ; High IO IN @2,@0 ORI @2,1<<@1 OUT @0,@2 .else ; Memory LDS @2,@0 ORI @2,1<<@1 STS @0,@2 .endif .endif .ENDM ;............................................................. ;Clear BIT with REG .MACRO CLRB .if @0 < 0x20 ; Low IO CBI @0,@1 .else .if @0<0x40 ; High IO IN @2,@0 ANDI @2,~(1<<@1) OUT @0,@2 .else ; Memory LDS @2,@0 ANDI @2,~(1<<@1) STS @0,@2 .endif .endif .ENDM ;Clear BIT with STACK .MACRO CLRBM .if @0 < 0x20 CBI @0,@1 .else .if @0<0x40 PUSH R17 IN R17,@0 ANDI R17,~(1<<@1) OUT @0,R17 POP R17 .else PUSH R17 LDS R17,@0 ANDI R17,~(1<<@1) STS @0,R17 POP R17 .endif .endif .ENDM ;............................................................. .MACRO INVB .if @0 < 0x40 IN @2,@0 LDI @3,1<<@1 EOR @3,@2 OUT @0,@3 .else LDS @2,@0 LDI @3,1<<@1 EOR @2,@3 STS @0,@2 .endif .ENDM .MACRO INVBM .if @0 < 0x40 PUSH R16 PUSH R17 IN R16,@0 LDI R17,1<<@1 EOR R17,R16 OUT @0,R17 POP R17 POP R16 .else PUSH R16 PUSH R17 LDS R16,@0 LDI R17,1<<@1 EOR R17,R16 STS @0,R17 POP R17 POP R16 .endif .ENDM ;= End macro.inc ========================================

Με την πάροδο του χρόνου, όταν γράφετε σε assembler, υπάρχουν πολλές τέτοιες μακροεντολές. Βγάζονται σε ξεχωριστό αρχείο και συνδέονται απλώς με οποιοδήποτε από τα έργα σας και η σύνταξη κώδικα γίνεται εύκολη και ευχάριστη.

Αλλά πίσω στον κώδικα,
Ας αναβοσβήνουμε ένα LED, τελικά;

Φυσικά, δεν υπάρχει πρόβλημα. Οι λυχνίες LED είναι ήδη τοποθετημένες στην πλακέτα επίδειξης, γιατί να μην τις χρησιμοποιήσετε; Κρέμονται στις ακίδες της θύρας PD4, PD5, PD7. Απλά πρέπει να φοράτε άλτες.

; Internal Hardware Init ===================================== SETB DDRD,4,R16 ; DDRD.4 = 1 SETB DDRD,5,R16 ; DDRD.5 = 1 SETB DDRD,7,R16 ; DDRD.7 = 1 ; Τέλος εσωτερικής εισαγωγής υλικού ====================================

Μένει να ανάψουμε τις διόδους μας. Φωτίζονται γράφοντας bits στον καταχωρητή PORT. Αυτό γίνεται ήδη στην κύρια ενότητα του προγράμματος.

; Κύρια ===================================================== ======= Κύριο: SETB PORTD,4,R16 ; Αναμμένο LED1 SETB PORTD,7,R16; Αναμμένο LED3 JMP Κύριο ; Κύριο τέλος ================================================= ====

Κάνουμε μεταγλώττιση, μπορείτε να το εκτελέσετε στο tracer, θα δείτε αμέσως πώς αλλάζουν τα bit. Αναβοσβήνουμε ... και αφού κάνετε κλικ στο RESET και ξεφορτώσετε το bootloader (εκτός βέβαια αν έχετε) θα δείτε αυτή την εικόνα:


Και για την έκδοση II


Σε! Είναι κάπως βαρετό. Ας τους κλείσουμε το μάτι.

Ας αντικαταστήσουμε απλώς τις μακροεντολές μας.

; Κύρια ===================================================== ======= Κύριο: SETB PORTD,4,R16 ; Αναμμένο LED1 INVB PORTD,7,R16,R17 ; Invert LED3 JMP Main ; Κύριο τέλος ================================================= ====

Αναμμένο, αναβοσβήνει...

Αλλά τα σύκα - και τα δύο είναι αναμμένα, αλλά το ένα είναι λίγο αμυδρό. Πραγματικά τρεμοπαίζει, αλλά πολύ πολύ γρήγορα. Αν ρίξετε έναν παλμογράφο στην έξοδο του PD7, θα δείτε ότι το επίπεδο αλλάζει εκεί με μια ξέφρενη συχνότητα:


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

; Κύρια ===================================================== ======= Κύριο: SETB PORTD,4,R16 ; Αναμμένο LED1 INVB PORTD,7,R16,R17 ; Invert LED3 RCALL Delay JMP Main ; Κύριο τέλος ================================================= ==== ; = Διαδικασία================================================ == .equ LowByte = 255 .equ MedByte = 255 .equ HighByte = 255 Καθυστέρηση: LDI R16,LowByte ; Φόρτωση τριών byte LDI R17,MedByte ; Το απόσπασμά μας LDI R18,HighByte βρόχος: SUBI R16,1 ; Αφαιρέστε 1 SBCI R17.0 ; Αφαιρέστε μόνο C SBCI R18.0 ; Αφαίρεση μόνο C BRCC Loop ; Εάν δεν υπάρχει μεταφορά - μετάβαση RET ; Διαδικασία λήξης ==============================================

Το αναβοσβήσαμε, το εκτοξεύσαμε... Ω ναι, τώρα το αναβοσβήσιμο θα γίνει αντιληπτό.

Με τις παραμέτρους 255.255.255, η ταχύτητα κλείστρου στα 8 MHz θα είναι περίπου 2,1 δευτερόλεπτα. Μπορείτε να αυξήσετε το μήκος της καθυστέρησης κατά μερικά ακόμη byte. Στη συνέχεια, μπορείτε να φορτίσετε τουλάχιστον μια ώρα.

Αλλά αυτή η μέθοδος είναι ελαττωματική, τώρα θα σας δείξω γιατί.

Ας προσθέσουμε ένα κουμπί. Αφήστε το LED3 να αναβοσβήνει κατά την αναστροφή. Και θα το κάνουμε έτσι ώστε όταν πατηθεί το κουμπί, το LED1 είναι αναμμένο και όταν απελευθερωθεί, το LED2 είναι αναμμένο.

Ας πάρουμε το ρολόι A ως κουμπί, συνδέστε το στη θύρα PD6.


Για την έκδοση II είναι παρόμοια. Απλώς πάρτε το κουμπί από την ομάδα κουμπιών και συνδέστε την έξοδο PD6 του ελεγκτή στην ακίδα COL1 στο πληκτρολόγιο.

Απλά προσέξτε τους βραχυκυκλωτήρες που βρίσκονται στους βραχυκυκλωτήρες του πεδίου κουμπιών. Τα μπλε είναι. Και επίσης ένα δυσδιάκριτο μαύρο jumper, το οποίο δείχνει το δεξί βέλος. Συνδέει την αριστερή στήλη των κουμπιών με τη γείωση. Ακουμπάει στις ακίδες GND και ROW1. Όλα είναι υπογεγραμμένα στον πίνακα.

Ο έλεγχος του κουμπιού γίνεται με την εντολή SBIC, αλλά πρώτα πρέπει να αρχικοποιηθεί. Κάντε DDR=0, PORT=1 - pull-up είσοδο.

Προσθέστε αυτές τις γραμμές στην ενότητα προετοιμασίας (Internal Hardware Init):

; Κύρια ===================================================== ======= Κύρια: SBIS PIND,6 ; Εάν πατηθεί το κουμπί - μετάβαση RJMP BT_Push SETB PORTD,5 ; Ανάβει LED2 CLRB PORTD,4 ; Απενεργοποίηση LED1 Επόμενο: INVB PORTD,7,R16,R17 ; Invert LED3 RCALL Delay JMP Main BT_Push: SETB PORTD,4 ; Ανάβει LED1 CLRB PORTD,5 ; Απενεργοποίηση LED2 RJMP Επόμενο ; Κύριο τέλος ================================================= ====

Λοιπόν, λειτουργεί. Το κουμπί είναι πατημένο - οι δίοδοι αλλάζουν. Ο τρίτος κλείνει το μάτι χαρούμενα. Υπάρχει όμως ένα αλίευμα:

Το πρόγραμμα επιβραδύνεται! Πάτησα το κουμπί, αλλά η εικόνα δεν άλλαξε, πρέπει να περιμένετε, κρατήστε το... Γιατί; Και αυτό οφείλεται στο bydlokoding μας.

Θυμάσαι που σου είπα ότι οι ηλίθιες καθυστερήσεις στις οποίες ο ΜΚ δεν κάνει τίποτα είναι κολασμένο κακό; Εδώ! Τώρα το είδατε μόνοι σας. Λοιπόν, το κακό πρέπει να καταπολεμηθεί. Πως? Λοιπόν, το είπα ήδη - να κάνω έναν συνεχή κύκλο με σημαίες. Τουλάχιστον προσθέστε λίγη χρήσιμη δουλειά στην καθυστέρηση μας.

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

Υπάρχει ένα τύμπανο με καρφιά που προεξέχουν και ελατήρια σε διαφορετικούς τόνους. Τα νύχια στριφογυρίζουν, τα ελατήρια συσπώνται — κουδουνίζουν. Αποδεικνύεται raskolbasny Mouzon. Και τι γίνεται αν το hurdy-gurdy μας επεκταθεί σε κορδέλα. Δεν είναι αλήθεια ότι τα νύχια μοιάζουν με μονάδες; ;))))

Η κασέτα θα είναι ένας μετρητής που μετράει από το μηδέν, ας πούμε, στο FF.FF.FF.FF και μετά ξανά στο μηδέν ή κάποια άλλη τιμή, όσο χρειαζόμαστε και θα κάνουμε. Και οι υπορουτίνες μας θα παίζουν το ρόλο των ελατηρίων, κολλώντας στα σωστά σημεία - συγκρίνοντας τη σταθερά τους με την τρέχουσα τιμή του μετρητή.

Συνέπεσε; Ας κάνουμε ένα ΣΚΑΛΜΑ!

Μένει μόνο να συνταγογραφήσουμε για τον χρονικό κύκλο του hurdy-gurdy μας πού και τι πρέπει να ξεκινήσει. Και εδώ υπάρχει ένα πολύ βολικό χαρακτηριστικό - για να δημιουργήσουμε κυκλικές ακολουθίες, αρκεί να πιάσουμε ένα κομμάτι.

Ας υποθέσουμε ότι το όργανο της κάννης μετράει από το 0 έως το 1000 και πρέπει να αναβοσβήνουμε τη δίοδο 10 φορές. Δεν είναι απαραίτητο να κολλήσετε 10 χειριστές με διαφορετικές τιμές. Ένα είναι αρκετό, αλλά για να πιάσει την τιμή **10. Όλα τα άλλα δεν είναι σημαντικά για εμάς. Και θα λειτουργεί στα 0010, 0110, 0210, 0310, 0410, 0510, 0610, 0710, 0810, 0910. Τα πιο συχνά διαστήματα χωρίζονται επίσης όπως χρειαζόμαστε, αρκεί να μπούμε σε άλλη κατηγορία. Εδώ είναι απαραίτητο μόνο να μην ξεχάσετε να κόψετε τα ανώτερα ψηφία του nafig για να μην παρεμβαίνετε.

Ας αρχίσουμε. Αρχικά, ας δημιουργήσουμε τον μετρητή μας στο τμήμα δεδομένων:

LDS R16,CCNT LDS R17,CCNT+1 LDS R18,CCNT+2 LDS R19,CCNT+3

Όλα, τώρα στο R16 το νεότερο byte του μετρητή μας και στο R19 το παλαιότερο.

Οι καταχωρητές μπορούν να ωθηθούν στη στοίβα εκ των προτέρων, αλλά θα σας δώσω καλύτερες συμβουλές - όταν γράφετε ένα πρόγραμμα, σκεφτείτε τον αλγόριθμο με τέτοιο τρόπο ώστε να χρησιμοποιείτε τους καταχωρητές ως συνεχές TEMP του οποίου τα δεδομένα είναι σχετικά μόνο εδώ και τώρα. Και το τι θα τους συμβεί στην επόμενη διαδικασία δεν είναι πλέον σημαντικό - όλα όσα πρέπει να αποθηκευτούν στη μνήμη RAM.

Μπορείτε να το κάνετε ως εξής:

LDI R20.1 ; Χρειαζόμαστε ένα CLR R15. Και επίσης ένα μηδέν. ΠΡΟΣΘΗΚΗ R16,R20 ; Προσθέτουμε 1 εάν ο καταχωρητής είναι 255, τότε θα είναι C ADC R17, R15. Προσθήκη 0+C ADC R18,R15; Προσθέστε 0+С ADC R19,R15 ; Προσθέστε 0+C

Χρειάστηκε να ξοδέψουμε δύο ακόμη καταχωρητές για να αποθηκεύσουμε τις σταθερές πρόσθεσης. Όλα από το γεγονός ότι το AVR δεν μπορεί να προσθέσει καταχωρητές με άμεσο αριθμό. Αλλά μπορεί να διαβάσει.

Έχω ήδη δείξει ότι R-(-1)=R+1, αλλά κανείς δεν μας απαγορεύει να κανονίσουμε την ίδια τεχνική εδώ - να κάνουμε πρόσθεση μέσω αφαίρεσης.

1 2 3 4 SUBI R16,(-1) SBCI R17,(-1) SBCI R18,(-1) SBCI R19,(-1)

SUBI R16,(-1) SBCI R17,(-1) SBCI R18,(-1) SBCI R19,(-1)

Θα μας δώσει μια αύξηση ενός αριθμού τεσσάρων byte R19:R18:R17:R16

Και τώρα θα σας δείξω κάποια ακέραια μαγεία.
Γιατί θα λειτουργήσει; Ρίξτε μια ματιά μόνοι σας:

Το SUBI R16, (-1) είναι, στην πραγματικότητα, το R16 - 255 και σχεδόν σε όλες τις περιπτώσεις θα μας δώσει δάνειο από την επόμενη κατηγορία - C. Και τον αριθμό με τον οποίο θα μείνουν περισσότερα στο μητρώο.

Εκείνοι. δείτε πώς λειτουργούν αυτά τα μαθηματικά, θυμηθείτε τον αριθμό σε πρόσθετους κωδικούς. Θα δείξω σε τετραψήφιο δεκαδικό παράδειγμα. Έχουμε ΜΟΝΟ ΤΕΣΣΕΡΙΣ ΔΙΑΦΟΡΕΣ, ούτε περισσότερο, ούτε λιγότερο. Ένας αρνητικός αριθμός είναι 0-1 σωστά; ΕΝΤΑΞΕΙ.

1 C 0000-1=9999+C

Εκείνοι. Εμείς, σαν να λέγαμε, αφαιρέσαμε 1 από το πενταψήφιο 1 C 0000, αλλά έχουμε μόνο τέσσερα ψηφία! Έλαβε πρόσθετο κωδικό 9999 και σημαία δανείου C (που υποδεικνύει ότι υπήρχε δάνειο)

Εκείνοι. στα ακέραια μαθηματικά μας 9999=-1 :) Είναι εύκολο να ελέγξετε -1+1 = 0 Σωστά;

9999+1 = 1 C 0000 Σωστά! :))) Και το 1 πιο σημαντικό κομμάτι απλά δεν χωρούσε στη χωρητικότητα και μπήκε στη σημαία μεταφοράς C, η οποία σηματοδοτεί επίσης υπερχείλιση.

Εντάξει, τώρα ας πάρουμε και κάνουμε R-(-1). Έστω R=4

1 C 0004-9999 = 0005+C

Το πήραν λοιπόν και το πρόσθεσαν μέσω της αφαίρεσης. Απλά μαγεία, σωστά; ;)

Το αστείο του assembler είναι ότι αυτά είναι απλώς εντολές, και όχι δόγμα και όχι κανόνας. Και εντολές που περιλαμβάνουν υπολογισμούς σημάτων μπορούν να χρησιμοποιηθούν οπουδήποτε, αρκεί να δίνουν το αποτέλεσμα που χρειαζόμαστε!

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

Η σημαία C δεν θα εμφανιστεί μόνο όταν σημειώσουμε το 255 (9999 στο δεκαδικό παράδειγμα), τότε θα είναι 255-255 = 0 και μόνο το Z θα εμφανιστεί, αλλά δεν το χρειαζόμαστε.

STS CCNT,R16 STS CCNT+1,R17 STS CCNT+2,R18 STS CCNT+3,R19

Ο κωδικός προσαύξησης μιας σταθεράς τεσσάρων byte στη μνήμη μπορεί να διπλωθεί σε μια μακροεντολή ώστε να μην ακατασταθεί ο κώδικας

; Κύρια ===================================================== ======= Κύρια: SETB PORTD,4 ; Αναμμένο LED1 INVB PORTD,7,R16,R17 ; Αντεστραμμένο LED3 Επόμενο: INCM CCNT JMP Main

Ξεκινήστε τη λειτουργία εντοπισμού σφαλμάτων και τοποθετήστε ένα σημείο διακοπής (F9) στην ετικέτα Main και οδηγήστε τον κέρσορα στο πρώτο σημείο διακοπής.

0xB6(CCNT) 0x9F(CCNT+1) 0x04(CCNT+2) 0x00(CCNT+3)

Μένει τώρα μόνο να συγκρίνουμε τον αριθμό με αυτό το καστ.

Πώς να συγκρίνετε; Ναι, είναι αρκετά απλό. Όλα εξαρτώνται από το τι θέλουμε να πάρουμε. Αν υπάρχει ΕΝΑ συμβάν για ΟΛΗ την περίοδο του παγκόσμιου μετρητή του hurdy-gurdy μας, τότε βλακωδώς, byte byte. Σε αυτήν την περίπτωση, η δίοδος σας θα αναβοσβήνει ένα δευτερόλεπτο μετά την εκκίνηση και, στη συνέχεια, θα περιμένετε μισή ώρα μέχρι να υπερχειλίσει ολόκληρος ο μετρητής τεσσάρων byte.

Για να αναβοσβήνει κάθε δευτερόλεπτο, πρέπει να καλύπτετε τα υψηλά bit του καθολικού μετρητή κατά τη σύγκριση, σαν να έχει πλάτος bit όχι 32 bit, αλλά λιγότερο (και ξεχειλίζει πιο συχνά).

Τα χαμηλότερα byte συγκρίνονται ως έχουν, και το παλαιότερο είναι μόνο μέχρι το μέγιστο ψηφίο του, τα υπόλοιπα πρέπει να αποκοπούν.

Εκείνοι. το πιο σημαντικό ψηφίο για αυτήν την περίπτωση είναι CCNT+2=0x04 εάν σε δυαδική αναπαράσταση τότε 0x04 = 00000 100 λοιπόν, έχουμε έναν τετραψήφιο μετρητή, που σημαίνει ένα γεγονός με μάσκα

00 04 9F B6 ( 00000000 00000 100 10011111 10110110)

πριν από την υπερχείλιση θα υπάρξει dofiga πολλές φορές. Βλέπετε, τόνισα τα μηδενικά με έντονη γραφή. Δεν θα συγκρίνουμε καθόλου το παλαιότερο, αλλά πριν από το παλαιότερο, είναι απαραίτητο να σπρώξουμε AND στη μάσκα 00000111 για να κόψουμε τα high bits.

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

LDS R16,CCNT ; Φορτώνουμε αριθμούς σε καταχωρητές LDS R17, CCNT+1 LDS R18, CCNT+2 ANDI R18,0x07 ; Επιβάλλουμε μάσκα CPI R16,0xB6. Σύγκριση byte προς byte BRNE NoMatch CPI R17.0x9F BRNE NoMatch CPI R18.0x04 BRNE NoMatch ; Εάν ταιριάζει, τότε κάνουμε την ενέργεια Match: INVB PORTD,7,R16,R17 ; Αντεστραμμένο LED3 ; Δεν ταίριαξε - μην το κάνεις :) NoMatch: Επόμενο: INCM CCNT ; Γυρίζοντας το όργανο κάννης JMP Main

Σε, η λήψη τώρα αναβοσβήνει. Δεν υπάρχουν αμβλύτητα, τίποτα δεν κρέμεται πουθενά, και ο κύριος κύκλος πετάει με ένα σφύριγμα, απλά έχετε χρόνο να γυρίσετε το τύμπανο hurdy-gurdy :)

Απλώς αναβοσβήνει αισθητά πιο αργά από ό,τι θέλαμε. Όχι 1 δευτερόλεπτο, αλλά 8. Λοιπόν, τι θέλατε - προσθέτοντας τη διαδικασία σύγκρισης, επιμηκύναμε τον κύκλο κατά μερικές ακόμη εντολές. Και τώρα εκτελείται όχι για 25 κύκλους, αλλά για 36. Υπολογίστε ξανά όλους τους αριθμούς :)))))))

Αλλά αυτό δεν είναι το πιο ttimes! Το αστείο είναι ότι έχετε μέρος του κώδικα που εκτελείται, και κάποιο όχι - εντολές σύγκρισης και μετάβασης. Επομένως, είναι ευκολότερο να υπολογίσετε με ακρίβεια την καθυστέρηση ανά κύκλους - πρέπει να υπολογίσετε για κάθε επανάληψη πότε και πόσες μεταβάσεις θα έχετε, πόσους κύκλους θα χρειαστούν ...

Και αν ο κωδικός είναι ακόμη μεγαλύτερος, τότε τελικά ο σωλήνας και το σφάλμα συσσωρεύονται με κάθε επανάληψη!

Αλλά αν προσθέσετε τον κωδικό επεξεργασίας του κουμπιού:

; Κύρια ===================================================== ======= Κύρια: SBIS PIND,6 ; Εάν πατηθεί το κουμπί - μετάβαση RJMP BT_Push SETB PORTD,5 ; Ανάβει LED2 CLRB PORTD,4 ; Απενεργοποίηση LED1 Επόμενο: LDS R16,CCNT ; Φόρτωση αριθμών σε καταχωρητές LDS R17,CCNT+1 LDS R18,CCNT+2 ANDI R18.0x07 CPI R16.0xB6 ; Σύγκριση byte προς byte BRNE NoMatch CPI R17.0x9F BRNE NoMatch CPI R18.0x04 BRNE NoMatch ; Εάν ταιριάζει, τότε κάνουμε την ενέργεια Match: INVB PORTD,7,R16,R17 ; Αντεστραμμένο LED3 ; Δεν ταίριαξε - μην το κάνεις :) NoMatch: NOP INCM CCNT JMP Κύριο BT_Push: SETB PORTD,4 ; Ανάβει LED1 CLRB PORTD,5 ; Απενεργοποίηση LED2 RJMP Επόμενο ; Κύριο τέλος ================================================= ====

Τότε θα δούμε ότι δεν έχουν μείνει ίχνη από τα φρένα. Τα κουμπιά ανταποκρίνονται αμέσως στο πάτημα και η λυχνία LED αναβοσβήνει μόνη της. Multitasking! :)

Γενικά, το hurdy-gurdy δεν είναι κατάλληλο όπου χρειάζονται ακριβείς υπολογισμοί. Αλλά αν η εργασία είναι από τη σειρά "πρέπει να τραντάζεσαι περιοδικά και δεν έχει σημασία πόσο ακριβώς", τότε αυτό είναι. Επειδή δεν καταλαμβάνει πόρους υλικού όπως ένα χρονόμετρο.

Για παράδειγμα, σαρώνετε περιοδικά το πληκτρολόγιο, ας πούμε, κάθε 2048 περιστροφές του κύριου βρόχου. Υπολογίστε μόνοι σας ποιον αριθμό πρέπει να φορτώσετε για σύγκριση και ποια μάσκα να εφαρμόσετε :)

Μπορείτε να κάνετε λήψη και να ρίξετε μια ματιά, να το εντοπίσετε για να δείτε πώς περιστρέφονται όλα.

Και για ακριβείς υπολογισμούς χρόνου, υπάρχουν χρονόμετρα. Υπάρχει όμως μια ξεχωριστή συζήτηση για αυτούς.

  • φροντιστήριο

Λειτουργία θυρών I/O

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

Ένα παράδειγμα θα εξεταστεί σε έναν μικροελεγκτή ATMega8 .

Θα γράψουμε το πρόγραμμα Atmel Studio 6.0 .

Θα μιμηθούν το κύκλωμα μέσα Proteus 7 Professional .

Ο μικροελεγκτής επικοινωνεί με τον έξω κόσμο μέσω θυρών εισόδου/εξόδου. Το σχήμα θύρας I/O υποδεικνύεται στο φύλλο δεδομένων:

Αλλά είναι αρκετά δύσκολο για έναν αρχάριο να καταλάβει το σχήμα. Ας απλοποιήσουμε λοιπόν το διάγραμμα:

Κάθε θύρα μικροελεγκτή AVR (συνήθως ονομάζεται A, B και μερικές φορές C ή ακόμα και D) έχει 8 bit, καθένα από τα οποία συνδέεται σε μια συγκεκριμένη ακίδα του πλαισίου. Κάθε θύρα έχει τρεις ειδικούς καταχωρητές DDRx, PORTxΚαι PINx(όπου x είναι το γράμμα της θύρας A, B, C ή D). Σκοπός των μητρώων:

DDRx– Ρυθμίστε τα bits της θύρας x για είσοδο ή έξοδο.

PORTx– Έλεγχος της κατάστασης των εξόδων θύρας x (εάν το αντίστοιχο bit έχει διαμορφωθεί ως έξοδο) ή συνδέοντας μια εσωτερική αντίσταση έλξης (αν το αντίστοιχο bit έχει διαμορφωθεί ως είσοδος).

PINx–Διαβάστε τα λογικά επίπεδα bit της θύρας x.

PINхnείναι το μητρώο ανάγνωσης. Μπορεί να διαβαστεί μόνο από. Στο μητρώο PINxnπεριέχει πληροφορίες σχετικά με το πραγματικό τρέχον λογικό επίπεδο στις ακίδες της θύρας. Ανεξάρτητα από τις ρυθμίσεις θύρας. Αν λοιπόν θέλουμε να μάθουμε τι έχουμε στην είσοδο, διαβάζουμε το αντίστοιχο bit του καταχωρητή PINxn. Επιπλέον, υπάρχουν δύο όρια: το όριο του εγγυημένου μηδενός και το όριο του εγγυημένου ενός - τα όρια πέρα ​​από τα οποία μπορούμε ξεκάθαρα να προσδιορίσουμε με σαφήνεια το τρέχον λογικό επίπεδο. Για τροφοδοσία πέντε βολτ, αυτά είναι 1,4 και 1,8 βολτ, αντίστοιχα. Δηλαδή, όταν η τάση πέφτει από το μέγιστο στο ελάχιστο, τα bit του καταχωρητή PINxθα αλλάξει από το 1 στο 0 μόνο όταν η τάση πέσει κάτω από 1,4 βολτ, αλλά όταν η τάση αυξηθεί από το ελάχιστο στο μέγιστο, το bit θα αλλάξει από το 0 στο 1 μόνο όταν η τάση φτάσει τα 1,8 βολτ. Δηλαδή, υπάρχει μια υστέρηση μεταγωγής από το 0 στο 1, η οποία εξαλείφει τη χαοτική εναλλαγή υπό την επίδραση παρεμβολών και παρεμβολών και επίσης εξαλείφει την εσφαλμένη ανάγνωση του λογικού επιπέδου μεταξύ των ορίων μεταγωγής.

Με μείωση της τάσης τροφοδοσίας, φυσικά, μειώνονται και αυτά τα κατώφλια.

DDRxnείναι ο καταχωρητής κατεύθυνσης λιμένα. Η θύρα σε μια συγκεκριμένη χρονική στιγμή μπορεί να είναι είτε είσοδος είτε έξοδος (αλλά αυτό δεν έχει σημασία για την κατάσταση των bit PINxn. Διαβάστε από PINxnη πραγματική αξία είναι πάντα δυνατή).

DDRxy= 0 - η έξοδος λειτουργεί ως ΕΙΣΟΔΟΣ.

DDRxy= 1 - η έξοδος λειτουργεί ως OUTPUT.

PORTxn– λειτουργία ελέγχου κατάστασης εξόδου. Όταν ορίσουμε την έξοδο σε είσοδο, τότε από PORTxο τύπος καταχώρισης εξαρτάται (Hi-Z ή PullUp, περισσότερα για αυτό παρακάτω).

Όταν ο ακροδέκτης έχει ρυθμιστεί στην έξοδο, η τιμή του αντίστοιχου bit στον καταχωρητή PORTxορίζει την κατάσταση εξόδου. Αν PORTxn=1 τότε η έξοδος είναι log.1, αν PORTxn=0 τότε η έξοδος είναι log.0.

Όταν το πόδι έχει διαμορφωθεί για είσοδο, τότε εάν PORTxn=0, τότε η έξοδος είναι σε λειτουργία Hi-Z. Αν PORTxn\u003d 1 τότε η έξοδος είναι σε λειτουργία PullUp με αντίσταση έλξης 100k στην ισχύ.

Τραπέζι. Διαμόρφωση ακροδεκτών θύρας.

DDRxn PORTxn I/O Σχόλιο
0 0 I (Είσοδος) Είσοδος Είσοδος υψηλής σύνθετης αντίστασης. (Δεν συνιστώ τη χρήση του, καθώς μπορεί να προκληθούν παρεμβολές από το τροφοδοτικό)
0 1 I (Είσοδος) Είσοδος Η εσωτερική αντίσταση τραβήχτηκε προς τα πάνω.
1 0 O (Έξοδος) Έξοδος Η έξοδος είναι χαμηλή.
1 1 O (Έξοδος) Έξοδος Η έξοδος είναι υψηλή.

Η γενική εικόνα της λειτουργίας του λιμανιού φαίνεται στα σχήματα:

Ρύζι. DDRxn=0 PORTxn=0 – Λειτουργία: HI-Z– είσοδος υψηλής σύνθετης αντίστασης.

Ρύζι. DDRxn=0 PORTxn=1 - Λειτουργία: Τραβήξτε– είσοδος με pull-up to log.1.

Ρύζι. DDRxn=1 PORTxn=0 – Λειτουργία: Παραγωγή– Έξοδος log.0. (σχεδόν GND)

Ρύζι. DDRxn=1 PORTxn=1 - Λειτουργία: Παραγωγή- στο ημερολόγιο εξόδου.1. (σχεδόν VCC)

είσοδος Hi-Z- λειτουργία εισόδου υψηλής αντίστασης.
Αυτή η λειτουργία είναι ενεργοποιημένη από προεπιλογή. Όλοι οι διακόπτες είναι ανοιχτοί και η αντίσταση της θύρας είναι πολύ υψηλή. Κατ 'αρχήν, σε σύγκριση με άλλους τρόπους λειτουργίας, μπορεί να θεωρηθεί άπειρο. Δηλαδή ηλεκτρικά η έξοδος, λες, δεν συνδέεται πουθενά και δεν επηρεάζει τίποτα. Αλλά! Ταυτόχρονα, διαβάζει συνεχώς την κατάστασή του στο μητρώο PINnκαι μπορούμε πάντα να μάθουμε τι έχουμε στην είσοδο - ένα ή μηδέν. Αυτή η λειτουργία είναι καλή για ακρόαση οποιουδήποτε διαύλου δεδομένων, επειδή. δεν έχει καμία επίδραση στο λεωφορείο. Τι συμβαίνει εάν η είσοδος είναι στον αέρα; Και σε αυτή την περίπτωση, η τάση θα πηδήξει σε αυτό ανάλογα με τα εξωτερικά pickups, τις ηλεκτρομαγνητικές παρεμβολές και, γενικά, τη φάση της σελήνης και τον καιρό στον Άρη (ιδανικός τρόπος για να κόψετε τυχαίους αριθμούς!). Πολύ συχνά, σε αυτήν την περίπτωση, ένα ασταθές ημιτονοειδές 50 Hz στη θύρα είναι μια λήψη από το δίκτυο 220 V και στο μητρώο PINnθα αλλάξει 0 και 1 με συχνότητα περίπου 50Hz

είσοδος Τραβήξτε- Είσοδος έλξης.
Στο DDRxn=0 και PORTxn=1, κλείνει ο συρόμενος διακόπτης και συνδέεται μια αντίσταση 100 kΩ στη γραμμή, η οποία φέρνει αμέσως τη γραμμή που δεν είναι συνδεδεμένη πουθενά στην κατάσταση log.1. Ο σκοπός του pull-up είναι προφανής - να αποτραπεί μια χαοτική αλλαγή στην κατάσταση στην είσοδο υπό την επίδραση των pickups. Εάν όμως εμφανιστεί ένα λογικό μηδέν στην είσοδο (βραχύνοντας τη γραμμή με τη γείωση με ένα κουμπί ή άλλο μικροελεγκτή / μικροκύκλωμα), τότε μια ασθενής αντίσταση 100 kΩ δεν θα μπορεί να διατηρήσει την τάση στη γραμμή στο επίπεδο του log.1 και το η είσοδος θα είναι log.0.

λειτουργία εξόδου.
Εδώ, νομίζω, όλα είναι ξεκάθαρα - αν χρειαστεί να εκδώσουμε το log.1 στη θύρα, ενεργοποιούμε τη θύρα εξόδου ( DDRxn=1) και ημερολόγιο εξόδου.1 ( PORTxn\u003d 1) - ταυτόχρονα, ο επάνω διακόπτης κλείνει και εμφανίζεται μια τάση κοντά στην ισχύ στην έξοδο. Και αν χρειάζεστε log.0, ενεργοποιήστε τη θύρα εξόδου ( DDRxn=1) και ημερολόγιο εξόδου.0 ( PORTxn\u003d 1) - ταυτόχρονα ανοίγει η κάτω βαλβίδα, η οποία δίνει περίπου μηδέν βολτ στην έξοδο.