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:
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:
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.
|