## Circular bit shift with LED's

18 posts / 0 new
Author
Message

Hello

First of all I'm totally new to bit manipulation and I have only before this worked with Arduino. So what I'm trying to do is that I'm programming a function on atmega1284, where I'm trying to make a LED chaser on PORTA. It should run for x amount of shifts going from LSB to MSB (or for that sake the other way around). So for that I'm guessing I would be needing a circular bit shift.

An example would be that rand() gives out integer 21 and the function then shifts the bits so the LED light up one by one for 2 full circles and ending on 0b00010000 where it stops.

This is my code so far (and yes there are parts that is work under progress and mostly for testing and learning). Any help is very appreciated because if been stuck for 20+ hours and this point on trying to make this work.

```#define F_CPU 16000000

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>

#define BUTTON_PRESSED(0 == (PIND & (1 << PORTD2)))
#define LEDSOFF 0
#define LEDSRUNNING_SLOW 1
#define LEDSRUNNING_FAST 2
#define LEDSBET 3

unsigned char LEDState = LEDSBET;
unsigned char CurrentButtonState = 0;
unsigned char PreviousButtonState = 0;

int RotateLeftSlow(int shift) {
if (shift & (PORTA = (unsigned char) 0x8000)) {
PORTA = (shift <<= 1);
_delay_ms(100);
PORTA = (shift |= 1);
_delay_ms(100);
} else {
PORTA = (shift <<= 1);
_delay_ms(200);
}
return (shift);
}

int RotateRightFast(int shift) {
if (shift & (PORTA = 1)) {
PORTA = (shift >>= 1);
PORTA = (shift |= 0x8000);
_delay_ms(100);
} else {
PORTA = (shift >>= 1);
_delay_ms(100);
}
return (shift);
}

void LEDOff() {
PORTA = 0x00;
}

void Bet() // Make a betting system....
{
/*for(int i=0; i<8; i++)
{
PORTA = (0b00000001<< i);
_delay_ms(100);
}*/
}

int main(void) {
// Using DDR register to set all pins for PORTA to output
DDRA = 0xFF;

// If PORTxn is written logic one when the pin is configured as an input pin, the pull-up resistor is activated.
DDRD &= ~(1 << DDD2);
PORTD |= (1 << DDD2);

while (1) {
// Handle the Button activation (going from not pressed to being pressed)
PreviousButtonState = CurrentButtonState;
CurrentButtonState = BUTTON_PRESSED;

if ((PreviousButtonState == 0) && (CurrentButtonState != 0)) { // Change LED state based on the previous state
if (LEDState == LEDSOFF) {
LEDState = LEDSRUNNING_SLOW;
} else
if (LEDState == LEDSRUNNING_SLOW) {
LEDState = LEDSRUNNING_FAST;
} else
if (LEDState == LEDSRUNNING_FAST) {
LEDState = LEDSBET;
} else
if (LEDState == LEDSBET) {
LEDState = LEDSOFF;
}
}
// Handling the output based on the state
if (LEDState == LEDSOFF) {
LEDOff();
}

if (LEDState == LEDSRUNNING_SLOW) {
RotateLeftSlow(rand() % 25);
}

if (LEDState == LEDSRUNNING_FAST) {
RotateRightFast(rand() % 25);
}

if (LEDState == LEDSBET) {
Bet();
}
}
}```

This topic has a solution.
Last Edited: Wed. Sep 15, 2021 - 10:03 AM

welcome to AVRFreaks

kte86 wrote:
I'm totally new to bit manipulation

note that it's all standard C syntax - so you could practice on a "normal" system, like a PC

the key thing about a rotate is that, after you've shifted a bit out of one end,  you have to shift it back in at the other ...

Top Tips:

1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...

How many LEDS are you working with, just 8 connected to PORTA?

Last Edited: Tue. Sep 14, 2021 - 03:28 PM

Thank you and I will have a look at it.

nikm wrote:

How many LEDS are you working with, just 8 connected to PORTA?

Yes that is correct. The general idea is like a roulette game where when I push the button the LEDS should rotate for x amount and then landing on a random single lighted LED

Why mix in delays all over with the shift??---just makes a mess.

Do your shifting, then if wanted, call a delay afterwards

Don't forget to debounce you button(s)

If you use assembler, a ROR command will rotate right, through the carry bit

Some other brands of micros have an additional rotate style, that rotates from the lsb to msb (or msb into lsb), bypassing the carry bit (that would be perfect for your app)

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

kte86 wrote:
This is my code so far (and yes there are parts that is work under progress and mostly for testing and learning)
Don't write the code while you are still designing the solution or what you initially write may bog you down into some convoluted solution that is trying to work around what has already been written. Do the design work separately. When you have a very clear picture of how the code should look in your head then convert that into C and you'll end up with a much cleaner solution.

I think you're introducing to many new concepts to start with.  The old adage goes 'make it work then make it better'

You don't need to do bit shifting for this to start with, it'll be plenty fast enough just to turn the leds on and off.  ie

While(button not pressed)

{

for x = 0; x < 8; x++)

{

Led(x) on

led(x-1) off // Take care of 0 position ie if x =  0 then turn off 7

_delay_ms(250);

}

}

// button pressed

y = random(count)

while(-1)

{

for x = 0; x < 8; x++)

{

Led(x) on

led(x-1) off // Take care of 0 position ie if x =  0 then turn off 7

_delay_ms(250);

count++;

if(count > y)

exit();

}

}//end

avrcandies wrote:

Why mix in delays all over with the shift??---just makes a mess.

Do your shifting, then if wanted, call a delay afterwards

Don't forget to debounce you button(s)

If you use assembler, a ROR command will rotate right, through the carry bit

Some other brands of micros have an additional rotate style, that rotates from the lsb to msb (or msb into lsb), bypassing the carry bit (that would be perfect for your app)

Well without the delay they are flickering so fast that it looks like they are just on all the time but I will try and place the delay elsewhere. Unfortunately I don't know assembler so I would prefer it as pure c.

Thank you for the advice. I will try and do more structured programming in the future.

kte86 wrote:
Well without the delay they are flickering so fast that it looks like they are just on all the time but I will try and place the delay elsewhere.

```count = get_a_count();

for (i = 0; i < count; i++)
{
shift_leds_one_over();
delay();
}```

With high level language the "shifting" can just be done with high level loops.

have a routine that lights the needed led

this can just  be a bunch of if else

Illuminate_Led(position)

if (position==0)

{PORTA = 0x01;}

else if (position==1)

{PORTA = 0x02;}

else if (position==2)

{PORTA = 0x04;}

etc

Then just form loops  ,

say from 0 to 6 and calling the Illuminate_Led

form a following loop  7 to 1 and calling Illuminate_Led

repeat these two loops endlessly   0123456 7654321 0123456 ....etc

toss in a delay at the exit of  Illuminate_Led

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Tue. Sep 14, 2021 - 05:01 PM

With a CPU as big (in memory and resources) as the ATmega1284, you don't want to tie up the whole CPU with something as simple as running a single 8-bit/8/_LED "Knight Rider/Cylon LED" strip.

Set one of the timers to interrupt every 1 milli-second.   Increment a volatile 32-bit integer counter ('millis')  on each interrupt.   Have a 16-bit integer that counts the number of 1ms interrupts before the LED changes.  This is the LED_interval.     Each single lighted LED position is a 'frame'.  Basically you have an animation with 14 frames, 8 frames of moving the LED right from position 0 to position 7, and then 6 frames of moving the LED left from position 6 to position 1.  Positions 0 and 7 are lighted for only one LED interval.

Say you are rotating a single lighted LED back-and-forth from position 0 on the far right to position 7 on the far left; 8 positions total; twice a second.  That is 28 frames a second: 36 ms per frame.  Have an array of 14 8-bit values with each value representing how PORTA will be lighted with one LED for that frame:  LightedLED[14] = {  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02 };    Now you need a 'frameCounter' variable.   Increment it each time that you change the LED frame with in the main's while(1) loop:

#define  MS_PER_FRAME  36

unsigned long   millis=0, currentFrameIntervalEnd = MS_PER_FRAME;

if (millis == currentFrameIntervalEnd) {

currentFrameIntervalEnd = millis + MS_PER_FRAME;

PORTA = LightedLED[frameCounter];

frameCounter += 1;

if (frameCounter == 14) frameCounter=0;

}

There are no delay routines so that the CPU can be running through all the other things in the while(1) loop,  while running the LED chaser seemingly in the background.

Thank you so much this really seems like something that would work great for me. Just have to read up on timers first. Haven't been working with that before

This reply has been marked as the solution.

kte86 wrote:

```int RotateLeftSlow(int shift) {
if (shift & (PORTA = (unsigned char) 0x8000)) {
PORTA = (shift <<= 1);
```

Your test against 0x8000 is wrong - 0x0100 is probably what you meant.

However - Your main bug is that you don't have a shifting loop for the number of shifts requested.

Try this code instead: (NB: I've used 8-bit shits instead of 16-bit shifts. You do know AVR is only an 8-bit processor so there is a cost for 16-bit operations)

```void RotateLeftSlow (uint8_t nrShifts)
{
/* You might want a random starting pattern; you didn't say */
#   define START_PATTERN 0b00000001

uint8_t pattern = START_PATTERN;
PORTA = pattern;
_delay_ms(100);

for (uint8_t shift = 0; shift < nrShifts; shift++) {
if (pattern)
pattern <<= 1;
else
pattern = 1;

PORTA = pattern;
_delay_ms(100);
}
}
```
Last Edited: Wed. Sep 15, 2021 - 09:56 AM

Thank you so much. This was exactly what I was looking for :)

For a genuine circular shift, I'll just throw this in, would work with any pattern

```static void circular_left_shift(uint8_t n)
{
static uint8_t pattern = 0x80;
while (n--)
{
pattern = (pattern << 1) | (pattern >> 7);
printf("pattern %02x\n", (unsigned int)pattern);
}
}

int main(void)
{
circular_left_shift(5);
circular_left_shift(5);
}
```

pattern 01
pattern 02
pattern 04
pattern 08
pattern 10
pattern 20
pattern 40
pattern 80
pattern 01
pattern 02