T&T - PIC

 

Shift senza RAM

 


Shiftare un registro su un pin di uscita

E' comune la necessità di scrivere routine di comando per periferiche con ingresso shift register del genere clock + dati (164, 4093, DS1302, ecc). Solitamente si struttura il modulo sotto forma di subroutine che riceve dalla procedura chiamante il dato da shiftare attraverso il registro WREG.
L' impiego di due locazioni RAM, una per il dato e una per il contatore degli shift è prassi comune.

Per un PIC16F possiamo scrive una cosa del genere:

ShiftOut:     ; move 8 bit from WREG to shift register, data + clock
     movwf  saved_data     ;save data
     movlw  0x08           ;set for 8 bit shift
     movwf  shift_cntr
     bcf    shift_datapin  ;preset data pin = 0
     bcf    shift_clkpin   ;and clock pin = 0
sfhtl
     nop                   ;stabilization time
 
    rlf    saved_data, f  ;rotate bit into Carry
     btfsc
  STATUS, C      ;check carry = 0?
     bsf    shift_datapin  ;no - shift data pin = 1
     nop                   ;stabilization wait
     bsf    shift_clkpin   ;shift reg clock high
     bcf    shift_clkpin   ;shift reg clock low
     bcf    shift_datapin  ;shift data pin =0
     decfsz shift_cntr, f  ;count end ?
      goto  sfhtl          ;n - another loop
     return

Per un PIC Enhanced possiamo anche non  utilizzare il Carry:

ShiftOut:     ; move 8 bit from WREG to shift register, data + clock
     movwf  saved_data     ;save data
     movlw  0x08           ;set for 8 bit shift
     movwf  shift_cntr
     bcf    shift_datapin  ;preset data pin = 0
     bcf    shift_clkpin   ;and clock pin = 0
sfhtl
     nop                   ;stabilization time
     btfsc
  save_data,7    ;check bit 7 equ to 0?
     bsf    shift_datapin  ;no - HC164data = 1
     nop                   ;stabilization wait
     bsf    shift_clkpin   ;shift reg clock high
     bcf    shift_clkpin   ;shift reg clock low
     bcf    shift_datapin  ;HC164data pin =0
     rlncf  saved_data, f  ;rotate for next bit
     decfsz shift_cntr, f  ;count end ?
      bra   sfhtl          ;n - another loop
     return

In questi esempi classici sono indispensabili le locazioni di RAM saved_data per salvare il contenuto di WREG e shift_cntr  come contatore.

Ma servono veramente ?


PIC16

Se una locazione di RAM può essere difficile da trovare nell' applicazione, possiamo ricorrere ad un piccolo trucco:

  • pre carichiamo il Carry a 1 un attimo prima della prima rotazione
  • al rotate a sinistra (rlf) il bit 7 del dato andrà al Carry e il contenuto del Carry andrà al bit 0 del dato: abbiamo iniettato un 1 nel dato
  • ne consegue che, qualsiasi sia il valore contenuto inizialmente nel dato, esso è ora diverso da 0
  • dopo la rotazione e il test del Carry, azzeriamolo: la prossima rotazione inietterà uno 0 nel registro

In questo modo, per ogni rotazione, i bit del registro saranno passati al carry per la valutazione del livello da attribuire al pin  di uscita dati, mentre nel registro verrà iniettato uno 0.
Alla ottava rotazione, il bit 1 inizialmente iniettato si troverà nella posizione 7: il dato è ancora diverso da 0.
 La successiva rotazione manderà questo 1 al carry, mentre il contenuto del registro diventerà 0.
Testando questa condizione sul flag Z dello STATUS possiamo verificare che siano stati effettuati 8 shift senza bisogno di un contatore esterno.

ShiftOut:     ; move 8 bit from WREG to shift register, data + clock
     movwf  saved_data     ;save data
     bcf    shift_datapin  ;preset data pin = 0
     bcf    shift_clkpin   ;and clock pin = 0
    
bsf    STATUS, C      ; set carry for the first rotate
sfhtl
     nop                   ;stabilization time
 
    rlf    saved_data, f  ;rotate bit 7 into Carry - Carry to bit 0
     btfsc
  STATUS, C      ;check carry = 0?
     bsf    shift_datapin  ;no - shift data pin = 1
     nop                   ;stabilization wait
     bsf    shift_clkpin   ;shift reg clock high
     bcf    shift_clkpin   ;shift reg clock low
     bcf    shift_datapin  ;shift data pin =0
     movf   saved_data, w  ;test if data = 0
     btfsc  STATUS, Z      ;if >0, another loop
      return               ;if = 0. end and return
     bsf    STATUS, C      ;clear carry for next rotate
    
bsf    sfhtl          ;and loop

La locazione shift_cntr non è più necessaria. Abbiamo risparmiato una locazione di RAM con un lieve aumento del numero delle istruzioni necessarie.


PIC18F

Nel set di istruzioni degli Enhanced sono presenti alcuni vantaggi sostanziosi rispetto ai 16F.

Nei PIC16F l' operazione:

     rlf  WREG, w         

non è possibile in quanto il registro W non è indirizzabile. Occorre allora utilizzare un registro intermedio:

   movf  temporaneo 
  rlf
   temporaneo, w    
     

Invece, un particolare molto interessante del set istruzioni dei PIC18F è quello di poter utilizzare l' accumulatore WREG in modo del tutto analogo agli altri SFR.

Quindi è possibile scrivere semplicemente:

     rlcf  WREG, w         

In questo modo, la rotazione che interessava il registro intermedio può essere effettuata direttamente in WREG, senza occupare alcuna locazione di RAM ausiliaria.

Se poi ricorriamo al piccolo trucco con il Carry, possiamo fare a meno anche della locazione di RAM utilizzata come contatore per i passi dello shift.

ShiftOut:     ; move 8 bit from WREG to shift register, data + clock
       bsf   STATUS, C      ;set carry for the first rotate
shftl  bcf   shift_datapin  ;preset shift data pin = 0
       rlcf  WREG,w         ;rotate data to carry
        bz   shfte          ;if data=0, loop's end
         bnc shft0          ;if not, check carry
       bsf   shift_datapin  ;y - shift data pin = 1
       nop                  ;stabilization wait
shft0  bsf   shift_clkpin   ;shift clock pin high
       bcf   shift_clkpin   ;shift clock pin low
       bcf   shift_datapin  ;shift data pin =0
       clrc                 ;inject 0 on rotate
       bra   shftl
shfte  return

Ora possiamo fare a meno di entrambe le locazioni di RAM ed ottenere una routine più semplice e più compatta.


 

 

Copyright © afg. Tutti i diritti riservati.
Aggiornato il 21/04/11.