Shift Right with 16 bit numbers

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have setup Timer1 and it is outputting a steady stream of pulses. Now I want to change the speed of the pulses in steps of 2X, 4X, 8X, 16X etc. I am working in Assembler

I have played with developing the number and saving it in the EEPROM and calling it and loading it into the timer1 registers. This will work no problem. However I am wondering if I can take the number for the original pulse rate and shift it right once for 2X, twice for 4X etc.

I know how to do this with an 8 bit number but this is working on only one register. Now with a 16 bit number it is two registers! I have read about shifts and carries and my head hurts.

So my question is how does one do a divide by 2 on a 16 bit number? Or should I not be trying to be so clever and go with the original plan?

Can I do this operation on the OCR1AH and OCR1AL registers directly or do you have to do this in R24/25 and load the result into OCR1AH/L?

Thank you

Bob Parry

Bob Parry

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For 16 bit numbers the carry is where the extra bit goes when it falls off either end. If you shift left 0b10000000 the carry flag will then be 1. If you shift left 0b01000000 then the 0 in the 7th bit shifts to the carry. Then when you work with the other register the carry flag shifts into that. So 0b00000000 shifted left with the carry flag set becomes 0b00000001. You can also rotate ROL for example the carry flag moves into bit position 0 and bit7 moves into the carry flag.

It's all there in the assembler help file for each command with diagrams that show the action on the byte in question as well as the registers the command can operate on.

By the way, simple addition is all you need for a divide by 2,4,8,16 etc... Just increment a register every time the timer generates an interrupt. Bit 1 will toggle at 1/2 the rate, bit 2 will toggle at rate/4 etc...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

robpar wrote:
I know how to do this with an 8 bit number but this is working on only one register. Now with a 16 bit number it is two registers! I have read about shifts and carries and my head hurts.
The procedure to use depends on whether the 16-bit value is signed or unsigned. Say you have an unsigned value in r25:r24. To shift it right once use:

lsr r25
ror r24

The first instruction shifts r25 right one bit, shifting in a zero to the MSB and placing the LSB in the carry. The second instruction rotates r24 right so that the carry goes into the MSB.

If the value is signed, you use instead:

asr r25
ror r24

The arithmetic shift right differs from the logical shift right in that the MSB stays the same. This preserves the sign of the result so that a negative value remains negative.

The same procedure can be extended to any number of bytes; simply use the rotate instruction on all bytes other than the most significant byte.

A left shift operation is similar except that you work from the least significant end toward the most signficant using a logical shift left on the least significant and a rotate left on all remaining bytes.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Then when you work with the other register the carry flag shifts into that.. So 0b00000000 shifted left with the carry flag set becomes 0b00000001.

To be clear, this part is done with ROL and ROR. So to shift a 16 bit number right you need:

LSR highByte
ROR lowByte

For shifting left:

LSL lowByte
ROL highByte

These commands work with all 32 registers

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Remember that for coarser steps, the timer prescaler typically offers /1, /8, /64, /256, /1024.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I have played with developing the number and saving it in the EEPROM and calling it and loading it into the timer1 registers

Be aware that EEPROM is guaranteed to do 100.000 writes before it's worn out.
Sounds alot but if you write to it several times every second you will have trouble.
Better to store temporary values in SRAM, that have no limitation of number of writes. It is also faster to access.
The purpose of EEPROM is to save values that must not be lost when you turn off power.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I had not thought of using the prescale. What a good idea. It gives view options for frequency however I may not actually need that many options.

Good Idea Thanks Lee.

I now have a better idea of how to do Shifts thanks for the lesson.

Bob Parry

Bob Parry

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

how would i need to change this code to divide a 32-bit number?

Koshchi wrote:

To be clear, this part is done with ROL and ROR. So to shift a 16 bit number right you need:

LSR highByte
ROR lowByte

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i think this works

LSR Byte3
ROR Byte2
ROR Byte1
ROR Byte0
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know what you are using it for so this could be off target!

When I need to be able to change the speed that something is call'ed at (make a tone etc).
1. I make a timer interrupt that run's at the highest speed I need.
2. I have 2 registers 1. keeps a count, and the 2. holds a number that I add to the first in each interrupt, if I get a carry I call my "tone".
So if I add 128 I get 1/2 of the speed, 64 1/4 etc.
(Yes I know that that I can't make full speed this way, if needed just check a bit to bypass the check and call every time!)

Jens

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mustihi wrote:
i think this works

LSR Byte3
ROR Byte2
ROR Byte1
ROR Byte0


Yes, this is correct.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mustihi wrote:
i think this works

LSR Byte3
ROR Byte2
ROR Byte1
ROR Byte0


If it's an unsigned 32-bit value, yes. If it's signed, use ASR instead of LSR.

Don Kinzer
ZBasic Microcontrollers
http://www.zbasic.net

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
If it's signed, use ASR instead of LSR

True. This goes for signed values of any length.

Regards,
Steve A.

The Board helps those that help themselves.