Go Down

### Topic: Efficient control of leds (Read 873 times)previous topic - next topic

#### a.mlw.walker

##### Feb 16, 2013, 08:16 pm
Hi guys
I have 50 leds all in a line. The leds are in pairs (a blue and an orange one).

Each pair of LED's are grouped with every 24th pair of LED's
So if you turn on the first pair (LED 0 & 1)  then you expect LED pair 12 to come on aswell (LED 24 & 25)- and LED 48 & 49 for that matter.
If the LED overflows the 50 (i.e LED pair 3 (4 &5) is paired with 27/28 and 51/52 never mind..
I am trying to think of the best way of controlling the pairs so that the groups all come on.
The state of each LED is stored in an array:
Code: [Select]
` data[0] = 0b0000000000000000; data[1] = 0b0000000000000000; data[2] = 0b0000000000000000; data[3] = 0b0000000000000000;`
so data[0] MSB is LED 0.
So if I turned on pair 1 (LED 0 & 1) Then I need to set the array so that:

Code: [Select]
` data[0] = 0b1100000000000000; data[1] = 0b0000000110000000; data[2] = 0b0000000000000000; data[3] = 0b1100000000000000;`
i.e spaced 24 apart.
However sometimes I may not want to turn on both in a pair.
I originally tried something like this
Code: [Select]
`void LedManager::toggle(int led){ data[led/16] ^= _BV(led%16);}`
However I couldnt work out how to deal with a situation where the first led to turn on was not in data[0] but in one of the other ones.

I was storing the first one of the pairs in an enum:
Code: [Select]
`enum letters {A = 0x00, B = 0x04, C = 0x8, D = 0xa, E = 0xe, F=0x12, G=0x16};`
and then adding 24 to it when calling the above function.

Any better ideas?
I want to be able to set this up and then just call on the enum when I need a group of LEDs to come on.

#### Grumpy_Mike

#1
##### Feb 16, 2013, 08:31 pm
Can you be more explicit about how these LEDs are wired up. A schematic would be good.
The statement:-
Quote
I have 50 leds all in a line. The leds are in pairs

In technical terms means nothing. What are they wired to where are the resistors, do you have supply decoupling fitted, that sort of thing.

#### a.mlw.walker

#2
##### Feb 16, 2013, 08:52 pm
Hi Grumpy Mike
They are wired up using 4 MAX6971 led drivers. Unfortunately I dont have a schematic to hand, but I can show you the code if you like:
Code: [Select]
`LedManager::LedManager(int latch, int Din, int clock){ //Constructor set_output(DDRD, Din); set_output(DDRD, latch); set_output(DDRD, clock); this->Din = Din; this->clock = clock; this->latch = latch; data[0] = 0b0000000000000000; data[1] = 0b0000000000000000; data[2] = 0b0000000000000000; data[3] = 0b0000000000000000; blank();}//Toggle a specific Ledvoid LedManager::toggle(int led){ data[led/16] ^= _BV(led%16);}void LedManager::blank(void){ output_low(PORTD, Din); for (int i=0;i<NUM_LEDS;i++){ clockToggle(); }}void LedManager::refresh(void){ //Data is clocked in on rising edge. //The right-most LED's state is clocked in first for(int i=(NUM_LEDS-1);i>=0;i--){ //get the ith LED state from the array int bit = (data[i/16] & _BV(i%16)); //set the data line high or low if (bit)//!=0 output_high(PORTD, Din); else output_low(PORTD, Din); //clock the data into LED driver(s) clockToggle(); }}void LedManager::clockToggle(void){ output_high(PORTD, clock); __asm__ volatile("NOP \n\t");//19ns delay required, clock is 62.5ns so single NOP sufficient //NOP may not be required at all here //but I'm not certain at what point in the clock cycle output shifts high or low //or what the rise time on the pin is - safer to wait. output_low(PORTD, clock); __asm__ volatile("NOP \n\t");//19ns}void LedManager::latchToggle(void){ output_high(PORTD, latch); __asm__ volatile("NOP \n\t");//30ns required output_low(PORTD, latch);}`
The user must call the function they want to do (eg Toggle(int led)) then call refresh then latchToggle. That updates the state of all the leds.
So I could call Toggle(27);
refresh();
latchToggle();

and LED 27 would be toggled.
What I want to do is be able to create easy to access "groups" of LED's that are defined somewhere, and I can then just call a group name or something. But with the binary states of all the leds stored in an array of size 4 - each element holding a 16bit value, Im not sure the best way to do it?

#### Grumpy_Mike

#3
##### Feb 16, 2013, 11:31 pm
Quote
But with the binary states of all the leds stored in an array of size 4 - each element holding a 16bit value, Im not sure the best way to do it?

Sounds like a good way to do it to me.
At the end of the day the computer has to change bits in variables, often the simplest way to do this is with an array acting as a look up table.
http://www.thebox.myzen.co.uk/Tutorial/Arrays.html
It is written with seven segment display codes in mind but the principal applies to anything you want to output as a pattern.
Quote
So I could call Toggle(27);

So you need to write your own function that toggles a set of values. If these values are held in an array the function consists of a for loop that goes through an array holding your group and toggles the LEDs.
Something like this:-
Code: [Select]
`macroToggle(int group){ // toggles the bits stored in an array called pattern// You have previously defined the array 'pattern' as a long int containing the bit pattern of the group you want to changeint mask = 1;for(int i=0; i<32; i++){    if ( (pattern[group] & mask) != 0 ) Toggle(i)    mask = mask << 1;  }}`
The use of 'mask' which is a variable that contains one 1 and the rest zeros allows you to isolate the bits one at a time and decide what bits to toggle. the mask = mask << 1 shifts that one to the next place so that next time round the loop you look at a different bit in your word that defines the group of LEDs you want to change.

You can write the same sort of functions to set or clear groups defined by arrays.

#### a.mlw.walker

#4
##### Feb 17, 2013, 05:02 pmLast Edit: Feb 17, 2013, 05:24 pm by a.mlw.walker Reason: 1
Hi Mike
Thanks for the response, I think I get it:
assuming I have two patterns stored in the array pattern of type long int (how long is a long it?):
Code: [Select]
`long int pattern[2] = 0;pattern[0] = 0b0000000011111111000000001111111100000000111111110000000011111111;pattern[1] = 0b0101010101010101010101010101010101010101010101010101010101010101;int loop(){macroToggle(0);}macroToggle(int group){ // toggles the bits stored in an array called pattern// I have increased the for loop to size 64 as thats how many bits I have.int mask = 1;for(int i=0; i<64; i++){    if ( (pattern[group] & mask) != 0 ) Toggle(i)    mask = mask << 1;  }}`

Does that then make sense in terms of what you were thinking?

I cant store that bigger pattern( I have 50 leds) in a long int so need to break it down somehow?

#### PeterH

#5
##### Feb 17, 2013, 05:35 pm
You could use 'long long' to get a 64-bit integer, but you don't actually need to get your entire bitmask into a single number - you could just as easily handle it as a byte array of the appropriate length and then iterate through each byte and each bit within the byte.

#### a.mlw.walker

#6
##### Feb 17, 2013, 05:46 pm
Yeah the other thing I was thinking was that doing it this way will start to nail my available flash space.
Is there a neat way I could do it by stating the bit positions rather than defining HUGE binary numbers?
i.e  4,7,11,46
rather than 000010000000000000000000000000000000000100010010000

that would require less memory if I could do it that way right? But can I still do it bit manipulation fast rather than sluggish for loop speed?

#### Grumpy_Mike

#7
##### Feb 17, 2013, 06:36 pm
Learn to use hex, it is much easer to read.
When the code is compiled though the compiler makes the same bit pattern no matter how you define it in the source code.

Go Up