17. Διαμόρφωση των bits των καταχωρητών GPR και Ι/Ο

Θέτοντας σε 1 τα bits των GPR

Η εντολή SBR (Set Bits in Register) θέτει σε 1 καθορισμένα bits των καταχωρητών γενικού σκοπού. Έχει την ακόλουθη σύνταξη:

SBR  Rd, K ; set bits in register Rd

Όπου Κ είναι μια 8-bit τιμή που μπορεί να είναι μεταξύ 0x00 έως 0xFF και ο καταχωρητής Rd ένας από τους R16 – R31 καταχωρητές GPR. Η εντολή SBR είναι ένα άλλο όνομα για την εντολή ORI η οποία θέτει σε 1 καθορισμένα bits των καταχωρητών γενικού σκοπού και εκείνα των οποίων το bit στη μεταβλητή Κ είναι 1. Για παράδειγμα στο ακόλουθο πρόγραμμα η εντολή SBR θέτει σε 1 τα bits 2, 5 και 6 ανεξάρτητα των προηγούμενων τιμών τους.

LDI  R17, 0b01011001  ;  R17 = 0x59
SBR  R17, 0b01100100 ; set 2, 5 and 6 in register R17

Όταν η εκτέλεση των προηγούμενων εντολών εκπληρωθεί ο R17 περιέχει την τιμή 0x7D

Θέτοντας σε 0 τα bits των GPR

Η εντολή CBR (Clear Bits in Register) μηδενίζει καθορισμένα bits των καταχωρητών γενικού σκοπού. Έχει την ακόλουθη σύνταξη:

CBR  Rd, K  ; clear bits in register Rd

Η σταθερά Κ είναι μια 8-bit τιμή, η οποία μπορεί να είναι από 0x00 έως 0xFF και ο Rd είναι ένας καταχωρητής σκοπού από τον R16 έως τον R31. H εντολή CBR θέτει σε 0 τα bits του καταχωρητή γενικού σκοπού, εκείνα του οποίου η θέση των bits της σταθεράς Κ είναι 1. Για παράδειγμα, στο ακόλουθο πρόγραμμα η εντολή CBR μηδενίζει τα bits 2, 5 και 6 ανεξάρτητα από τις προηγούμενες τιμές τους.

LDI  R17, 0b01011001  ;   R17 = 0x59
CBR  R17, 0b01100100  ;  clear bits 2, 5 and 6 in register R17

Μετά την εκτέλεση των παραπάνω εντολών ο R17 περιέχει την τιμή 0x19

Αντιγράφοντας ένα bit

Όπως είδαμε σε προηγούμενη ενότητα, ένα bit του SREG (καταχωρητή κατάστασης) ονομάζεται T (temporary) το οποίο χρησιμοποιείται όταν θέλουμε να αντιγράψουμε ένα bit δεδομένων από ένα καταχωρητή γενικού σκοπού GPR σε ένα άλλο. Οι εντολές BST (Bit Store from register to T) και BLD (Bit Load from T to register) μπορούν να χρησιμοποιηθούν για να αντιγράψουν ένα bit ενός καταχωρητή σε ένα συγκεκριμένο bit ενός άλλου καταχωρητή.

Η εντολή “BST  Rd, b” αποθηκεύει το bit b από τον καταχωρητή Rd στη σημαία Τ του καταχωρητή κατάστασης, ενώ η εντολή “BLD  Rr, b” αντιγράφει τη σημαία Τ στο bit b του καταχωρητή Rr. Για παράδειγμα το ακόλουθο πρόγραμμα αντιγράφει το bit3 από τον R17 στο bit5 του καταχωρητή R19

BST  R17, 3 ; αποθηκεύει το bit3 από τον R17 στη σημαία Τ
BLD  R19, 5 ; αντιγράφει τη σημαία Τ στο bit5 του R19

Στον παρακάτω πίνακα φαίνονται οι εντολές που μπορούν να γίνουν σε επίπεδο bit πάνω στους καταχωρητές GPR αλλά και στους Ι/Ο καταχωρητές:

Παράδειγμα: Ένας διακόπτης είναι συνδεμένος στο pin PB4. Γράψε ένα πρόγραμμα που να παίρνει την κατάσταση του διακόπτη και να την καταχωρεί στο D0 της εσωτερικής μνήμης RAM και στη θέση 0x200.

Λύση

.EQU  MYREG = 0x200    ;  ορισμός σταθερής τιμής
      CBI  DDRB, 0     ;  κάνε το pin PB0 είσοδο
      IN  R17, PINB    ;  R17 = PINB
      BST  R17, 4      ;  T = PINB.4
      LDI  R16,  0x00  ;  R16 = 0x00
      BLD  R16, 0      ;  R16.0 = T
      STS  MYREG, R16  ;  αντέγραψε τον R16 στη θέση $200 της μνήμης δεδομένων
HERE: JMP  HERE

Ελέγχοντας ένα bit

Για να δούμε εάν ένα bit ενός καταχωρητή γενικού σκοπού είναι 1 ή 0 χρησιμοποιούμε την εντολή SBRS (Skip next instruction if Bit in register is Set) ή την SBRC (Skip next instruction if Bit in register is Cleared).

Η εντολή SBRS ελέγχει ένα bit ενός καταχωρητή και παραλείπει την αμέσως επόμενη εντολή εάν αυτό το bit είναι 1 (HIGH). Η σύνταξη της εντολής SBRS είναι η ακόλουθη:

SBRS  Rd, b  ;  skip next instruction if Bit b in Rd is HIGH

Για παράδειγμα στο ακόλουθο πρόγραμμα η εντολή LDI  R20, 0x55 δεν θα εκτελεστεί επειδή το bit3 είναι HIGH

LDI  R17, 0b00001010
SBRS R17, 3
LDI  R20, 0x55
LDI  R30, 0x33

Η εντολή SBRC παραλείπει την επόμενη εντολή εάν το συγκεκριμένο bit ενός GPR είναι 0 (LOW). Η εντολή αυτή έχει την ακόλουθη σύνταξη:

SBRC Rd, b ; skip next instruction if Bit b in Rd is 0

Στο ακόλουθο παράδειγμα η εντολή “LDI  R20, 0x55” δεν θα εκτελεστεί διότι το bit2 τουR16 είναι LOW.

LDI R16, 0b00001010
SBRC R16, 2 ; skip next instruction if Bit 2 in R16 is cleared
LDI  R20, 0x55
LDI  R30, 0x33

Παράδειγμα:  Ένας διακόπτης είναι συνδεμένος στο pin PC7. Χρησιμοποιώντας την εντολή SBRS γράψε ένα πρόγραμμα που να ελέγχει την κατάσταση του διακόπτη και να εκτελεί τα ακόλουθα:
(α) Εάν switch = 0 να στέλνει τον χαρακτήρα ‘Ν’ στη PortD
(b) Εάν switch = 1 να στέλνει τον χαρακτήρα ‘Υ’ στη  PortD

Λύση

       CBI  DDRC, 7  ;  κάνει το pin PC7 σαν είσοδο
       LDI  R16, 0xFF
       OUT  DDRD, R16
AGAIN: IN  R20, PINC  ; R20 = PINC
       SBRS  R20, 7   ; παράκαμψε την επόμενη εντολή εάν το bit PC7 είναι HIGH
       RJMP  OVER     ; εάν είναι LOW
       LDI  R16, ‘Y’  ; R16 = ‘Y’ ASCII  γράμμα Υ
       OUT PORTD, R16
       RJMP  AGAIN
OVER:  LDI  R16, 'Ν'  ; R16 = ‘N’ ASCII γράμμα Ν
       OUT PORTD, R16 ; Αντιγραφή του R16 στη PortD
       RJMP  AGAIN

Διαχειρισμός των bits των Ι/Ο καταχωρητών

Όπως είπαμε σε προηγούμενη ενότητα, μπορούμε να θέσουμε σε 1 ή 0 τους χαμηλότερους 32 Ι/Ο καταχωρητές (διευθύνσεις 0 έως 31) χρησιμοποιώντας τις εντολές SBI (Set bit in I/O register) και CBI (Clear bit in I/O register). Για παράδειγμα, οι επόμενες δυο εντολές θέτουν σε 1 το PORTD.1 και θέτουν σε 0 το PORTB.4 αντίστοιχα.

SBI  PORTD, 1  ;  set Bit 1 in PORTD
CBI  PORTB, 4  ;  clear Bit 4 in PORTB

Παράδειγμα: Γράψε ένα πρόγραμμα που να εναλλάσσει το pin RB2  200 φορές

Λύση

       LDI  R16, 200   ;  φόρτωσε τον μετρητή στον R16
       SBI  DDR2, 2    ;  DDRB.1 = 1 κάνε το RB1 σαν έξοδο
AGAIN: SBI   PORTB, 2  ;  θέσε σε 1 το bit PB2
       CBI  PORTB, 2   ;  θέσε σε 0 το bit  PB2
       DEC  R16        ;  μείωσε τον R16
       BRNE  AGAIN     ;  συνέχισε μέχρι ο μετρητής γίνει 0

Όπως είπαμε σε προηγούμενη ενότητα μπορούμε να ελέγχουμε ένα bit στους χαμηλότερους 32 Ι/Ο registers χρησιμοποιώντας τις εντολές SBIS (skip if Bit in I/O register is cleared) και SBIC (skip if Bit in I/O register is cleared)

Παράδειγμα: Γράψτε το πρόγραμμα του παραπάνω παραδείγματος χρησιμοποιώντας την εντολή SBIC. :  Ένας διακόπτης είναι συνδεμένος στο pin PC7. Χρησιμοποιώντας την εντολή SBRS γράψε ένα πρόγραμμα που να ελέγχει την κατάσταση του διακόπτη και να εκτελεί τα ακόλουθα:
(α) Εάν switch = 0 να στέλνει τον χαρακτήρα ‘Ν’ στη PortD
(b) Εάν switch = 1 να στέλνει τον χαρακτήρα ‘Υ’ στη  PortD

Λύση

       CBI  DDRC, 7    ;  κάνει το pin PC7 σαν είσοδο
       LDI  R16, 0xFF
       OUT  DDRD, R16
AGAIN:
       SBIC  PINC, 7   ;  παράκαμψε την επόμενη εντολή εάν το Bit PC7  είναι 0
       RJMP  OVER
       LDI  R16,  'N'  ;  R16 = ‘N’  ASCII  γράμμα Ν
       OUT  PORTD, R16
       RJMP   AGAIN
OVER:  LDI R16, ‘Y’    ;  R16 = ‘Y’ ASCII γράμμα Υ
       OUT PORTD, R16
       RJMP  AGAIN

Παράδειγμα: Γράψε το προηγούμενο πρόγραμμα χρησιμοποιώντας την εντολή SBIS

Λύση

       CBI  DDRC, 7   ;  κάνε το pin PC7 σαν είσοδο
       LDI  R16,  0xFF
       OUT  DDRD, R16 ;  κάνε την PortD σαν έξοδο
AGAIN: SBIS  PINC, 7  ;  παράκαμψε την επόμενη εντολή εάν το Bit PC7 είναι 1
       RJMP OVER
       LDI  R16, ‘Y’  ;  R16 = ‘Y’  ASCI γράμμα Υ
       OUT  PORTD,  R16
       RJMP AGAIN
OVER:  LDI  R16,  ‘N’ ; R16 = ‘N’  ASCII  γράμμα Ν
       OUT  PORTD,  R16
       RJMP AGAIN

Ελέγχοντας ένα bit σημαίας

Υπάρχουν μερικές εντολές για τον έλεγχο των bits στον καταχωρητή κατάστασης, όπως φαίνονται στον (ακόλουθο πίνακα). Όλες οι εντολές χωρίζονται σε δυο τύπους: BRBS (Branch if status flag is set) και BRBC (Branch if status flag is Cleared).

BRBS  s, k  ;  branch if status flag bit is set
BRBC  s, k  ;  branch if status flag bit is cleared

Όπου s είναι ένας αριθμός μεταξύ 0 και 7 ο οποίος αντιπροσωπεύει το bit του καταχωρητή κατάστασης και k είναι η διεύθυνση της θέσης στην οποία θα πάει η ροή της εκτέλεσης όταν η συνθήκη είναι αληθής.

Για παράδειγμα στο επόμενο πρόγραμμα η εντολή LDI δεν εκτελείται όταν η σημαία κρατουμένου είναι 1

BRBS 0, L1  ;  branch if status flag bit 0 is set
LDI  R20, 3
L1:

Μπορούμε να γράψουμε το ίδιο απόσπασμα προγράμματος χρησιμοποιώντας την εντολή “BRCS  L1” όπως ακολούθως:

BRCS  L1  ;  branch if carry flag is set
LDI  R20, 3
L1:

Επειδή είναι δύσκολο να θυμόμαστε τα bits του καταχωρητή κατάστασης και να χρησιμοποιούμε τις εντολές BRBC και BRBS μπορούμε να χρησιμοποιούμε τις εντολές του πίνακα για να απλοποιήσουμε τη χρήση των bits του καταχωρητή κατάστασης.

Διαμόρφωση bit σημαίας του SREG

Για να θέσουμε σε 1 μια σημαία χρησιμοποιούμε την εντολή BSET:

BSET  s  ;  flag bit set

Όπου s είναι ένας αριθμός μεταξύ 0 και 7 και παριστάνει το bit που πρόκειται να γίνει 1 στον καταχωρητή κατάστασης. Για παράδειγμα η επόμενη εντολή θέτει σε 1 τη σημαία κρατουμένου:

BSET 0 ;  set bit 0  (carry flag)

Ένα άλλο παράδειγμα, η εντολή “BSET 2” θέτει σε 1 τη σημαία Ν (Negative)

Για να κάνουμε 0 μια σημαία χρησιμοποιούμε την εντολή BCLR (flag bit clear)

BCLR s ;  set bit 0  (carry flag)

Όπου s είναι ένας αριθμός μεταξύ 0 και 7 ο οποίος αντιπροσωπεύει το bit που πρόκειται να γίνει 0 στον καταχωρητή κατάστασης. Για παράδειγμα, η επόμενη εντολή θέτει σε 0 τη σημαία κρατουμένου στον SREG:

BCLR 0  ;  clear bit 0  (carry  flag)

Ένα άλλο παράδειγμα, η εντολή “BCLR  1” θέτει σε 0 τη σημαία Z (Zero).

Ένας πιο προσιτός τρόπος είναι να χρησιμοποιήσουμε την εντολή CLZ όπως φαίνεται στον πίνακα.

Διαχειρισμός bit της εσωτερικής μνήμης δεδομένων RAM

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

Παράδειγμα: Γράψε ένα πρόγραμμα για να δεις εάν η εσωτερική μνήμη RAM στη θέση $195 περιέχει άρτια τιμή. Εάν ναι στείλτε τη στη PortB. Εάν όχι κάντε τη άρτια και μετα στείλτε τη στη PortB

Λύση 1

.EQU MYREG = 0x195
       LDI  R16, 0xFF
       OUT  DDRB, R16 ; κάνε την PortB έξοδο
AGAIN: LDS R16,  MYREG
       SBRS  R16, 0   ; παράκαμψε την επόμενη εντολή εάν το bit D0 είναι 1
       RJUMP  OVER
       CBR  R16, 0b00000001 ; κάνε 0 το D0
OVER:  OUT PORTB, R16       ; αντιγραφή στη PortB
       JMP  AGAIN

Λύση 2

.EQU MYREG = 0x195
       LDI  R16, 0xFF
       OUT  DDRB, R16 ; κάνε την PortB έξοδο
AGAIN: LDS R16,  MYREG
       CBR  R16, 0b00000001 ; κάνε 0  το D0
OVER:  OUT PORTB, R16 ; αντιγραφή στη PortB
       JMP  AGAIN

Παράδειγμα:  Γράψε ένα πρόγραμμα για να δεις εάν στη θέση $137 της εσωτερικής RAM υπάρχει άρτια τιμή. Εάν ναι γράψε την τιμή 0x55 στη θέση $200. Εάν όχι γράψε την τιμή 0x63 στη θέση $200

Λύση

.EQU  MYREG = 0x137
.EQU  RESULT = 0x200
      LDS  R16, MYREG
      SBRC R16, 0
      RJMP  OVER
      LDI  R16,  0x55
      STS  RESULT,  R16
      RJUMP  HERE
OVER: LDI  R16, 0x63
      STS  RESULT,  R16
HERE: RJUMP  HERE