Byte Shift Code Help

Status
Not open for further replies.

Suraj143

Active Member
I have 14 bytes & needs to shift them Left or Right when I want.But the New_Data must feed into the last feed.
Is there any compact way of writing this than below?

Code:
                        cblock    20h
                        Led1,Led2,Led3,Led4,Led5,Led6,Led7,Led8,Led9,Led10,Led11,Led12,Led13,Led14
                        endc

Left_Shift_14X            movlw        Led2        ;2nd Led
                        movwf        FSR
                        movlw        .13
                        movwf        Temp
Left_Shift_14X_Loop        movf        INDF,W
                        decf        FSR,F
                        movwf        INDF
                        incf        FSR,F
                        incf        FSR,F
                        decfsz        Temp,F
                        goto        Left_Shift_14X_Loop    
                        movf        New_Data,W
                        movwf        Led14
                        return
                
Right_Shift_14X            movlw        Led13        ;13th Led
                        movwf        FSR
                        movlw        .13
                        movwf        Temp
Right_Shift_14X_Loop    movf        INDF,W
                        incf        FSR,F
                        movwf        INDF
                        decf        FSR,F
                        decf        FSR,F
                        decfsz        Temp,F
                        goto        Right_Shift_14X_Loop
                        movf        New_Data,W
                        movwf        Led1
                        return
 
I'd have to play with it a little, but there should be a way to simply use an index pointer that defines the start/end of your data. Instead of moving the data left or right, allow it to be stationary and increment or decrement a pointer instead. Assuming the pointer referenced the oldest data, the value of the pointer would be where the "New_Data" is written to. You can still use INDF/FSR indexing with reference to the incremented or decremented pointer. What flavor of micro are you using?
 
Use a "circular buffer" and just offset the input and output start positions.

You make it so the address "rolls over" back in to the opposite end of the buffer when incremented or decremented beyond the buffer range.

You normally use power-of-two buffer sizes, as that allows the address range to be kept in the buffer by simple bit masking or manipulation. A size of 16 (2^4) is suitable for your needs.

Use a buffer start address with those bits zero at the LSB end, eg. 0x20, 0x030, 0x40

Keep the offset in to the buffer as a single byte variable, a simple number 0-15.
AND that with 0x0F after any change (increment or decrement etc.) That gives you the circular "wrap-around" effect.

Add that offset to the buffer base address and move the result to FSR to read or write a buffer entry.


Once you have that, incrementing or decrementing that has the effect of moving the whole buffer by a step when you read it, relative to the offset number.

Just update the one value at the appropriate position relative to the offset value after an increment or decrement ( or before it, whichever is easier).


It's one of the type of things that can sound complex but is really incredibly simple, once you get the concept stuck in your head.

The same principle also works for any kind of FIFO type buffer for such as serial comms input & output.


Edit - to read out the buffer just using the start address loaded in to FSR, check the next bit of that beyond the buffer mask; ie. the mask is 0x0F, check bit 0x10 - if that is different from whatever the start address bit was, you need to reload the start address before continuing to increment FSR.

eg. if using 0x30, [ 0011 0000 ], incrementing past the end of the buffer gives 0x40 [ 0100 0000 ], bit 4 is wrong. Use a skip as long as that unchanged, or reload FSR if it has changed, in your display readout loop.
 
Last edited:
Even with a non power of two buffer size, it's not difficult to implement a circular buffer. So, if the buffer has to be 14 bytes long, it's not the end of the world, it just makes the rollover calculation slightly more complicated.
 
I don't think that you will get code that is a lot more compact. A circular buffer will execute much faster, but there will still be several lines of code needed for it.

The 12F and 16F processors only have one indirect addressing register, which makes shifts like that somewhat slow. You are only needing to move data by 1, so you can leave the data in the w register while changing the fsr register. If you have to free up the w register, that makes it even slower.

The 18F processors also have 8 bits of data, and they have three indirect addressing registers, along with a way of incrementing or decrementing the fsr register automatically. That makes routines a lot quicker to run and a bit easier to write.

The 24F/33F processors have 16 bits of data, and any of the 16 working registers can be used as indirect registers, also with increment or decrement. The smallest / cheapest 24F processor is $0.80 in quantity and 14 pins.
 
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…