NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Microcontroller Programming » knight rider LED animation
December 01, 2010 by archee |
Hi, As my first project I wanted to make my 6 leds work like those on KITT car from "Knight Rider" And I sucsesfuly made all these six leds work like those on KITT(runing forward and backwords) only modifying code from "led_blink.c" But in my opinion my code is too long, I know it can be modified and made like two times shorter.
I figured, that all six DDRC calls can be replaced with DDRC |= 63 0r DDRC |=(0111111) am I wright... and might be there is some other better way to replace it?? and what could be the possible way of optimize LED animation. I`m pretty sure it can be done in some bitwise arithmetical way... or this is as simple(short) as it gets... ?? Thanks in advance |
---|---|
December 01, 2010 by exussum |
Your right with the first call, It can all be done in 1 go, with |=63 or you can stick with it like you are for readability ? The trick here is to bitshift itself.
That Turns the first one on, Delays then turns 0000001 to 0000010 delays again. Loop this forwards and backwards, and you have significantly less lines (4 for the forwards, 4 the for backwards.) I can give working code if that helps ? you will probably understand whats happening better if you write the code yourself though - Hope it works as expected |
December 01, 2010 by bretm |
Here's some short for you (and totally unmaintainable, unexpandable, and incomprehensible):
|
December 01, 2010 by nanaeem |
@bretm: just to satisfy my programmer curiosity: could you explain how you got to this sequence of instructions... |
December 01, 2010 by bretm |
OK, but apologies to archee for derailing the thread a little bit. The KITT animation seems to come up as a topic, and it always bugged me for some reason that there had to be two separate loops, one for forward scan and one for backward scan. I wanted just one loop, which implies a function that looks like this:
where X is the loop index and Y is the series of values (1<<PC0) through (1<<PC5) and back again. You could just put these values into an array, but that didn't seem as fun. ^_^ I knew (from mathematics background) that the function would probably come out simpler if the X values were centered around zero since the Y values are symmetrical, so I shifted the X values by -5.5:
I wanted to stick to integer math if possible, so I doubled all of the X values:
If you graph these points, it looks like a steep vertical peak. I guessed (math background again) that I might get a better fit if the curve were smoother, and I also knew that the KITT animation looks the same backwards as it does forwards, so I reversed the Y values so that it starts from PC5 and goes to PC0 instead of the other way around:
This results in a nice, smooth bowl shape. Next, I knew that rational functions are a powerful way to approximate data using a small number of coefficients, so I plugged these pairs of values into a rational function solver at ZunZun.com. I chose Rational Functions as the family of functions to search. I knew that I didn't have to get an exact fit; it just had to be close enough that the division would be within 0.5 of the right value, because the integer division would truncate the result. The solver came up with a bunch of candidates. I picked a simple one, y = (a ) / (1.0 + b + c( x^2 ) ) + Offset:
I divided by -c in the numerator and denominator to remove one of the coefficients. I rounded the coefficients and got lucky that the results stayed within range after truncation. The for loop generates the X values and the function generates the Y values. You can use the same function for 6 or fewer LEDs, and the same technique to add a 7th, or even 8th, but it gets a bit ridiculous. You can also use the same technique to come up with a function that doesn't repeat the "end" values, e.g. that goes 1, 2, 4, 8, 16, 32, 16, 8, 4, 2 with only one 32 and one 1. In that case you don't have to double the X values to center them on zero as integers.
|
December 02, 2010 by nanaeem |
@bretm: Thanks for the wonderfully detailed explanation. Math is beautiful! |
December 02, 2010 by archee |
@exussum: thanks for answer I made code as you adviced and it was much smaller than my version. I uploaded it and it worked perfectly(at first it crashed my PC, but I think that my WIN7 just played jokes with me and comited a suicide) Sample from code
@bretm: thanks your short code version realy surprised me. I knew it could be shorter, but that it could be this short.. I tried your code. I uploaded it to MCU and it worked perfectly...(and the main thing, because of your long explanation I perfectly understand how it works, and feel like fool for not figuring out that by myself) Just for my curiosity: 1) DDRC = 63; <-- in this line we decler that PC0 to PC5 will work as outputs.. ? 2) if DDRC all registers values are all left at 0 all PC ports will work as inputs.. ? 3) if there is values like 3.1 or 3.5 or 3.9 in integer value they all will be trunced down to 3, 3 and 3... ? OK this far it would be done, now I have to program MCU to make "Knight Rider" intro music, in midi format.. I suppose it will be hard for noob like me, but I like the challange... Cheers, Arturs |
December 02, 2010 by exussum |
To make the code you have smaller, You can use code that actually looks like mine for(i=1;i<7;i++){ PORTC = PORTC<<1; delay_ms(50); } That will save you repeating yourself. And you can do a reverse loop to get back down to 1 from 6. When your happy with that code, Look on to using Bretm's code. to 2) Yes - This will tell you if you have a Binary 1 (5V) or binary 0(0V) on that pin. 3) Look up type casting - for ints yes, It takes the whole number part. 1.9 = 1 1.1 =1 |
December 02, 2010 by exussum |
Forgot to indent code again ... If you would prefer instead of bitshifting the number,
That times it by 2 each time its run, Which is what the bitshift is doing |
December 02, 2010 by bretm |
Just to be clear, I recommend that you don't use my version. You'll come back to it later, or someone else will see your code, and have no idea how it works. Yes, DDRC = 63 will configure PC0 through PC5 as outputs. It will also configure PC6 and PC7 as inputs. If you do DDRC |= 63 instead, it will leave PC6 and PC7 configuration unchanged. (Although the Atmega168 doesn't have a PC7 pin.) Yes, if DDRC is left at 0 all PC pins will be inputs. And yes, if you assign a floating-point value to a register or other integer variable, it will be truncated to an integer. The code I posted uses integer division, so it does not result in fractional values. But even integer division is really slow (although it doesn't matter since it's immediately followed by a much longer delay). |
December 02, 2010 by bretm |
If PORTC starts at (1<<PC0), this will shift it six times and end up at (1<<PC6). The code would have to look more like
because the original code had it sitting at PC0 and PC5 for two times 50ms. I find the following approach to be the most self-explanatory:
This approach also lets you easily define more complex patterns. |
December 02, 2010 by archee |
@exussum: for(i=1;i<7;i++){ PORTC = PORTC<<1; delay_ms(50); } I dont uderstand how this will be working... What I see is that PORTC will be set to 0000001 for 7 times..? in my mind it looks like --> PORTC = 1; and this line done 7 times. Your offered final code should look like this:
@bretm:
I Thanks for answering to my 3 questions |
December 02, 2010 by exussum |
@ archee "I dont uderstand how this will be working... What I see is that PORTC will be set to 0000001 for 7 times..?" If PORTC=1 (00000001) then PORTC bitshifted one value left is 00000010 I didnt know you could do <<= Learn something new all the time. Bitshift 00000010 one to the left is 00000100. The way in nerdkits code is usually 1<<value That means take binary 1 and bitshift it (value) positions, so PC4 if you echo it locally will give you that value which you can confirm by doing a manual bitshift. Hope that made seance |
December 02, 2010 by archee |
Ouuu... thats what it is
loop cycle goes throu and shifts bits from 0000001 to: i=0; 0000010 i=1; 0000100 i=2; 0001000 i=3; 0010000 i=4; 0100000 'PORTC<<=1' this is a bitshift.? No realy Im so green at this. Im learning something new from every replay you give to me. I didn`t knew that its possible to do something like bitshift still have to study this part of bretm`s code
but I dont want to bother you. You have helped me a lot, I ll try some usual methods like google. |
December 02, 2010 by bretm |
The calculations in my funny code won't significantly decrease battery life. They take microseconds. The power will be used mostly in lighting the LED and running delay_ms(50). Whereas the calculations can take a hundred or so clock cycles, one delay_ms(50) call will burn hundreds of thousands of clock cycles. If you really want to extend your battery life, I would recommend doing these things:
Just off the top of my head (not compiled or tested):
|
December 08, 2010 by exussum |
That should work OK too |
December 09, 2010 by Makoto |
I just got my nerd kit a couple of days ago and have only gone through the temp sensor and LED blink projects and while I don't have a complete understanding of what I've done I was able to come up with this solution using only 3 LEDs to test. I'll add that I have never programmed in C but am quite familiar with web based languages like Javascript, PHP, and Actionscript.
I have a lot of questions about some of the parameters but for fear of hijacking this thread, I'll make a new post. -Makoto |
December 09, 2010 by exussum |
DDRC = 63; You dont want that many outputs, And really it should be
7 in binary is 00000111 so only the ones you want are outputs. But the rest seems fine :) |
December 09, 2010 by archee |
there is so many solutions for this one little animation, but how to know which solution is the best for the job.. ? My personal favorite is the one where all otput port adresses are stored in array... In my head it should be the best solution. @:Makoto DDRC=63; was for my six leds 63 -> 0111111 |
December 09, 2010 by Makoto |
Ok, I am starting to get a clearer picture now, this is good. Thank you exussum and archee for the explanations. Its funny, my initial intention for the LED array was to generate a Knight Rider light setup with several different patterns that it could cycle thru, I guess most nerds think alike. :) I will be trying to create a 3x40 grid for my project and incorporate the brightness action applied in the valentines demo. -Makoto |
December 09, 2010 by exussum |
the "best" solution taking everything in to consideration would be a timer based interrupt firing every 50 ms doing either the array style one or a bitshift. I highly doubt theres much performance difference between the two |
Please log in to post a reply.
Did you know that you can make a huge, multi-panel LED display? Learn more...
|