Jump to content



Assembly σε 8051


Dr.Paneas

Recommended Posts

Η ΟΡΓΑΝΩΣΗ ΜΝΗΜΗΣ ΚΑΙ ΟΙ ΤΡΟΠΟΙ ΠΡΟΣΠΕΛΑΣΗΣ

Σύντομη θεωρητική εισαγωγή

Τι είναι ο 8051

Ο 8051 είναι ένας μικροεπεξεργαστής ( microprocessor – μC) αναπτυγμένος σε ένα chip ( one chip microcomputer) των 40 pins, κατασκευασμένος από την γνωστή εταιρία επεξεργαστών Intel, περίπου το 1980. Σκοπός του ήταν και είναι η χρήση του σε ενσωματωμένα συστήματα ( αυτά που λέμε embedded systems) όπως είναι ηλεκτρονικά κυκλώματα, αυτοματισμοί, ηλεκτρονικά εμπορικά προϊόντα όπως ψηφιακές φωτογραφικές μηχανές έως παιχνίδια, ηλεκτρικές συσκευές και κάθε είδους αυτοκινούμενα τροχοφόρα οχήματα κλπ. Ο χρήστης/προγραμματιστής χρησιμοποιεί τον 8051 για να του εγγράψει κάποια στιγμή στη μνήμη EPROM (εσωτερική ή εξωτερική) ένα πρόγραμμα που θα τρέχει συνεχώς (ατέρμον βρόχος) ώστε αυτός να κάνει συνέχεια μια συγκεκριμένη δουλειά.

πχ να ελέγχει την λειτουργία ενός πλυντηρίου.

Το πρόγραμμα που τρέχει ο 8051 είναι γραμμένο στη γλώσσα μηχανής του ως μία σειρά/διαδοχή από bytes που αποτελούν κωδικοποιημένη μορφή εντολών. Η γλώσσα μηχανής του 8051 γράφεται με ένα, δύο ή τρία bytes. Μία εντολή μπορεί να κάνει διάφορες στοιχειώδεις λειτουργίες σε δεδομένα που βρίσκονται στη μνήμη RAM, σε Registers, ή στις Ports του 8051.

Για παράδειγμα η εντολή :

MOV A,R7

λέει βάλε (αντέγραψε) το περιεχόμενο του καταχωρητή ομάδας R7 της ενεργής ομάδας στον συσσωρευτή A .

Αυτή η εντολή κωδικοποιείται με το byte E8h που έχει διεύθυνση 29h . Αυτή η εντολή στη γλώσσα μηχανής γράφεται με δύο bytes, τα 25H και 28H. Δεδομένου ότι η γλώσσα του 8051 έχει 255 τέτοιες εντολές καταλαβαίνετε πόσο δύσκολο και επίπονο θα ήταν να γράφουμε προγράμματα γλώσσας μηχανής χρησιμοποιώντας απευθείας τα bytes που κωδικοποιούν τις εντολές.

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

Ο 8051 ήταν πολύ δημοφιλής μέχρι και την δεκαετία του 90’, αλλά σήμερα έχει εμφανώς ξεπεραστεί εξαιτίας της μεγάλης ανάπτυξης καινούριων επεξεργαστών από διάφορες εταιρίες.

Για παράδειγμα προτείνεται από πολλούς η χρήση του AVR καθώς είναι φθηνότερος και υπάρχει άφθονο υλικό πηγών στο internet γι αυτόν.

Η πρώτη υλοποίηση του 8051 έγινε με την τεχνολογία NMOS και αργότερα εξελίχθηκε στα CMOS η οποία αναγνωρίζεται στο stepping από τα τσιπάκια με το γράμμα “C” στο όνομά τους ( πχ 80C51). Ο λόγος που χρησιμοποιήθηκε η CMOS είναι γιατί απαιτεί λιγότερη ενέργεια, κάτι που έκανε τους μικροεπεξεργαστές αυτούς να είναι συμβατοί με συσκευές που χρησιμοποιούν μπαταρίες. Όπως για παράδειγμα στην motherboard, μετά από ένα αποτυχημένο overclocking, κάνουμε το λεγόμενο "Clear CMOS" το οποίο στην ουσία είναι να αφαιρούμε την μπαταρία από το κύκλωμα. (είτε κυριολεκτικά είτε με ένα jumper βραχυκλώνουμε με την γείωση). Αυτό έχει ως συνέπεια να σταματήσει να τρέχει ένα κύκλωμα μικροελεγκτή που είναι για την συγκεκριμένη δουλειά. Στην ουσία, έτσι κάνουμε reset το BIOS. Αντίθετα, όταν περνάμε μία νέα έκδοση BIOS, στην ουσία το επαναπρογραμματίζουμε, δηλαδή το φλασάρουμε.

Στην πραγματικότητα ο 8051 είναι ένας μικροελεγκτής ( microcontroller ) γιατί είναι σχεδιασμένος για γρήγορο και εκτεταμένο χειρισμό σημάτων από και προς ελεγχόμενες από αυτόν εξωτερικές συσκευές. O μικροελεγκτής είναι ένας τύπος επεξεργαστή, ή αν θέλετε μία παραλλαγή μικροεπεξεργαστή ο οποίος μπορεί να λειτουργήσει με εξωτερικά εξαρτήματα, λόγω των πολλών ενσωματωμένων υποσυστημάτων που διαθέτει.

Η Αρχιτεκτονική του 8051

Η βασική αρχιτεκτονική των μικροελεγκτών δεν διαφέρει από την κοινή των μικροεπεξεργαστών την αρχιτεκτονική μνήμης τύπου Harvard. Αυτή είναι μια αρχιτεκτονική που λέει ότι ο χώρος διευθύνσεων προγράμματος (ROM) είναι ανεξάρτητος από εκείνων των χώρο διευθύνσεων των δεδομένων ( RAM). Το μήκος των λέξεων στο χώρο του προγράμματος μπορεί να διαφορετικό από το μήκος των λέξεων στο χώρο των δεδομένων. Οι εντολές στα προγράμματα μπορούν να έχουν σαν ορίσματα τις διευθύνσεις του χώρου των δεδομένων ( βλ pointers). Σ’ αυτήν την αρχιτεκτονική βασίζεται ο 8051, δηλαδή έχει ξεχωριστό χώρο διευθύνσεων για το πρόγραμμα και τα δεδομένα. Παρόλα αυτά με έναν κατάλληλο συνδυασμό των pins !PSEN και !RD μπορεί να αλλάξει η αρχιτεκτονική σε von Neuman, όπου πλέον εκεί αναφερόμαστε σε ένα ενιαίο χώρο διευθύνσεων χωρίς να ξεχωρίζουμε δεδομένα και πρόγραμμα.

Τι είναι μικροεπεξεργαστής

Ο 8051 αποτελείται από τον μικροεπεξεργαστή και άλλα υποσυστήματα. Ο μικροεπεξεργαστής αποτελείται από την μονάδα επεξεργασίας δεδομένωνμονάδα ελέγχου.

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

  • Μονάδα αποκωδικοποίησης (Decoding Unit)
  • Λογική και Αριθμητική Μονάδα (Arithmetic and Logical Unit, ALU): Η μονάδα στην οποία εκτελούνται μία προς μία οι αριθμητικές ή λογικές πράξεις, όπως υπαγορεύονται από τις εντολές που έχουν δοθεί στον υπολογιστή.
  • Καταχωρητές (Registers): Μικρά κύτταρα μνήμης στο εσωτερικό του επεξεργαστή, που χρησιμοποιούνται για την προσωρινή αποθήκευση των δεδομένων, καθώς αυτά υφίστανται επεξεργασία. Οι καταχωρητές διαφέρουν ανάλογα με τον τύπο του επεξεργαστή και τον κατασκευαστή, τόσο ως προς την οργάνωση όσο και ως προς τη χωρητικότητά τους.
  • Μονάδα ελέγχου (Control Unit): Ελέγχει τη ροή δεδομένων από και προς την ALU, τους καταχωρητές, τη μνήμη και τις περιφερειακές μονάδες εισόδου/εξόδου.
  • Μονάδα προσκόμισης (Fetch Unit): Μεταφέρει τις εντολές από τη μνήμη στον επεξεργαστή.
  • Μονάδα προστασίας (Protection Unit): Εξασφαλίζει το αποδεκτό σφάλμα της κάθε διεργασίας που εκτελεί ο επεξεργαστής, ώστε να μη τροποποιούνται δεδομένα που δεν πρέπει ή να μην εκτελούνται μη αποδεκτές εντολές, όπως, π.χ., διαίρεση αριθμού με το μηδέν.

Βλέπετε το block διάγραμμα μικροεπεξεργαστή

[ATTACH]7067[/ATTACH]

Τι είναι μικροελεγκτής

Όπως προείπαμε ο 8051 είναι μικροελεγκτής, για αυτό αποτελείται απ’ όλα τα παραπάνω (όντας μικροεπεξεργαστής) και από κάποια άλλα υποσυστήματα. Αυτά είναι η μνήμη δεδομένων RAM ( Random Access Memory ) για την προσωρινή αποθήκευση δεδομένων, και η μνήμη προγράμματος ROM (Read Only Memory) ή EPROM ή EEPROM για την μόνιμη αποθήκευση του προγράμματος.

Για επικοινωνία με τον έξω κόσμο διαθέτει τέσσερις παράλληλες πόρτες των 8 bits (P0, P1, P2, P3 ) καθώς και σειριακή θύρα ( UART).

Τα εσωτερικά στοιχεία του 8051 συνδέονται μεταξύ του με τον εσωτερικό δίαυλο δεδομένων (εσωτερικό data bus), τον εσωτερικό δίαυλο διευθύνσεων ( address bus ) και τον εσωτερικό δίαυλο ελέγχου ( control bus ).

Σε περίπτωση όπου δεν επαρκούν οι εσωτερικές/ενσωματωμένες (on-chip) RAM και ROM μνήμες, ο 8051 έχει την δυνατότητα σύνδεσης με εξωτερικές. Κατά την εκτέλεση των εντολών ενός προγράμματος ο μικροελεγκτής μεταβαίνει από κατάσταση σε κατάσταση στα αρνητικά μέτωπα της παλμοσειράς του clock. Η συνήθης συχνότητα ρολογιού για τον 8051 είναι 12Mhz, όπου 12 παλμοί του ρολογιού συνιστούν έναν κύκλο μηχανής του 8051. Έχει λοιπόν συχνότητα ρολογιού 12 Mhz, περίοδο ρολογιού 1/12μsκαι ο κύκλος μηχανής διαρκεί 1μs.

[ATTACH]7068[/ATTACH]

Τα σημαντικότερα τεχνικά χαρακτηριστικά του 8051 είναι τα εξής:

  • Παρέχει λειτουργικότητα (CPU, RAM, I/0, λογικούς διακόπτες, Χρονιστή, κρυσταλλικό ταλαντωτή για το ρολόι κλπ ) σε ένα single chip.
  • 8-bit ALU, Accumulator και Registers , γεγονός που επιβεβαιώνει ότι είναι ένας 8-bit microcontroller.
  • 8-bit δίαυλο δεδομένων – μπορεί να έχει πρόσβαση σε 8 bit δεδομένων με μία φορά
  • 16-bit δίαυλο διευθύνσεων – μπορεί να έχει πρόσβαση σε 216 τοποθεσίες μνήμης – δηλαδή 64kiB (65536 τοποθεσίες) για RAM και ROM.
  • Εσωτερική (on-chip) RAM – 128 bytes ή 256 bytes( μνήμη δεδομένων) ανάλογα με το μοντέλο.
  • Εσωτερική (on-chip) ROM – 4kiB (μνήμη προγράμματος).
  • 4 Byte διπλής κατεύθυνσης θύρα I/0 .
  • UART ( Σειριακή θύρα ).
  • Δύο 16-bit Counter/Timers
  • Δύο επίπεδα προτεραιότητας διακόπτη
  • Σχέδιο χαμηλής κατανάλωσης ενέργειας

Βλέπετε το Block Διάγραμμα του μικροελεγκτή

[ATTACH]7069[/ATTACH]

Το εσωτερικό ενός Intel 8051 Microcontroller

[ATTACH]7070[/ATTACH]

Το pinout του 8051

[ATTACH]7071[/ATTACH]

Οργάνωση Μνήμης

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

Εσωτερική Μνήμη RAM – Μνήμη Δεδομένων

Η εσωτερική μνήμη RAM του 8051 έχει 128 θέσεις μνήμης των 8bit η κάθε μία ξεχωριστά. Από 0x00 [0] μέχρι 0x7F [127] έχουμε 128 θέσεις 1Byte εσωτερικής μνήμης RAM και από 0x80 [128] μέχρι 0xFF [255] έχουμε 128 μερικές θέσεις που καταλαμβάνουν οι SFR – Special Function Registers ( Καταχωρητές Ειδικής Λειτουργίας ). Οι υπόλοιπες θέσεις μεταξύ 0x80 και 0xFF που δεν καταλαμβάνονται από SFR μένουν αχρησιμοποίητες και δεν είναι διαθέσιμες για αποθήκευση bytes.

Με απλά λόγια θα λέγαμε λοιπόν ότι η εσωτερική μνήμη RAM είναι σπασμένη σε δύο κομμάτια.

Στο
πρώτο κομμάτι
έχουμε
128 ( 0
--->
127 ) θέσεις

και στο
δεύτερο κομμάτι
127 ( 128
--->
255 )
θέσεις που είναι είτε SFR, είτε κενές και άχρηστες προς αποθήκευση.

Γενικότερα αναφερόμαστε στην εσωτερική RAM ως μία 128bytes μνήμη.
Αν αυτή είναι 256bytes
τότε το δεύτερο κομμάτι της ταυτίζεται με τους SFR.

Μελετώντας πιο προσεχτικά το πρώτο κομμάτι της εσωτερικής RAM βλέπουμε ότι έχουμε 128 θέσεις. Αρχίζουμε από την 00h και τελειώνουμε στην 7Fh .

Πρώτο Κομμάτι ( Απευθείας RAM | DirectRAM ) [ 0 – 127 ]

  • Bank Registers [ 0 – 31 ]

Στις πρώτες 32 θέσεις ( 0 έως 31 – 00h έως 1Fh ) έχουμε τις 4 ομάδες καταχωρητών ( bank registers ) , οι οποίες είναι Register Bank 0 , 1 , 2 , 3 .

Η κάθε ομάδα αποτελείται από 8 καταχωρητές ομάδας ( work registers ) οι οποίοι είναι: R0, R1, R2, R3, R4, R5, R6, R7 .

Συνεπώς η πρώτη ομάδα καταχωρητών αρχίζει από την θέση 00h και τελειώνει στην θέση 07h. Η δεύτερη αρχίζει από την θέση 08h και τελειώνει στην θέση 0Fh. Η τρίτη αρχίζει από την θέση 10h και τελειώνει στην 17h. Και η τελευταία και τέταρτη ομάδα αρχίζει από την θέση 18h και τελειώνει στην 1Fh θέση.

  • Bit Addressable [ 32 – 47 ]

Στις επόμενες 16 θέσεις ( από την 32 έως 47 -- 20h έως 2Fh ) έχουμε θέσεις μνήμης οι οποίες μπορούν να προσπελαστούν με δική τους 8-bit διεύθυνση ( bit addressable ) . Δηλαδή έχουμε 16 θέσεις μνήμης, όπου στην κάθε θέση μπορούμε να βάλουμε μέχρι 8bit και να έχουμε πρόσβαση σ'αυτά ξεχωριστά. πχ πρόσβαση στο 2ο bit της θέσης μνήμης 21h , είναι μία έγκυρη εντολή. Αντίθετα πρόσβαση στο 2ο bit της θέσης μνήμης 81h είναι άκυρη εντολή, επειδή η συγκεκριμένη θέση ΔΕΝ είναι προσπελάσιμη κατά bit.

  • Γενικής Χρήσης [ 47 – 127 ]

Όπως είπαμε νωρίτερα το πρώτο μέρος της εσωτερικής RAM μνήμης δεδομένων αποτελείται από 128 θέσεις μνήμης και εμείς έχουμε μιλήσει για το τι βρίσκεται στις 32+16 = 48 πρώτες θέσεις της. Οι υπόλοιπες 80 θέσεις που μένουν είναι θέσεις γενικού σκοπού για οποιαδήποτε αποθήκευση. Αυτές οι 80 θέσεις αρχίζουν από την θέση 30h και τελειώνουν στην 7Fh , όπου τελειώνει και το πρώτο κομμάτι της εσωτερικής RAM.

Βλέπετε μία απεικόνιση του πρώτου κομματιού της εσωτερικής RAM .

[ATTACH]7072[/ATTACH]

Δεύτερο Κομμάτι ( Έμμεση RAM | IndirectRAM ) [ 128 – 255 ]

Στην συνέχεια, στο δεύτερο κομμάτι της RAM βλέπουμε αχρησιμοποίητες θέσεις μνήμης που δεν μπορούμε να γράψουμε δεδομένα, και τους καταχωρητές ειδικής λειτουργίας SFR ( Special Function Registers ). Το κομμάτι αυτό, όπως προείπαμε, αρχίζει από την θέση 80h και τελειώνει στην FFh.

Βλέπετε τις 128 θέσεις του δεύτερο πάνω μισού της εσωτερικής RAM.

[ATTACH]7073[/ATTACH]

Ορίστε μία απεικόνιση ολόκληρης της εσωτερική μνήμης RAM μαζί με το δεύτερο κομμάτι των SFR .

[ATTACH]7074[/ATTACH]

Μνήμη ROM – Μνήμη Προγράμματος ( Εσωτερική και Εξωτερική )

Αρκετά είπαμε όμως για την εσωτερική μνήμη RAM. Ας περάσουμε στην εσωτερική μνήμη ROM, την μνήμη προγράμματος ( code memory ) , όπου διατηρείται ο κώδικας του προγράμματος μας. Γενικότερα για εξωτερική και εσωτερική ROM , ο 8051 χρησιμοποιεί 16bit διευθύνσεις . Δηλαδή μπορεί να προσπελάσει 64k. Ενώ για εσωτερική RAM έχει 8bit διευθύνσεις. Το μέγεθος της εσωτερικής ROM είναι 4kiB και εκεί φυλάσσετε ο κώδικας, δηλαδή η μνήμη του προγράμματος .

Η εξωτερική ROM έχει μέγεθος 60k.

Συνεπώς εξωτερική ROM + εσωτερική ROM = 64k χωρίς αυτό να είναι αναγκαίο. Υπάρχουν διάφοροι συνδυασμοί όπου μπορεί να μην έχουμε καθόλου εσωτερική ROM και να έχουμε όλα τα 64k στην εξωτερική ROM. Η εξωτερική RAM έχει μέγεθος 64k.

Τύπος Μνήμης

Εσωτερική
RAM
:

128
bytes( ο κλασσικός 8051)

256
bytes ( 256 + 128
SFR )

Εσωτερική
ROM

4kiB

Εξωτερική
RAM

64kiB

Εξωτερική
ROM

60kiB

Παρακάτω βλέπετε μία συνολική εικόνα των μνημών:

[ATTACH]7075[/ATTACH]

Στην περίπτωση όπου έχουμε εσωτερική RAM 256 bytes τότε το δεύτερο κομμάτι της RAM έχει τις ίδιες διευθύνσεις με τους SFR και διαφέρει στον τρόπο προσπέλασής του.

Βλέπετε μία πιο λεπτομερής εικόνα των μνημών

[ATTACH]7076[/ATTACH]

ΤΡΟΠΟΙ ΠΡΟΣΠΕΛΑΣΗΣ ΜΝΗΜΗΣ

Αυτό που πρέπει να γίνει πρώτα είναι να ερμηνευθούν τα σύμβολα:

  • Codememory Μνήμη προγράμματος. C
  • Direct addressable internal RAM = Εσωτερικήαπευθείαςπροσπελάσιμη RAM. D
  • Indirect addressable internal RAM = ΕσωτερικήέμμεσαπροσπελάσιμηRAM. I
  • External memory = Εξωτερικήμνήμη. X
  • Bit addressable RAM = Προσπελάσιμηκατά bit RAM. B
  • Peripheralmemory = Περιφερειακή μνήμη (ακροδέκτες θυρών εισόδου / εξόδου) P

Πειραματική διαδικασία

ΑΣΚΗΣΗ 2.1

Ανοίξτε το debugger και δώστε στο παράθυρο Memory την εντολή d D:0000h. Θα εμφανιστούν τα περιεχόμενα των θέσεων της απ’ ευθείας (Direct) προσπελάσιμης μνήμης. Επαληθεύστε τις τιμές Reset, συγκρίνοντας με αυτές που εμφανίζει ο Πίνακας 2-1.

Ανοίγοντας το MemoryWindowγράφοντας την εντολή D:0000hβλέπω τις θέσεις RAMαπό 0000hέως 7Fh. Οι τιμές που επαληθεύονται είναι οι τιμές που βλέπω από 80hμέχρι FFh, οι οποίες υπάρχουν στον πίνακα των SFRτου βιβλίο σελ24.

ΑΣΚΗΣΗ 2.2

Δώστε τη διαταγή e I:0010=κωδ1, παρατηρήστε και εξηγήστε το αποτέλεσμα της.

Δίνοντας αυτήν την εντολή μιλάμε απευθείας στον compilerόπου του λέμε να δώσει στην θέση εσωτερικής μνήμης έμμεσης RAMτον κωδ1 ο οποίος είναι ένα νούμερο (σταθερά). Δηλαδή Για παράδειγμα δίνοντας eD:00E0h = 2 όπου είναι η διεύθυνση του ACCβλέπουμε ότι όντως παίρνει αυτή την τιμή.

[ATTACH]7077[/ATTACH]

ΑΣΚΗΣΗ 2.3

Δώστε τις διαταγές Α=κωδ2, Β=κωδ2+1, R0= κωδ2+2, R1= κωδ2+3,…,R7= κωδ2+9, DPTR=8000h, SP= κωδ2+10, CY=1 και ΟV=1 και επαληθεύστε τα αποτελέσματα τους στο παράθυρο Registers και στο παράθυρο Memory.

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

  • Στην 82h όπου κρατάει το lowbit <εισέρχεται το 00 >
  • Στην 83h όπου κρατάει το highbit <εισέρχεται το 80>

ΑΣΚΗΣΗ 2.4

Φορτώστε το πρόγραμμα EX1-1 και επαληθεύστε τον κώδικα όπως περιέχεται στην μνήμη, με αυτόν που παρήγαγε ο μεταφραστής και περιέχεται στο αρχείο EX1-1.lst.

Ανοίγουμε το αρχείο *.LST και βλέπουμε τον κώδικα. Στην συνέχεια ανοίγουμε να δούμε την ROM με την εντολή C:διεύθυνση όπου εκεί βλέπουμε τον ίδιο κώδικα με εντολές.

[ATTACH]7078[/ATTACH]

post-928-1414343373,9171_thumb.png

post-928-1414343373,9412_thumb.png

post-928-1414343373,954_thumb.png

post-928-1414343373,9773_thumb.png

post-928-1414343374,0418_thumb.png

post-928-1414343374,0654_thumb.png

post-928-1414343374,076_thumb.png

post-928-1414343374,0943_thumb.png

post-928-1414343374,1062_thumb.png

post-928-1414343374,1248_thumb.png

post-928-1414343374,1536_thumb.png

post-928-1414343374,177_thumb.png

Link to comment
Share on other sites

ΑΣΚΗΣΗ 2.5

Το επόμενο πρόγραμμα πόλλαπλασιάζει τους αριθμούς 30h και 8Ch. Γράφει το αποτέλεσμα στη θέση VAR1. Γράψτε, μεταφράστε και εκτελέστε το πρόγραμμα, επαληθεύοντας η λειτουργία του.

; Πρόγραμμα πολλαπλασιασμού δύο σταθερών αριθμών

; Όνομα : …………

;

VAR1 equ 40h

;

cseg at 0

MOVA,#3 ;Βάλε τον 3 αριθμό στον Α

MOVB,#2 ;Βάλε τον 2 αριθμό στον B

MUL AB ;Πολλαπλασίασε Α επι Β

MOV VAR1,B ; Φύλαξε το αποτέλεσμα, πρώτα το highbyte

MOV VAR1+1,A ; καιμετάτο low byte

HALT: JMP HALT

end

To ; ( semicolon ) χρησιμοποιείται για την εισαγωγή σχολίου, καθώς μπορεί να χρησιμοποιηθεί και ο κλασσικό τύπος commenting της C /* . . . */

Όπου βλέπει ο Assembler VAR1 την εξισώνει ( equals ) με την θέση 40h .

Αρχικά ο ACC έχει την τιμή 00003 και ο Β την τιμή 0002. Μετά τον πολλαπλασιασμό τους, το αποτέλεσμα αποθηκεύεται στον ACC ο οποίος παίρνει την τιμή 0006. Μετά αποθηκεύει στην θέση 40h το HIGH Byte δηλαδή το 00 και στην συνέχεια το Low Byte που είναι το 06 στην θέση 41h.

[ATTACH]7079[/ATTACH]

Συμπεράσματα

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

Όλα αυτά έγιναν πράξη με το μVisionόπου μέσω του debuggin είδαμε βήμα-βήμα την λειτουργία των εντολών μέσα στην μνήμη του 8051 ( χρησιμοποιώντας το Memory Window ).

post-928-1414343374,2029_thumb.png

Link to comment
Share on other sites

ΤΡΟΠΟΙ ΔΙΕΥΘΥΝΣΙΟΔΟΤΗΤΗΣ – ΕΝΤΟΛΕΣ ΜΕΤΑΦΟΡΑΣ ΔΕΔΟΜΕΝΩΝ

Σύντομη θεωρητική εισαγωγή

ΤΡΟΠΟΙ ΠΡΟΣΠΕΛΑΣΗΣ ΜΝΗΜΗΣ

Αυτό που πρέπει να γίνει πρώτα είναι να ερμηνευθούν τα σύμβολα:

C

Codememory = Μνήμη προγράμματος.

D

Direct addressable internal RAM = Εσωτερικήαπευθείαςπροσπελάσιμη RAM.

I

Indirect addressable internal RAM = ΕσωτερικήέμμεσαπροσπελάσιμηRAM.

X

External memory = Εξωτερικήμνήμη.

B

Bit addressable RAM = Προσπελάσιμηκατά bit RAM.

P

Peripheralmemory = Περιφερειακή μνήμη (ακροδέκτες θυρών εισόδου / εξόδου).

Οι εντολές για την προσπέλαση μνήμης είναι:

[ATTACH]7080[/ATTACH]

Έχουμε 6 τρόπους addressing. Επειδή η ελληνική μετάφραση δεν αντιστοιχεί ακριβώς στην ακριβή ορολογία θα χρησιμοποιήσω μόνο την αγγλική.

  • Immediate Addressing

Όπως φαίνεται και από το όνομα, Immediate addressing λέγεται η διευθυνσιοδότηση όπου η τιμή που θα αποθηκευτεί στην μνήμη ακολουθείται απευθείας (immediately) από τον «κωδικό λειτουργίας / operation code» στην μνήμη. Η ίδια εντολή υποδεικνύει την τιμή που θα αποθηκευτεί στην μνήμη. Δηλαδή τα δεδομένα είναι μέρος της ίδιας της εντολής.

Για παράδειγμα, η οδηγία:

[SIZE=2]
MOV A,#20h [/SIZE]

Αυτή η οδηγία χρησιμοποιεί Immediate Addressing επειδή ο Accumulator θα φορτωθεί με την τιμή που ακολουθεί αμέσως μετά.

Στην περίπτωσή μας το 20 (hex) .

Η Immediate Addressing είναι πολύ γρήγορη και αυτό γιατί η τιμή που πρόκειται να φορτωθεί στην μνήμη περιλαμβάνεται στην ίδια την οδηγία/εντολή.

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

πχ MOV A,#0Eh 
αντί για MOX A,#Eh που είναι λάθος

Ας δούμε μερικές εντολές:

  • MOV A,#12h


Βάλε στον Accumulator την σταθερά 12 (hex)

  • MOV R7,#12h


Βάλε στον καταχωρητή ομάδας R7 την σταθερά 12 (hex)

  • MOV DPH,#12h


Βάλε στο High Byte του DTPR την σταθερά 12 (hex)

  • MOV DPL,#12h

Βάλε στο Low Byte του DPTR την σταθερά 12 (hex)

  • MOV DPTR,#12h


Βάλε στον DTPR την σταθερά 12 (hex)

  • MOV @R0,#12h


Βάλε στην μνήμη που δείχνει ο R0 την τιμή 12 (hex)

  • MOV 35h,#12h


Βάλε στην διεύθυνση 35 (hex) της μνήμης, την σταθερά 12 (hex).

Με αυτόν τον τρόπο αναφερόμαστε σε τιμή.

Για παράδειγμα θα ήταν λάθος να γράψουμε MOV 12h,#R7 γιατί ο R7 είναι καταχωρητής και όχι τιμή.

  • Direct Addressing

Direct Addressing λέγεται η διευθυνσιοδότηση όπου η τιμή που θα αποθηκευτεί στην μνήμη προέρχεται άμεσα (directly) από μία άλλη θέση της μνήμης. Με τον τρόπο αυτόν μπορούμε να κάνουμε προσπέλαση στα κάτω 128 bytes της RAM και στους SFR. Αν η RAM είναι 256 bytes τότε στα πάνω 128bytes που συμπίπτουν με τις διευθύνσεις των SFR δεν μπορούμε να προσπελάσουμε με αυτόν τον τρόπο.

Για παράδειγμα:    

MOV A,30h

[SIZE=2]Αυτή η οδηγία, θα διαβάσει τα δεδομένα από την εσωτερική RAM που βρίσκονται στην θέση 30 (hex) και θα την αποθηκεύσει στον Accumulator. [/SIZE] [SIZE=2]
[/SIZE]

Αυτός ο τρόπος δίνει πιο αργές εντολές σε σχέση με την Immediate Addressing, αλλά επειδή η πληροφορία ανταλλάσσεται εσωτερικά στην RAM, η λειτουργία παραμένει αρκετά γρήγορη. Επίσης είναι πιο ευέλικτη αφού η τιμή που θα φορτωθεί είναι ότι υπάρχει ήδη στην διεύθυνση μνήμης – η οποία μπορεί να διαφέρει ( σε σχέση με πριν που μπορούσαμε να φορτώσουμε μία συγκεκριμένη τιμή).

Αυτό που αξίζει να πούμε για μία ακόμα φορά είναι ότι με Direct Addressing μπορούμε να κάνουμε προσπέλαση τα κάτω 128bytes της εσωτερικής RAM.

Δηλαδή τις διευθύνσεις από 00 έως 7Fh.

Επίσης μπορούμε να προσπελάσουμε και τους SFR, δηλαδή τις διευθύνσεις 80h μέχρι FFh. Σε περίπτωση όμως που η εσωτερική RAM είναι 256kB τότε όπως είπαμε αρκετά πιο πάνω, έχουμε δύο διαφορετικά τμήματα στο πάνω μέρος της RAM.

Δηλαδή έχουμε:

1) Τμήμα: Από 80h μέχρι FFh που είναι SFR και άχρηστες κενές θέσεις μη χρησιμοποιούμενες.

2) Τμήμα: Από 80h μέχρι FFh που είναι η συνέχεια της απλής γενικής χρήσης RAM.

Για παράδειγμα στην θέση μνήμης 0E0h βρίσκεται ο ACC ο οποίος είναι ένας SFR. Μπορώ να τον προσπελάσω με Direct Addressing.

[SIZE=2]
πχ MOV A,h30 // βάλε στον Α ότι υπάρχει στην θεση 30h
ή με την διεύθυνση του: MOV 0E0h, h30
η παραπάνω εντολή θα αποθηκεύση την τιμή της θέσης μνήμης 30h στον Accumulator που είναι SFR και όχι στην θέση μνήμης γενικού σκοπού 0E0h. Γιατι ; Γιατί χρησιμοποιήσαμε Direct Addressing που αυτό σημαίνει ότι μπορείς να γράφεις είτε στο κάτω μισό της εσωτερικής RAM είτε στο πάνω μισό ΑΛΛΑ ΜΟΝΟ στο τμήμα των SFR. [/SIZE]

Ας δούμε μερικές εντολές:

  • MOV A,12h


Βάλε στον Accumulator το περιεχόμενο της μνήμης RAM με διεύθυνση 12 (hex)

  • MOV R7,12h


Βάλε στον καταχωρητή ομάδας R7 το περιεχόμενο της μνήμης RAM με διεύθυνση 12 (hex)

  • MOV 12h,R7


Βάλε στην διεύθυνση 12 (hex) της μνήμης RAM, την τιμή που βρίσκεται στην διεύθυνση του καταχωρητή R7. Δηλαδή την τιμή που κρατάει ο R7.

  • MOV DPH,#12h


Βάλε στο High Byte του DTPR την σταθερά 12 (hex)

  • MOV DPL,12h

Βάλε στο Low Byte του DPTR το περιεχόμενο της μνήμης RAM με διεύθυνση 12 (hex)

  • MOV DPTR,12h


Βάλε στον DTPR το περιεχόμενο της μνήμης RAM με διεύθυνση 12(hex)

  • MOV @R0, 12h


Βάλε στην μνήμη που δείχνει ο R0, το περιεχόμενο της μνήμης RAM με διεύθυνση 12 (hex)

  • MOV 35h,12h


Βάλε στην διεύθυνση 35 (hex) της μνήμης, το περιεχόμενο της μνήμης RAM με διεύθυνση 12 (hex).

  • XCH A,12h


Αντάλλαξε δεδομένα

  • PUSH 12h


Βάλε στην στοίβα το περιεχόμενο της μνήμης RAM με διεύθυνση 12 hex

  • POP 12h

Βγάλε από την στοίβα το περιεχόμενο της μνήμης RAM με διεύθυνση 12 hex

Σ’ αυτή την κατηγορία εντάσσεται και το Register Addressing.

Για παράδειγμα:

[SIZE=2]
MOV A,R0[/SIZE]

Βάλε στον A, αυτό που κρατάει ο register R0. Μπορεί να γίνει επίσης και το ανάποδο, δηλαδή να βάλουμε στον R0, αυτό που κρατάει ο Accumulator.

Προσέξτε όμως κάτι που είναι πολύ σημαντικό.

 Δεν μπορούμε να έχουμε :
MOV R0,R2

Καθώς αυτό απαγορεύεται να γίνει στον 8051 ως εντολή.

Για αυτό μπορούμε να χρησιμοποιήσουμε την επόμενη μέθοδο, Indirect Addressing.

  • Indirect Addressing

Αυτός ο τρόπος είναι πολύ ισχυρός και μας παρέχει επιπλέον ευελιξία. Αποτελεί τον μοναδικό τρόπο προσπέλασης των επιπλέον 128bytes της εσωτερικής RAM (αν αυτή είναι 256bytes) σε έναν 8051 microcontroller.

Για παράδειγμα    
MOV A,@R0

Αυτή η οδηγία κάνει τον 8051 να αναλύσει την τιμή του R0 register. Στην συνέχεια, ο 8051 θα φορτώσει στον Accumulator μια τιμή από την εσωτερική RAM της οποίας η διεύθυνση είναι η τιμή που δείχνει ο R0.

Για παράδειγμα, ας πούμε ότι ο R0 κρατάει την τιμή 40h και στην διεύθυνση 40h της εσωτερικής RAM υπάρχει αποθηκευμένη η τιμή 67h.

Τότε, όταν εκτελεστεί η εντολή στον 8051, αυτός θα ελέγξει πρώτα απ’ όλα την τιμή του R0. Από την στιγμή που ο R0 κρατάει την τιμή 40h, o 8051 θα βάλει την τιμή που βρίσκεται σ’ αυτήν την θέση εσωτερικής μνήμης RAM (δηλαδή την τιμή 67h) και θα την αποθηκεύσει στον Accumulator. Έτσι, το τελικό αποτέλεσμα είναι ο Accumulator να έχει την τιμή 67h.

Σημαντικό: Το Indirect Addressing αναφέρεται πάντα στην εσωτερική RAM και ποτέ στους SFR. Η λογική είναι να φορτώνουμε την διεύθυνση που κρατάει τα δεδομένα μας στους registers συνήθως με Immediate Addressing και μετά να περνάμε τον Register με Indirect έτσι ώστε να γίνεται προσπέλαση στην διεύθυνση μνήμης που ορίσαμε στην αρχή.

Για παράδειγμα επειδή δεν μπορούμε να κάνουμε : MOV R0,R1

Θα κάνουμε:
MOV A,R1 MOV R0,A

Ή ένας άλλος τρόπος θα ήταν:


MOV A,#01h MOV R0,@A

Μερικές εντολές:

MOV A,@R0

Βάλε στον A, το περιεχόμενο της μνήμης που δείχνει ο R0.

  • MOV @R0,A


Βάλε στην διεύθυνση που δείχνει ο R0, το περιεχόμενο του Α.

  • MOV @R0,12h


Βάλε στην διεύθυνση που δείχνει ο R0, το περιεχόμενο της μνήμης στην θέση 12 ( hex)

  • MOV 12h,@R0


Βάλε στην θέση 12 (hex) της μνήμης, το περιεχόμενο της μνήμης στην διεύθυνση που δείχνει ο R0.

  • External Direct Addressing

Είναι ο direct τρόπος για να γράψουμε κάτι στην 2Byte ( 16bit ) εξωτερική RAM.

Το σκεπτικό είναι το εξής:

Αρχικά φορτώνουμε στον DPTR την εξωτερική διεύθυνση μνήμης που θέλουμε γράψουμε:

πχ MOV DPTR,#15h 

Έτσι φορτώνω στον DTPR την διεύθυνση 15h της εξωτερικής μνήμης.

  • READ from External RAM

Στην συνέχεια η επόμενη εντολή θα αντιγράψει δεδομένα από την εξωτερική διεύθυνση στον Accumulator:


MOVX A,@DPTR

Κατά αυτόν τον τρόπο διαβάζουμε δεδομένα από την εξωτερική μνήμη.

  • WRITE to External RAM

Για να γράψουμε δεδομένα, τότε γράφουμε:


MOVX @DPTR,A

Αυτή η εντολή γράφει στην εξωτερική διεύθυνση μνήμης που δείχνει ο DPTR, την τιμή που κρατάει ο Accumulator.

  • External Indirect Addressing

Αυτός ο τρόπος δεν συνηθίζεται και είναι χρήσιμος όταν θέλουμε να μεταφέρουμε στην εξωτερική μνήμη μικρά δεδομένα (όπου δεν έχει nibbles για να χωρίσουμε σε High Byte και Low Byte ώστε να μην υπάρχει ανάγκη χρήσης του DPTR 16bit register). Για αυτό τον λόγο φορτώνουμε στον R0 την διεύθυνση της εξωτερικής μνήμης που θέλουμε αποθηκεύσουμε τα δεδομένα μας (περίπτωση WRITE) . Οπότε γράφουμε:

MOVX @R0,A 

Πειραματική διαδικασία

ΑΣΚΗΣΗ 3.1

Αντιγράψτε το περιεχόμενο της θέσης κωδ1 στην εσωτερική μνήμη RAMστον καταχωρητή R4 χρησιμοποιώντας διευθυνσιοδότηση.

a. Register – Direct

b. Direct – Direct

c. Indirect στην κωδ1

d. Indirect στον R4

[SIZE=2]
a) MOV R4,κωδ1h
MOV 04h,κωδ1h
c) MOV R0,#κωδ1
MOV R4,@R0
d) MOV @R4,κωδ1
[/SIZE]

Ανοίγοντας το MemoryWindowγράφοντας την εντολή D:0000hβλέπω τις θέσεις RAMαπό 0000hέως 7Fh. Οι τιμές που επαληθεύονται είναι οι τιμές που βλέπω από 80hμέχρι FFh, οι οποίες υπάρχουν στον πίνακα των SFRτου βιβλίο σελ24.

ΑΣΚΗΣΗ 3.2

Γράψτε την σταθερά κωδ2 στις θέσεις μνήμης RAMαπό 20hμέχρι 23hμε διευθυνσιοδότηση:

a. Direct – Immediate

b. Direct – Direct

c. Direct – Register

d. Indirect – Indirect

MOV A,#12h
MOV 20h,A
MOV 21h,A
MOV 22h,A
MOV 23h,A

MOV 20h,#12h
MOV 21h,#12h
MOV 22h,#12h
MOV 23h,#12h

MOV 15h,#12h
MOV R0,#15h
MOV 20h,@R0
MOV 21h,@R0
MOV 22h,@R0
MOV 23h,@R0

MOV 15h,#12h
XCH A,15h
MOV 20h,A
MOV 16h,#12h
XCH A,16h
MOV 21h,A
MOV 17h,#12h
XCH A,17h
MOV 22h,A
MOV 18h,#12h
XCH A,23h
MOV 23h,A

ΑΣΚΗΣΗ 3.3

Γράψτε στην εξωτερική μνήμη RAMστη διεύθυνση 0C00h τη σταθερά κωδ1

MOVDPTR,#0C00h      ;Βάλε στον DPTR την εξωτερική διεύθυνση X:0x0C00
MOV Α,#κώδ1 ;Βάλε στον A την σταθερά κωδ1
MOV @DPTR,A ;Γράψε τον Α στην εξωτερική διεύθυνση που δείχνει ο DPTR

ΑΣΚΗΣΗ 2.4

Γράψτε τη σταθερά κωδ2 στην θέση 0Ε0hτης εσωτερικής RAM (προσοχή: όχι στους SFR).

Πρόκειται για τα πάνω 128bytesτης RAM, συνεπώς θα χρησιμοποιήσω IndirectAddressing έτσι ώστε να αποφύγω την εγγραφή στον Accumulatorπου αντιστοιχεί στην διεύθυνση ;μνήμης D:0x0E0hτων SFR

MOVR0,#0E0h         ;Ο R0 Registerκρατάει την τιμή 0x0E0h
MOV @R0,#κωδ2 ;Βάλε στην διεύθυνση που δείχνει ο R0, την σταθερά κωδ2

Για την επαλήθευση δείτε I:0E0h

ΠΡΟΧΟΣΗ: Αν δείτε D:0E0hτότε θα δείτε SFRπου είναι λάθος.

Συμπεράσματα

Γνωρίζουμε πλέον τους τρόπους addressingστην μνήμη του 8051. Πλέον γνωρίζουμε τόσο θεωρητικά την δομή της μνήμης, αλλά πλέον μπορούμε με τις γνώσεις μας να προσπελάσουμε τις θέσεις αυτές και να επαληθεύσουμε αν τελικά καταλάβαμε σωστά την σημερινή έννοια του μαθήματος.

Το βασικότερο είναι ότι ξεχωρίσαμε ότι αν η μνήμη RAMείναι 256bytes, τότε τα πάνω 128bytesέχουν ίδιες διευθύνσεις με τους SFR. Για να ξεχωρίσουμε πότε θα απευθύνουμε σε SFRκαι πότε στα 128πάνω της RAM, χρησιμοποιούμε διαφορετικό τρόπο διευθυνσιοδότηση .

Επίσης δεν ξεχνάμε ότι δεν υπάρχει RegisterRegisteraddressingπχ MOVR0,R1

Τέλοςμάθαμετρόπους READ και WRITE απότηνεξωτερική RAM τόσο Indirect όσο Direct Addressing modes.

post-928-1414343374,2216_thumb.png

Link to comment
Share on other sites

ΕΝΤΟΛΕΣ ΔΙΑΚΛΑΔΩΣΗΣ

Σύντομη θεωρητική εισαγωγή

Αυτό που πρέπει να γίνει κατανοητό από όλους πριν αρχίσουμε την θεωρητική εισαγωγή αυτής της εργαστηριακής άσκησης είναι ο PC.

PCProgramCounter

O PC ( Απαριθμητής Προγράμματος ελληνιστί ) είναι ένας Register ο οποίος δείχνει κάθε φορά την διεύθυνση μνήμης της επόμενης εντολής. Για να είμαστε πιο συγκεκριμένoi, δείχνει το επόμενο byte προγράμματος που πρόκειται να εκτελεστεί από την ROM. Μετά την εκτέλεση της εντολής (οδηγίας) αυτόματα αυξάνεται κατά 1, έτσι ώστε να δείχνει κάθε φορά το επόμενο byte της επόμενη εντολής προς εκτέλεση (για παράδειγμα η εντολή μπορεί να είναι 2 bytes, έτσι αυτός θα δείξει αρχικά το low byte και στην συνέχεια το high byte).

Τα bytes αυτά οδηγούνται στο stack ( στοίβα ελληνιστί ) όπου εκεί έχουμε τον SP ( Stack Pointer ) να δείχνει πάντα την κορυφή (top) της σωρού-stack.

Στο συγκεκριμένο παράδειγμα, αν έχουμε 16bit εντολή ( aka 2 bytes) τότε το περιεχόμενο το SP θα αυξηθεί κατά 2. Το περιεχόμενό PC μπορεί να τροποποιηθεί μόνο με τις παρακάτω εντολές:

[ATTACH]7081[/ATTACH]

Αξίζει να αναφέρουμε ότι είναι 16bit Register, το οποίο είναι κάτι που σημαίνει ότι μπορεί να μεταδώσει 64k πληροφορίας μέσω του 16bit Address Bus του Intel 8051 processor.

Go To

Παλιότερα στον δομημένο προγραμματισμό ( structured programming ) υπήρχε (και υπάρχει μέχρι και σήμερα για λόγους προς τα πίσω συμβατότητας) η εντολή Go To. Αυτή η εντολή έκανε ένα άλμα από το ένα μέρος στο κώδικα του προγράμματος. Αντίστοιχα το ίδιο μπορούμε να κάνουμε και στην Assembly, μόνο που αντί για Go To, τώρα η εντολή λέγεται JMP ( JUMP – άλμα ). Αυτό μας βολεύει αρκετές φορές να το χρησιμοποιούμε, και στην ουσία είναι μία εντολή που μεταβάλει τον PC .

Στην πιο απλή της μορφή, μπορεί να χρησιμοποιηθεί ως :

JMP κάπου    

Και σε πιο σύνθετη περίπτωση να συμπεριλάβει μία συνθήκη ( if conditionals ) . Όπου αν και μόνον αν ισχύει κάτι, τότε κάνε JMP κάπου, αλλιώς μην κάνει τίποτα και συνέχισε το πρόγραμμα κανονικά. Μερικές συνθήκες είναι οι:

Z = Zero

NZ = Not Zero

C = Carry

NC = Not Carry

B = Bit (1)

NB = Not Bit (0)

*Προσέξετε επίσης την εντολή: BC=Bit and Clear (αν το bit είναι 1, μηδένισε το ).

Οι συνθήκες αυτές έχουν να κάνουν με την Boolean τιμή της συνθήκης. Αν η συνθήκη είναι αληθής τότε έχουμε JMP κάπου ( εννοείται πως έχουμε δηλώσει «πού») αλλιώς αν η συνθήκη είναι ψευδής, τότε έχουμε κανονικά την συνέχιση εκτέλεσης του προγράμματος.

Ο έλεγχος αυτός, είναι καθαρά σε πολύ χαμηλό επίπεδο μεταξύ bytes ή bits. Ο έλεγχος ενός bit είναι πολύ απλός και αρκετά σημαντικός. Στην ουσία, αφού το bit έχει δύο καταστάσεις ( λογικό μηδέν, λογικό ένα ) αυτό σημαίνει ότι μπορεί να γίνουν οι παραπάνω έλεγχοι του πίνακα.

Η λογική πίσω από τον έλεγχο ενός bit βρίσκεται στην λειτουργία του PSW και των flags αυτού.

Για παράδειγμα αν θέλουμε να δούμε αν ένας αριθμός είναι άρτιος ή περιττός και να κάνουμε κάποια ενέργεια για την μία ή την άλλη περίπτωση αρκεί να ελέγξουμε το 1ο bit του PSW, γνωστό ως Parity. Ο έλεγχος bytes έχει να κάνει με την σύγκριση δύο bytes ( μεγαλύτερο, μικρότερο, ίσο, διάφορο).

Διακλάδωση

Όπως είπαμε πριν, δεν θα είχε νόημα απλά να κάνουμε έναν έλεγχο χωρίς να γίνει κάποια λειτουργία – καθώς θα ήταν άστοχο και άσκοπο από άποψη κατανάλωσης επεξεργαστικών πόρων και clocks. Για αυτό τον λόγο έρχονται τώρα να υλοποιηθούν τα JMP ( Jumps ) που λέγαμε νωρίτερα στην αρχή της θεωρητικής εισαγωγής. Το όλο σχέδιο, είναι να γίνει έλεγχος και κατόπιν του αποτελέσματος που θα προκύψει ( αληθής ή ψευδής) να γίνει ένα JMP σε κάποιο σημείο στο οποίο υπάρχει ο κώδικας με τις λειτουργίες που θέλουμε να εκτελεστούν.

Οι εντολές είναι ίδιες με πριν, μόνο που μπαίνει μπροστά ένα J το οποίο υποδηλώνει ότι θα γίνει άλμα ( JMP ) αν η συνθήκη είναι αληθής και το μέρος που θέλουμε να γίνει το jump. Αυτή την διαδικασία την ονομάζουμε διακλάδωση.

  • Για bit

JZ κάπου = Jump if Zero

JNZ κάπου = Jump if Not Zero

JC κάπου = Jump if Carry

JNC κάπου = Jump if Not Carry

JB κάπου = Jump if Bit (1)

JNB κάπου = Jump if Not Bit (0)

Η μόνη λειτουργία που μπορούμε να κάνουμε on the fly είναι η εκκαθάριση του bit με την εντολή BC à JBC κάπου ( Jump and Clear if Bit (1) )

[ATTACH]7082[/ATTACH]

Οι εντολές αυτές είναι σωστές κατόπιν ελέγχουμε ένα και μόνο ένα bit ή θέση μνήμης που είναι bit addressable.

  • Για byte

Αυτό που αλλάζει είναι ότι στην ήδη υπάρχουσα διακλάδωση ενός bit προσθέτουμε το γράμμα C à Compare . Αν θυμάστε είπαμε νωρίτερα ότι ο έλεγχος μεταξύ bytes σχετίζεται με την σύγκριση αυτών. Τα bytes αυτά μπορεί να είναι θέσεις μνήμης ή Registers (πχ Bank Registers ή SFR Registers ).

[ATTACH]7083[/ATTACH]

Το γράμμα D όπως φαίνεται στο πεδίο Operation (λειτουργία) μειώνει κατά ένα αν και μόνον αν η συνθήκη είναι αληθής.

Πολύ σημαντικό σημείο που πρέπει να δώσετε προσοχή είναι η εντολή CJNE( Compare and Jump if Not Equal) .

Αυτή η εντολή επηρεάζει το Carry. Αν έχουμε Α >=Β τότε κάνει το Carry μηδενίζεται, αλλιώς γίνεται 1. Αυτό μας επιτρέπει να εισάγουμε με πλάγιο τρόπο την έννοια του else με μετέπειτα έλεγχο στο CY bit του PSW.

Κατηγοριοποίηση διακλαδώσεων

Αφού αναλύσαμε τις διακλαδώσεις σε bit και byte καθώς και τις λειτουργίες που έχει η κάθε μια ήρθε η στιγμή να οργανώσουμε λίγο τα πράγματα. Αρχικά έχουμε δύο ειδών διακλαδώσεις:

1) Μακρινή ή απόλυτη <χωρίς συνθήκη>

a. Άμεση

b. Έμμεση

2) Κοντινή ή Σχετική <με συνθήκη>

Αυτό που πρέπει να γνωρίζουμε για την Μακρινή Διακλάδωση ( Long JuMP) είναι ότι μπορεί να γίνει σε 64k θέσεις στην μνήμη. Η πιο απλή μορφή (άμεση) είναι 3bytes γιατί η εντολή (που είναι 2byte ) ακολουθείται από κωδικό λειτουργίας της εντολής (που είναι 1byte). H έμμεση διακλάδωση σχηματίζεται με το άθροισμα του DPTR και του ACC.

Αυτό που πρέπει να γνωρίζουμε για την Κοντινή Διακλάδωση ( Short JuMP) είναι ότι αποτελείται από 2 bytes. Δεν μπορούμε να κάνουμε διακλαδώσεις πέρα από το όρια [-128, 127].

ΠΕΙΡΑΜΑΤΙΚΗ ΔΙΑΔΙΚΑΣΙΑ

ΑΣΚΗΣΗ 5.1

Γράψτε ένα πρόγραμμα που να προσθέτει τα περιεχόμενα των αριθμών των 16bitsπου περιέχονται στη μνήμη, ο μεν πρώτος στις θέσεις κωδ1 (high) και kvd1+1 (low, ο δε δεύτερος στις θέσεις κωδ2 (high) και κωδ2+1 ( lowbyte_. Toαποτέλεσμα να φυλάγεται στις θέσεις μνήμης 20h (high), 21h(medium) και 22h (lowbyte).


cseg at 0

[/SIZE] [SIZE=2] mov 60h,#1100b ;high byte 1
mov 61h,#1000b ;low byte 1
mov 50h,#0110b ;high byte 2
mov 51h,#0100b ;low byte 2

[/SIZE] [SIZE=2] mov A,61h
add A,51h
mov 22h,A

[/SIZE] [SIZE=2] mov A,60h
addc A,50h
mov 21h, A

[/SIZE] [SIZE=2] JC HALT ;if C==1 sunexise | else go to HALT
mov 20h,#1

HALT: jmp HALT[/SIZE] [SIZE=2]
end

ΑΣΚΗΣΗ 5.2

Γράψτε ένα πρόγραμμα που να αντικαθιστά τον προσημασμένο αριθμό των 16bitsπου περιέχεται στη μνήμη στις θέσεις κωδ2h+7 (high) και κωδ2h+8 (lowbyte) με την απόλυτη τιμή του.


cseg at 0

[/SIZE] [SIZE=2] mov 20h,#11111111b ;high byte 1
mov 21h,#11111110b ;low byte 1

[/SIZE] [SIZE=2] jnb 20h.7, HALT ;if bit==0 then go to HALT
clr c ; gia tin aferesi
mov A,#0h
subb A,21h
mov 21h,A
mov A,0h
subb A,20h
mov 20h,A

HALT: jmp HALT[/SIZE] [SIZE=2]
end

ΑΣΚΗΣΗ 5.3

Γράψτε πρόγραμμα που να προσθέτει τα περιεχόμενα των θέσεων μνήμης από κωδ1 μέχρι κωδ1+15 στο συσσωρευτή. Αγνοήστε τα κρατούμενα που θα προκύψουν από τις προσθέσεις.


cseg at 0

;Gemizo 40 mexri 4F tis 8eseis me assous
mov R0,#40h
mov R3,#0Fh
gemise:mov A,#1
mov @R0,A
inc R0
djnz R3,gemise
mov A,#0h ; ka8arise pleon ton A
; teleiose i diadikasia gemismatos

mov R1,#40h
mov R7,#0Fh

[/SIZE] [SIZE=2]
loop:add A,@ R1
inc R1
djnz R7,loop

HALT:jmp HALT
end

ΑΣΚΗΣΗ 5.4

Παράδειγμα 1

Να διαβαστεί στο συσσωρευτή ο μεγαλύτερος από τους δύο αριθμούς των θέσεων μνήμης 30hκαι 31h.


cseg at 0

;Gemisma 8eseon
mov 30h,#1h
mov 31h,#2h

[/SIZE] [SIZE=2] MOV A,31h
CJNE A,30h,NEXT ; if ( A >= 31h ) then
; C = 0 (isxuei)
; else
; C = 1 (den isxuei)
NEXT: JNC HALT ; An einai 0 -- diladi isxuei, termatise
MOV A,30h ; Ara einai C==1
HALT: JMP HALT
end

Παράδειγμα 2

Να αντικατασταθεί το περιεχόμενο της θέσης μνήμης 30hμε τη 15hαν είναι μικρότερο από 16h.


cseg at 0

;Gemisma 8eseon
mov 30h,#1h

[/SIZE] [SIZE=2] MOV A,30h
CJNE A,#16h,NEXT ; if ( A >= 16h ) then
; C = 0 (isxuei)
; else
; C = 1 (den isxuei)
NEXT: JNC HALT ; An einai 0 -- diladi isxuei, termatise
MOV 30h,#15h ; Ara einai C==1
HALT: JMP HALT
end

Παράδειγμα 3

Αν ο αριθμός που περιέχεται στη θέση 30hείναι μεγαλύτερος από 7 να αυξηθεί κατά 1 η θέση 31hαλλιώς να μειωθεί κατά 1.


cseg at 0

;Gemisma 8eseon
mov 30h,#1h
mov 31h,#5h

[/SIZE] [SIZE=2] MOV A,30h
CJNE A,#07h,NEXT ; if ( A >= 7h ) then
; C = 0 (isxuei)
; else
; C = 1 (den isxuei)
NEXT: JNC AFKSISE ; An einai 0 -- diladi isxuei pane sto AFKSISE
DEC 31h ; Ara einai C==1
JMP HALT

[/SIZE] [SIZE=2] AFKSISE: inc 31h
HALT: JMP HALT
end

ΑΣΚΗΣΗ 5.5

Γράψτε πρόγραμμα που να αυξάνει κατά 1 το περιεχόμενο της θέσης μνήμης κωδ1 αν αυτό είναι περιττός αριθμός και μεγαλύτερος του #κωδ2.


cseg at 0

[/SIZE] [SIZE=2] ;Gemisma 8eseon
mov 30h,#5h ;kod1
mov 31h,#1h ;kod2

[/SIZE] [SIZE=2] MOV A,30h
CJNE A,31h,NEXT ; if ( A >= 31h ) then
; C = 0 (isxuei)
; else
; C = 1 (den isxuei)
NEXT: JNC PERITOS ; An einai 0 -- diladi isxuei pane sto AFKSISE
; Ara einai C==1
JMP HALT

[/SIZE] [SIZE=2] PERITOS: JNB P, AFKSISE
jmp HALT
AFKSISE: INC 30h
HALT: JMP HALT
end

ΣΥΜΠΕΡΑΣΜΑΤΑ

Κκαταφέραμε να πραγματοποιήσουμε και να κατανοήσουμε τις διακλαδώσεις ή αλλιώς αυτό που λέμε If-Else στον προγραμματισμό. Αποτελεί ένα πολύ δυνατό εργαλείο για την συνέχεια και σίγουρα θα μας βοηθήσει στις επόμενες ασκήσεις.

Χρειάζεται εξοικείωση με τις εντολές ώστε να γνωρίζουμε πότε αυτές τρέχουν και τι τρέχουν. Με αυτό τον τρόπο μπορούμε να επηρεάζουμε τον PC – απαριθμητή προγράμματος και να τον αναγκάζουμε να ανεβοκατεβαίνει στην μνήμη για να βρει εκεί που κάνουμε JMP κάθε φορά. Ο έλεγχος των bits και των bytes παίζει σημαντικό ρόλο ως έλεγχος αλλά και ως built-in λειτουργίες που έχει (όπως πχ να συγκρίνει και δίνει τιμή στο Carry, κάνει Clear ένα bit κλπ κλπ ).

post-928-1414343374,2414_thumb.jpg

post-928-1414343374,2541_thumb.jpg

post-928-1414343374,271_thumb.jpg

Link to comment
Share on other sites

ΣΤΟΙΒΑ ΚΑΙ ΥΠΟΡΟΥΤΙΝΕΣ

Σύντομη θεωρητική εισαγωγή

Τι είναι στοίβα ( stack)

Στοίβα είναι ο χώρος της εσωτερικής έμμεσης μνήμης RAM στον οποίο αποθηκεύονται (φύλαξη) και εξέρχονται (ανάκληση) δεδομένα. Η δομή της στοίβας είναι LIFO – Last In First Out . Συνεπώς κάθε φορά που δίνουμε την εντολή POP (ανάκληση) βγάζουμε από την στοίβα το τελευταίο στοιχείο που υπάρχει στην κορυφή της. Αντίστοιχα κάθε φορά που δίνουμε PUSH ( φύλαξη) στέλνουμε στην δεδομένα στην κορυφή της στοίβας.

Για να γνωρίζουμε κάθε φορά την κορυφή της στοίβας, αρκεί να γνωρίζουμε την διεύθυνση αυτής. Την χρήσιμη αυτή πληροφορία μας την δίνει ο Stack Pointer ( Δείκτης Στοίβας) ή αλλιώς SP Register , οποίος είναι SFR στην θέση 81h. Η δουλειά του είναι να δείχνει διαρκώς την κορυφή της στοίβας. Για αυτό λίγο πριν δώσουμε την εντολή PUSH αυτός αυξάνεται κατά ένα, αντίστοιχα λίγο πριν δώσουμε την εντολή POP, μειώνεται κατά ένα. WARNING: Απαγορεύεται να πειράξουμε χειροκίνητα την τιμή του SP γιατί ο CPU θα μπερδευτεί και θα χάσει την κορυφή της στοίβας.

Μερικές εντολές που αλλάζουν

Μετονομασία Καταχωρητή:

MOV A,#12 à MOV ACC,#12

Επίσης για τους Bank Registers είτε θα δώσουμε την διεύθυνση μνήμης τους:

εντολή:

    PUSH 0

Ή θα δηλώσουμε αρχικά στον assembler ότι έχουμε ενεργεί την Bank 1, γράφοντας την εντολή :

using 1

Και στην συνέχεια γράφοντας την εντολή έτσι όπως θα την γράφαμε:

εντολή :

PUSH R4

Τι είναι υπορουτίνες ( Subroutines)

Είναι ένα μικρό υποπρόγραμμα ή συνάρτηση ( function ) στον προγραμματισμό, όπου έχει αναλάβει να κάνει μία συγκεκριμένη επεξεργασία στα δεδομένα που δέχεται ως ορίσματα και να τα επιστρέφει με νέες τιμές. Για παράδειγμα αν θέλουμε να ελέγξουμε 50 θέσεις μνήμης ανά ζεύγη, τότε προφανώς θα προγραμματίσουμε μία υπορουτίνα να το κάνει για 2 ζεύγη μέσα σε ένα βρόγχο επανάληψης. Οι συναρτήσεις κάνουν το πρόγραμμα πιο ευανάγνωστο και συντηρήσιμο.

ΠΕΙΡΑΜΑΤΙΚΗ ΔΙΑΔΙΚΑΣΙΑ

ΑΣΚΗΣΗ 6.1

Σε αυτήν την άσκηση θα δούμε ένα πρόγραμμα το οποίο να ανταλλάσει υα περιεχόμενα 2 θέσεων μνήμης. Στην συγκεκριμένη περίπτωση οι 2 θέσεις θα είναι οι 3hκαι η 35h.Ο κώδικας του προγράμματος είναι:


cseg at 0

;Theseis mnimis[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
KOD1 equ 3h
KOD2 equ 5h

;1o Bima[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov SP,#7Fh ; Dinoyme timi ston SP

mov R0,#KOD1[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov A,#KOD2

using 0 ;Dilosi ston assembler oti exoume energi tin Bank0[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
push ar0 ;Fulakse to periexomeno tou R0
push acc
pop ar0
pop acc

HALT:jmp HALT[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
end

ΑΣΚΗΣΗ 6.2

Σε αυτήν την άσκηση πρέπει να γράψουμε ένα πρόγραμμα το οποίο να ανακαλεί στον καταχωρητή Β το περιεχόμενο της κορυφής της στοίβας χωρίς να χαλά αυτή ,ούτε και ο SP.Ο κώδικας του είναι:


cseg at 0

;Theseis mnimis[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
KOD1 equ 3h
B_Register equ 0F0h

;1o Bima[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov SP,#7Fh ; Dinoyme timi ston SP

mov 7Fh,#KOD1 ;Dino mia timi[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]

pop B_Register ; decrement SP[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
push B_Register ; increment SP

HALT:jmp HALT[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
end

ΑΣΚΗΣΗ 6.3

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


cseg at 0

;Theseis mnimis[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
KOD1 equ 3h
KOD2 equ 5h

;1o Bima[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov SP,#7Fh ; Dinoyme timi ston SP

mov A,#KOD2 ; A=5[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov R5,#KOD1 ;R5=3

CJNE A,05h, next[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
next:
JC HALT
call subr1 ; SP -> apo 7Fh + 2 = 81h

HALT:jmp HALT[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]

subr1:[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov R5,A
RET ; SP -> apo 81h - 2 = 7Fh
end

ΑΣΚΗΣΗ 6.4

Σε αυτήν την άσκηση θέλουμε να γραφτεί στον καταχωρητή R5 o μεγαλύτερος αριθμός από τους αριθμούς που υπάρχουν στις θέσεις 8000h+KOD2 μέχρι 8003h+KOD2,όπου το KOD2=35h. Ο κώδικας προγράμματος γι αυτό το πρόβλημα είναι:


cseg at 0

;Theseis mnimis[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
KOD1 equ 3h
KOD2 equ 5h


;1o Bima - Initialize SP[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov SP,#7Fh ; Dinoyme timi ston SP

;2 Bima - Gemizo 8000h+KOD2 mexri 8003h+KOD2 tis 8eseis me times 1++[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
MOV DPTR,#8000h+KOD2 ;Arxikopoio ton DPTR
MOV A,#1h ; Arxikopoio ton A

MOV R5,A ; Proti mnimi ston R5

[/SIZE][/FONT] [FONT=Tahoma][SIZE=2] call rFILL
call rFILL
call rFILL


jmp HALT[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
HALT:jmp HALT

rFILL:[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
MOVX @DPTR,A
CJNE A,05h, COMPARE ; if epomeni mnimi >= proigoumenis mnimis
SYNEXISE:
INC A
INC DPTR
RET


COMPARE:[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
JC SYNEXISE
mov R5,A
JMP SYNEXISE
RET
end

ΑΣΚΗΣΗ 6.5

Σε αυτήν την άσκηση μας ζθτείται ένα πρόγραμμα το οποίο να κάνει χρονική καθυστέρηση της τάξεως των 0,2s χρησιμοποιώντας την παρακάτω υπορουτίνα :


cseg at 0

mov SP,#7Fh[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov A,#10h

call subr1[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]

inc A[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
mov DPTR,#0CC00h
movx @DPTR,A
HALT:jmp HALT


subr1:[/SIZE][/FONT] [FONT=Tahoma][SIZE=2]
DELAY: MOV R6, #0C3h
DELAY1: MOV R7, #0FFh
DELAY2: NOP
NOP
DJNZ R7, DELAY2
DJNZ R6, DELAY1
RET
END

Το πρόγραμμα καθώς και η χρονική καθυστέρηση που προκαλεί φαίνεται στην παρακάτω εικόνα :

[ATTACH]7084[/ATTACH]

Όπως βλέπουμε ο χρόνος που κάνει να εκτελεστεί ατό το πρόγραμμα είναι 0,19946s που είναι πάρα πολύ κοντά στα 0,2s.

ΑΣΚΗΣΗ 6.6

Σε αυτήν την άσκηση πρέπει να γράψουμε τις παρακάτω εντολές

DEDOMENA segment idata
rseg DEDOMENA
ds 64
cseg at 0
movSP,#STOIBA-1


. . . . . .

Και να τις ενσωματώσουμε σε ένα πρόγραμμα. Στην συνέχεια θα δούμε τον χώρο τον οποίο δεσμεύσαμε για την στοίβα ανοίγοντας τον φάκελο .m51

Ο κώδικας του προγράμματος είναι:

[ATTACH]7085[/ATTACH]

και ανοίγοντας το αρχείο .M51 παρατηρούμε ότι η θέση που δεσμεύει για την στοίβα είναι είναι από τις θέσεις μνήμης 0008h(που είναι η defaultαπό το πρόγραμμα αρχή της στοίβας ) μέχρι την θέση μνήμης 0040h,δηλαδή 64 θέσεις μετά ,όσο δηλώσαμε εμείς δηλαδή με την εντολή :

ds 64

[ATTACH]7086[/ATTACH]

Αλλάζοντας το ds σε 32 όπως μα ζητείται από τις σημειώσεις τότε παρατηρούμε ότι και οι θέσεις μνήμης που δεσμεύονται από τη στοίβα μειώνονται στο μισό. Παρακάτω παρατίθεται ο κώδικας προγράμματος γι αυτό καθώς και το αρχείο .m51 :

[ATTACH]7087[/ATTACH]

Παρατηρούμε ότι αντί για 0040h που ήταν πριν έχει πάει στο 0020h δηλαδή 32 θέσεις.

post-928-1414343374,9869_thumb.png

post-928-1414343375,2787_thumb.png

post-928-1414343375,3951_thumb.png

post-928-1414343375,451_thumb.png

Link to comment
Share on other sites

Μερικές ασκήσεις χωρίς εκφώνηση, για να βρείτε μόνοι σας τι κάνουν :D

// 7.1


cseg at 0


MOV A,#00100101b

HALT:

//A
MOV C,ACC.0
ANL C,ACC.1 // 1 && 1
MOV ACC.0,C

//B
MOV C,ACC.2
ORL C,ACC.3 // 1 || 1
MOV ACC.2,C

//C
MOV C,ACC.4
CPL C // NOT C
MOV ACC.4,C

//d
MOV C,ACC.5
CPL C
ANL C,ACC.6 // !x*y
MOV F0,C // result is saved to F0

MOV C,ACC.5
ANL C,/ACC.6 // x*!y

ORL C,F0 // 0 || 1

MOV ACC.5,C

//E
MOV C, ACC.7
MOV ACC.7, C


jmp HALT
end

// 7.2


cseg at 0

//Esto KOD1 = 20h
//ESTO KOD1+1 = 21h
//ESTO KOD1+2 = 22h

MOV 20h,#0h
MOV 21h,#11111111b
MOV 22h,21h

//A
MOV ACC,#00001111b
MOV C,ACC.0 // Vazo C=1
MOV 20h.2,C

//B
CPL C // NOT C ==> C=0
MOV 21h.4,C
MOV 21h.5,C
MOV 21h.6,C
MOV 21h.7,C

//C
CPL 22h.0
CPL 22h.1
CPL 22h.2
CPL 22h.3

HALT:jmp HALT
end

// 7.3


cseg at 0

MOV A,#1h
HALT:
MOV 0A0h,A
RL A

jmp HALT
end

// 7.4


cseg at 0
//Esto KOD2=40h
//Esto KOD2+15 = 4F

;Gemizo 40 mexri 4F tis 8eseis me assous
mov R0,#40h
mov R3,#0Fh
mov A,#0h

gemise:
inc A
mov @R0,A
inc R0
djnz R3,gemise
mov A,#0h ; ka8arise pleon ton A
; teleiose i diadikasia gemismatos

// Pollplasiase oles tis times epi 2
mov R0,#40h
mov R3,#0Fh
MOV A,@R0

pollaplasiase:
MOV A,@R0
RL A ; shift aristera
mov @R0,A
inc R0
djnz R3,pollaplasiase




HALT:jmp HALT

// 7.5


cseg at 0

clr C

mov r5,#10001110b //artios
mov 20h,r5
jb 20h.0,next //an perittos pane sto next
jnb 20h.0,carr //an artios pane sto carr
next:
setb acc.0
carr:
setb C


HALT:jmp HALT
end

Link to comment
Share on other sites

TEXNIKEΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ

Σύντομη θεωρητική εισαγωγή

ΒΡΟΧΟΣ (LOOP)

Ο βρόχος είναι μία πολύ συνηθισμένη τεχνική στον προγραμματισμό (βλέπε for, do_while, while ) . Στην Assembly έχουμε μία standard τυποποίηση αυτής της επανάληψης έτσι ώστε να είναι πιο εύκολο το πρόγραμμα κατά τη συγγραφή σου.

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

Όταν έχουμε 2 byte, συνιστάται η χρήση εμφωλευμένης loop.

Σύγκριση προσιμασμένων αριθμών

Το αν ο αριθμός είναι προσιμασμένος ή όχι, φαίνεται από το 7ο bit. Το πρόσημα του αποτελέσματος της αφαίρεσης ελέγχεται από το bit ACC.7 ενώ η ορθότητα του αποτελέσματος από το bit Overflow. Αφαιρώντας από τον αριθμό τη σταθερά ΔΕ θα πρέπει να προκύψει αρνητικό αποτέλεσμα.

ΠΕΙΡΑΜΑΤΙΚΗ ΔΙΑΔΙΚΑΣΙΑ

ΑΣΚΗΣΗ 10.1

Επαληθεύστε ότι η εντολή MUL για τον πολλαπλασιασμό δύο προσημασμένων αριθμών δίνει λάθος αποτέλεσμα:

ΑΣΚΗΣΗ 10.2

ΔΙΝΕΤΑΙ ΕΝΑΣ ΠΙΝΑΚΑΣ ΣΤΗΝ ΜΝΗΜΗ ΠΡΟΓΡΑΜΜΑΤΟΣ ΣΤΙΣ ΔΙΕΥΘΥΝΣΕΙΣ ΑΠΟ 8000h ΜΕΧΡΙ 803Fh ΠΟΥ ΠΕΡΙΕΧΕΙ ΠΡΟΣΗΜΑΣΜΕΝΟΥΣ ΑΡΙΘΜΟΥΣ ΤΩΝ 2 BYTES. ΝΑ ΓΡΑΦΕΙ ΠΡΟΓΡΑΜΜΑ ΠΟΥ ΝΑ ΔΗΜΙΟΥΡΓΕΙ ΕΝΑΝ ΔΕΥΤΕΡΟ ΠΙΝΑΚΑ ΣΤΗΝ ΕΣΩΤΕΡΙΚΗ ΜΝΗΜΗ RAM ΣΤΙΣ ΔΙΕΥΘΥΝΣΕΙΣ ΑΠΟ 0C0h ΜΕΧΡΙ 0FFh ΠΟΥ ΝΑ ΠΕΡΙΕΧΕΙ ΤΙΣ ΑΠΟΛΥΤΕΣ ΤΙΜΕΣ ΤΩΝ ΑΡΙΘΜΩΝ ΤΟΥ ΠΡΩΤΟΥ ΠΙΝΑΚΑ.

ΑΣΚΗΣΗ 10.3

NA ΓΡΑΦΕΙ ΠΡΟΓΡΑΜΜΑ ΠΟΥ ΝΑ ΒΡΙΣΚΕΙ ΤΟ ΜΕΓΑΛΥΤΕΡΟ ΚΑΙ ΤΟ ΜΙΚΡΟΤΕΡΟ ΑΠΟ ΤΟΥΣ ΑΡΙΘΜΟΥΣ ΠΟΥ ΠΕΡΙΕΧΟΝΤΑΙ ΣΤΗΝ ΕΞΩΤΕΡΙΚΗ ΜΝΗΜΗ RAM ΣΤΙΣ ΔΙΕΥΘΥΝΣΕΙΣ ΑΠΟ 8000h ΜΕΧΡΙ 80FFh. O ΜΕΓΑΛΥΤΕΡΟΣ ΑΡΙΘΜΟΣ ΝΑ ΓΡΑΦΕΙ ΣΤΗ ΘΕΣΗ ΜΝΗΜΗΣ 20h ΚΑΙ Ο ΜΙΚΡΟΤΕΡΟΣ ΣΤΗΝ ΑΜΕΣΩΣ ΕΠΟΜΕΝΗ. ΟΙ ΘΕΣΕΙΣ ΤΩΝ ΑΡΙΘΜΩΝ ΝΑ ΦΥΛΑΓΟΝΤΑΙ ΣΤΙΣ ΔΙΕΥΘΥΝΣΕΙΣ 22h – 23h ΓΙΑ ΤΟΝ ΜΕΓΑΛΥΤΕΡΟ 24h – 25h ΓΙΑ ΤΟΝ ΜΙΚΡΟΤΕΡΟ.

ΑΣΚΗΣΗ 10.4

Η ΠΕΡΙΟΧΗ ΕΞΩΤΕΡΙΚΗΣ ΜΝΗΜΗΣ RAM ΜΕ ΔΙΕΥΘΥΝΣΕΙΣ ΑΠΟ 8000Η ΜΕΧΡΙ 8FFFh ΠΕΡΙΕΧΕΙ ΠΡΟΣΗΜΑΣΜΕΝΟΥΣ ΑΡΙΘΜΟΥΣ ΤΩΝ 16 bits. ΓΡΑΨΤΕ ΕΝΑ ΠΡΟΓΡΑΜΜΑ ΝΑ ΕΛΕΓΧΕΙ ΑΥΤΗΝ ΤΗΝ ΠΕΡΙΟΧΗ ΚΑΙ ΝΑ ΜΕΤΡΑ ΤΟΥΣ ΑΡΙΘΜΟΥΣ ΠΟΥ ΕΙΝΑΙ ΜΕΓΑΛΥΤΕΡΟΙ ΑΠΟ -10 ΚΑΙ ΜΙΚΡΟΤΕΡΟΙ Η ΙΣΟΙ ΑΠΟ +10. ΥΠΟΛΟΓΙΣΤΕ ΤΟ ΧΡΟΝΟ ΕΚΤΕΛΕΣΗΣ ΤΟΥ ΠΡΟΓΡΑΜΜΑΤΟΣ, ΑΦΟΥ ΤΟ ΤΡΕΞΕΤΕ.

ΑΣΚΗΣΗ 10.5

ΝΑ ΓΡΑΦΕΙ ΠΡΟΓΡΑΜΜΑ ΠΟΥ ΝΑ ΠΟΛΛΑΠΛΑΣΙΑΖΕΙ ΤΟΥΣ ΔΥΟ ΠΡΟΣΗΜΑΣΜΕΝΟΥΣ ΑΡΙΘΜΟΥΣ ΤΩΝ ΘΕΣΕΩΝ ΤΗΣ ΕΞΩΤΕΡΙΚΗΣ ΜΝΗΜΗΣ 1030Η ΚΑΙ 1031Η . ΤΟ ΑΠΟΤΕΛΕΣΜΑ ΝΑ ΚΑΤΑΧΩΡΕΙΤΑΙ ΣΤΙΣ ΘΕΣΕΙΣ ΜΝΗΜΗΣ 1032Η ΚΑΙ 1033Η .

ΑΣΚΗΣΗ 10.6

ΠΙΝΑΚΑΣ 500 ΘΕΣΕΩΝ ΠΟΥ ΑΡΧΙΖΕΙ ΑΠΟ ΤΗ ΔΙΕΥΘΥΝΣΗ ΜΝΗΜΗΣ 8000Η ΣΤΗΝ ΕΞΩΤΕΡΙΚΗ RAM . ΚΑΘΕ ΘΕΣΗ ΜΝΗΜΗΣ ΠΕΡΙΕΧΕΙ ΕΝΑΝ ΠΡΟΣΗΜΑΣΜΕΝΟ ΑΡΙΘΜΟ. ΝΑ ΓΡΑΦΕΙ ΠΡΟΓΡΑΜΜΑ ΠΟΥ ΝΑ ΑΠΑΡΙΘΜΕΙ ΣΤΟΝ R7 ΤΟΥΣ ΠΕΡΙΤΤΟΥΣ ΑΡΝΗΤΙΚΟΥΣ ΑΡΙΘΜΟΥΣ.

ΑΣΚΗΣΗ 10.7

NA ΓΡΑΦΕΙ ΠΡΟΓΡΑΜΜΑ ΠΟΥ ΝΑ ΑΥΞΑΝΕΙ ΚΑΤΑ 1 ΤΟ ΠΕΡΙΕΧΟΜΕΝΟ ΤΟΥ R7 ΑΝ Ο ΠΡΟΣΗΜΑΣΜΕΝΟΣ ΑΡΙΘΜΟΣ ΤΩΝ 3BYTES ΠΟΥ ΒΡΙΣΚΕΤΑΙ ΣΤΙΣ ΔΙΕΥΘΥΝΣΕΙΣ ΕΞΩΤΕΡΙΚΗΣ ΜΝΗΜΗΣ 1030Η , 1031Η , 1032Η ΕΙΝΑΙ ΜΕΓΑΛΥΤΕΡΟΣ ΑΠΟ ΤΟΝ ΠΡΟΣΗΜΑΣΜΕΝΟ ΑΡΙΘΜΟΣ ΤΩΝ 3 bytes ΤΩΝ ΘΕΣΕΩΝ 1033Η , 1034Η , ΚΑΙ 1035Η

Οι κώδικες:

//Askisi 10.1

ΕΠΑΛΗΘΕΥΣΤΕ ΟΤΙ Η ΕΝΤΟΛΗ MUL ΓΙΑ ΤΟΝ ΠΟΛΛΑΠΛΑΣΙΑΣΜΟ ΔΥΟ ΠΡΟΣΗΜΑΣΜΕΝΩΝ ΑΡΙΘΜΩΝ ΔΙΝΕΙ ΛΑΘΟΣ ΑΠΟΤΕΛΕΣΜΑ.


cseg at 0
MOV A,#0AH ;A=10
MOV B,#0F6H ;B=-10
MOV 20H,A ;TA METAFEROUME SE THESEIS 20H KAI 21H
MOV 21H,B ;OPOU MPOREI NA GINEI PROSPELASI KATA BIT
MOV R0,A
JNB 20H.7, CHECK2 ;AN O PRWTOS DEN EINAI ARNITIKOS PAME NA ELEGKSOUME TO DEFTERO
XRL 20H,#0FFH ;AN EINAI ARNITIKOS VRISKOUME TO SIMPLIRWMA TOU WS PROS 2
MOV A,20H
ADD A,#1
MOV R0,A ;TWRA O R0 PERIEXEI TO SIMPLIRWMA
CHECK2: JNB 21H.7,POL1 ;AN O DEFTEROS EINAI THETIKOS, AFOU O PRWTOS EINAI ÔHETIKOS,POLLAPLASIAZOUME
XRL 21H,#0FFH ;AN O DEFTEROS EINAI ARNITIKOS VRISKOUME TO SIMPLIRWMA GIA NA POLLAPLASIASOUME
MOV A,21H
ADD A,#1
MOV B,A
POL1: MOV A,R0
MUL AB
MOV R0,A
MOV R1,B
LOOP: JMP LOOP
END

//Askisi 10.2

ΔΙΝΕΤΑΙ ΕΝΑΣ ΠΙΝΑΚΑΣ ΣΤΗΝ ΕΞΩΤΕΡΙΚΗ ΜΝΗΜΗ ΠΡΟΓΡΑΜΜΑΤΟΣ ΣΤΙΣ ΔΙΕΥΘΥΝΣΕΙΣ ΑΠΟ 8000h ΜΕΧΡΙ 803Fh ΠΟΥ ΠΕΡΙΕΧΕΙ ΠΡΟΣΗΜΑΣΜΕΝΟΥΣ ΑΡΙΘΜΟΥΣ ΤΩΝ 2 BYTES. ΝΑ ΓΡΑΦΕΙ ΠΡΟΓΡΑΜΜΑ ΠΟΥ ΝΑ ΔΗΜΙΟΥΡΓΕΙ ΕΝΑΝ ΔΕΥΤΕΡΟ ΠΙΝΑΚΑ ΣΤΗΝ ΕΣΩΤΕΡΙΚΗ ΜΝΗΜΗ RAM ΣΤΙΣ ΔΙΕΥΘΥΝΣΕΙΣ ΑΠΟ 0C0h ΜΕΧΡΙ 0FFh ΠΟΥ ΝΑ ΠΕΡΙΕΧΕΙ ΤΙΣ ΑΠΟΛΥΤΕΣ ΤΙΜΕΣ ΤΩΝ ΑΡΙΘΜΩΝ ΤΟΥ ΠΡΩΤΟΥ ΠΙΝΑΚΑ.


cseg at 0
mov DPTR, #8000h
mov R0, #0C0h
mov R1, #0h
goto:
movx A, @DPTR
mov 20h, A
inc DPTR
movx A, @DPTR
mov 21h, A
inc DPTR
jnb 20h.7, com1
mov A, 20h
cpl A
mov 20h, A
mov A, 21h
cpl A
clr C
add A, #1h
mov 21h, A
jnc com1
inc 20h
com1:
mov @R0, 20h
inc R0
mov @R0, 21h
inc R0
inc R1
CJNE R1,#20h,goto
HALT: jmp HALT
end

//Askisi 10.3


org 0
mov DPTR, #8000h
mov 20h, A
mov 21h, A
logo:movx A, @DPTR
inc DPTR
mov R0,DPL
cjne R0, #00h, begin
loop: jmp loop
begin: cjne A, 20h, com1
com1: jc minim
mov 20h, A
mov 22h, DPH
mov 23h, DPL
jmp logo
minim:cjne A, 21h,com2
com2: jnc logo
mov 21h, A
mov 24h,DPH
mov 25h, DPL
jmp logo
end

κώδικας2


org 0
mov SP, #7Fh
mov R0, #00h
mov 21h, #0ffh
mov 20h, #00h
mov DPTR, #7fffh

klop: inc DPTR
movx A,@DPTR

call subr1

djnz R0,klop

loop: jmp loop

subr1: cjne A,20h,next
next : jc opo
mov 20h, a
mov 22h, 83h
mov 23h, 82h

opo : cjne a,31h, goto
goto : jnc son
mov 31h,a
mov 34h,83h
mov 35h,82h
son : ret

end

//Askisi 10.4


org 0
mov SP, #7Fh
mov R0, #00h
mov DPTR, #7fffh
mov r7, #00h
mov r1, #8h
mov r2,#00h

klop: inc DPTR
movx A,@DPTR
mov 20h, a τοποθετούμε κάθε φορά στις διευθύνσεις 20h και 21h
inc dptr της εσωτ. μνήμης RAM τους προσημασμένους
movx a, @dptr αριθμούς των 2 bytes της εξ. μνήμης RAM
mov 21h, a

call subr1

djnz R0,klop
djnz r1, klop

loop: jmp loop

subr1:jb 20h.7, pal
mov a, #0ah
clr c
subb a, 21h
mov a,#00h για αρνητικό προσημασμένο αριθμό κάνουμε τη
subb a, 20h σύγκριση : -10 < αριθμός
jb acc.7, telos
jb OV, telos
inc r7
jmp telos

pal : mov a, #0f6h
clr c
subb a, 21h
mov a,#0ffh για θετικό προσημασμένο αριθμό κάνουμε τη
subb a, 20h σύγκριση : αριθμός  +10
jb acc.7, r7inc
jnb OV, telos
r7inc:inc r7

telos:ret
end


//Askisi 10.5



cseg at 0

mov DPTR,#1030h
movx A, @DPTR
mov 20h, A

mov DPTR,#1031h
movx A, @DPTR
mov 21h, A

mov A, 20h
mov B, 21h

clr F0
jnb 20h.7, com1
cpl F0
CPL A
add A, #1h
mov 34h, A
com1: jnb 21h.7, com2
mov A, 31h
cpl F0
CPL A
add A, #1h
mov 33h, A
mov B, 33h
com2: mul AB
mov 33h, A
mov 32h, B
mov C, F0
jnc loop
cpl A
mov 44h, A
mov A, 32h
cpl A
mov 43h, A
clr C
mov A, 44h
add A, #01h
mov 33h, A
jnc loop
inc 32h
loop: jmp loop
end

//Askisi 10.6


ΔΙΝΕΤΑΙ ΠΙΝΑΚΑΣ 500 ΘΕΣΕΩΝ ΠΟΥ ΑΡΧΙΖΕΙ ΑΠΟ ΤΗ ΔΙΕΥΘΥΝΣΗ ΜΝΗΜΗΣ 8000Η ΣΤΗΝ ΕΞΩΤΕΡΙΚΗ RAM. ΚΑΘΕ ΘΕΣΗ ΜΝΗΜΗΣ ΠΕΡΙΕΧΕΙ ΕΝΑΝ ΠΡΟΣΗΜΑΣΜΕΝΟ ΑΡΙΘΜΟ. ΝΑ ΓΡΑΦΕΙ ΠΡΟΓΡΑΜΜΑ ΠΟΥ ΝΑ ΑΠΑΡΙΘΜΕΙ ΣΤΟΝ R7 ΤΟΥΣ ΠΕΡΙΤΤΟΥΣ ΑΡΝΗΤΙΚΟΥΣ ΑΡΙΘΜΟΥΣ.

[code]
ORG 0
MOV DPTR,#8000H
MOV R7,#0H
MOV LOOPCNTR, #500
LOOP1: MOVX A,@DPTR
JNB ACC.7,NEXT
JNB ACC.0,NEXT
INC R7
NEXT: INC DPTR
DJNE LOOPCNTR, LOOP1
LOOP: JMP LOOP
END

//Askisi 10.7


org 0
mov SP, #7Fh
mov R7, #00h
klop: call com1
loop: jmp loop
com1: mov A, 35h
clr C
subb A, 32h
mov A, 34h
subb A, 31h
mov A, 33h
subb A, 30h
jb ACC.7, R7inc
jnb OV, stop
R7inc: inc R7
stop: ret
end

ΣΥΜΠΕΡΑΣΜΑΤΑ

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

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

-----

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

Προγράμματα: uVision3

Για να συνδέσετε τον μικροεπεξργαστή στο PC και τον προγραμματίσετε θέλετε το Flip.

Καλό coding ;)

Link to comment
Share on other sites

  • 3 months later...

πολυ ενδιαφερον...

εχω ασχοληθει με pic programming αλλα αυτο που θα ηθελα ειναι καποιος προσωμοιοτης (οχι απαραιτητα για pic) για να μπορεσω να παιξω λιγο χωρις breadboard..

εχετε κατι να προτεινετε?

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Δημιουργία...

Important Information

Ο ιστότοπος theLab.gr χρησιμοποιεί cookies για να διασφαλίσει την καλύτερη εμπειρία σας κατά την περιήγηση. Μπορείτε να προσαρμόσετε τις ρυθμίσεις των cookies σας , διαφορετικά θα υποθέσουμε ότι είστε εντάξει για να συνεχίσετε.