NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Knight rider-ish code, with a few questions

September 04, 2010
by sporkalicious
sporkalicious's Avatar

So i wrote up a simple little "knight rider" code after doing the Led blink guide, and though successful it raised a few questions, first here's my code

#define F_CPU 14745600

#include <avr/io.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
//
// PC4 -- LED anode

int main() {
  // LED as output
  DDRC |= (1<<PC5);
  DDRC |= (1<<PC4);
  DDRC |= (1<<PC3);
  DDRC |= (1<<PC2);
  DDRC |= (1<<PC1);
  DDRC |= (1<<PC0);

  // loop keeps looking forever
  while(1) {
    // turn on LED 0
    PORTC |= (1<<PC5);

    // delay 500ms
    delay_ms(500);

    // turn off LED 0
    PORTC &= ~(1<<PC5);

    // turn on LED 1
    PORTC |= (1<<PC4);

    //delay 500ms
    delay_ms(500);

    // turn off LED 1
    PORTC &= ~(1<<PC4);

    // turn on LED 2
    PORTC |= (1<<PC3);

    //delay 500ms
    delay_ms(500);

    // turn off LED 2
    PORTC &= ~(1<<PC3);

    // turn on LED 3
    PORTC |= (1<<PC2);

    //delay 500ms
    delay_ms(500);

    // turn off LED 3
    PORTC &= ~(1<<PC2);

    // turn on LED 4
    PORTC |= (1<<PC1);

    // delay 500ms
    delay_ms(500);

    // turn off LED 4
    PORTC &= ~(1<<PC1);

    // turn on LED 5
    PORTC |= (1<<PC0);

    // delay 500ms
    delay_ms(500);

    // turn off LED 5
    PORTC &= ~(1<<PC0);

    // turn on LED 4
    PORTC |= (1<<PC1);

    // delay 500ms
    delay_ms(500);

    // turn off LED 4
    PORTC &= ~(1<<PC1);

    // turn on LED 3
    PORTC |= (1<<PC2);

    //delay 500ms
    delay_ms(500);

    // turn off LED 3
    PORTC &= ~(1<<PC2);

    // turn on LED 2
    PORTC |= (1<<PC3);

    //delay 500ms
    delay_ms(500);

    // turn off LED 2
    PORTC &= ~(1<<PC3);

    // turn on LED 1
    PORTC |= (1<<PC4);

    //delay 500ms
    delay_ms(500);

    // turn off LED 1
    PORTC &= ~(1<<PC4);
  }

  return 0;
}

Now for the questions

1, Is there way to optimize the cycling of LEDs beyond what i have alreayd done here, and short of trying to run a 2x3 array?

2, Would something along the lines of;

DDRC |= (111111<<PC0);

be an acceptable way to set PC0-PC5 as outputs? I only ask because in the Port C data direction register (DDRC) table on page 88 of the MCU datasheet, the bits appear to be sequential, I ask this more out of curiosity and a lock of desire to accidently screw something up just trying it, than a desire to use some bizarre hard to understand method of setting pins to output mode.

September 04, 2010
by sporkalicious
sporkalicious's Avatar

also to clarify by optimizing it i mean something along the lines of

x=0
y=0
(start a loop)
    // turn on LED X
    PORTC |= (1<<PC"X");

    // delay 500ms
    delay_ms(500);

    // turn off LED 0
    PORTC &= ~(1<<PC"X");
if y=0 x=x+1
if y=1 x=x-1
if x=5 y=1
if x=0 y=0
(end loop)

If something along these lines would work, how would i go about defining the PC"X" in an acceptable manner?

September 04, 2010
by Rick_S
Rick_S's Avatar

You have the basic idea, but the easiest way I've found when scanning an single LED back and forth is to toggle the enitire port rather than the this on/that off method.

Highly simplified code might look more like this:

(Modified borrowed code from an web source...)

uint8_t x=0;  // set x to zero as 8 bit unsigned integer
DDRC = 0xFF;  // This would Set the whole port for output
for(;;)  //Infinate loop
  {
    for(x=1;x<128;x*=2)  // This will increment x by powers of 2 or each binary digit
      {
        PORTC = x;  // set the port to the current value
        delay_ms(150);
      }
    for(x = 128; x > 1; x -= x/2) // Decrement x by power of 2
      {
        PORTC = x;  // set the port to the current value
        delay_ms(150);
      } 
  }

In your code, there would have been a few problems but you are definately on the right track.

1st, in C, you have to declare each variable with a type Instead of

x=0
y=0

You would need something like

uint8_t x=0;
uint8_t y=0;

(start a loop)
    // turn on LED X

Here you have the right idea, but you don't need the PC"X" just x. Such as..

PORTC |= (1<<PC"X");

Would be

PORTC |= (1<<x);

// delay 500ms
delay_ms(500);

The same would be true here

// turn off LED 0
PORTC &= ~(1<<PC"X");

Would become

PORTC &= ~(1<<x);

In c, the equal sign is for assignment so if you say this

if y=0 x=x+1

the if will be true because y is assigned zero not checked against it. If you want to compare y to zero you have to use a double equal sign like this:

if(y==0) x=x+1; // Or if(y==0) x+=1

The same would be true for the rest of your if statements below.

if y=1 x=x-1
if x=5 y=1
if x=0 y=0
(end loop)

Would become

if(y==1) x=x-1;
if(x==5) y=1;
if(x==0) y=0;

One other thing, don't forget parentesis and semicolons in the appropriate places..

I hope that helps a bit...

Rick

September 04, 2010
by sporkalicious
sporkalicious's Avatar

Okay first off, Rick, you are my hero bow =P Thank you for taking the time to help me out, I'm horrible with C but learning quickly(my only prior programming experience is with a TI-83 calculator, lol) Thanks to your help i rewrote the code as follows;

#define F_CPU 14745600

#include <avr/io.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

int main() {
    uint8_t x=0;            // define Current working led number
    uint8_t y=0;            // define directional variable
    DDRC =0xFF;         // set port C to output
        while(1) {          // loop keeps looking forever
        PORTC |= (1<<x);    // Turn LED X on
        delay_ms(500);      // Delay
        PORTC &= ~(1<<x);   // Turn LED x off
        if(y==0) x+=1;      // increment on up
        if(y==1) x-=1;      // decrement on down
        if(x==5) y=1;       // reverse at 5
        if(x==0) y=0;       // reverse at 0
    }

    return 0;
}

and it works wonderfully, I did not use your initial suggestion of a code block simply beacuse I do not exactly understand it, and I simply refuse to use something until I understand it =P, which brings me to my next question. Line 5, and line 10(the for statements) of your code example are a bit confusing to me, after a bit of reading about for loops I think i may have a basic grasp, but I'm not sure, so if it's okay with you I'd like to run by what i think it's attempting to do, and how i could use it in my quick sample project

for(x=1;x<128;x*=2)

what i think this is saying is to start the loop when x=1 (which would require actually initially defining x as 1 to work if I'm right) and keep looping as long as x<128, and for each pass of the loop xis multiplied by 2? my bigest question here is what would the first output value of x be?

for(x = 128; x > 1; x -= x/2)

this one really throws me off though, i understand that once x=128 it does this loop instead which would halve x intil it is equalt or less than 1, what i really don't understand is the halving operation itself.

theoreticly though applying this to my project should follow along the lines of

uint8_t x=0;
DDRC = 0xFF;

for(;;)  
  {
    for(x=0;x<5;x+=1)  
      {
        PORTC = x;  
        delay_ms(150);
      }
    for(x=5;x>0;x-=1) 
      {
        PORTC = x;  
        delay_ms(150);
      } 
  }

Please explain/correct me if I'm wrong, and thanks again for your help.

September 04, 2010
by sporkalicious
sporkalicious's Avatar

okay so after trying my attempt I was abit confused by the results, until i realized i had made a binary counter similar to one of the binary led clocks.. now i think i understand a bit more.. modified your code to create the following(128 would cycle 8 leds i'm only using 6)

for(;;)  
  {
    for(x=1;x<32;x*=2)   
      {
        PORTC = x;  
        delay_ms(150);
      }
    for(x=32;x>1;x-=x/2) 
      {
        PORTC = x;  
        delay_ms(150);
      } 
  }

what i still don't understand is the "-" before the equals sign in the second for statement, Having way too much fun with this now.. should be asleep.. lol

September 05, 2010
by hevans
(NerdKits Staff)

hevans's Avatar

Hi sporkalicious,

The - sign is part of the -= operator which works just like the much more common += operator. These operators are just shorthand that first apply to operator to the variable, and then set the operator equal to the result. So doing

x += 2

is the same as doing

x = x + 2

In this case

x -= x/2

would expand to

x = x - x/2

For this particular example, it turns out that the - is completely irrelevant, since the right side of the equation simplifies to x/2. In other words subtracting half from a number is the same as just dividing the number by two. Hope that makes sense!

Humberto

September 16, 2010
by rdalton
rdalton's Avatar

I would also like to toss a thank you out to Rich. That example was well explained and detailed line by line.

sporkalicious: I do the same thing you do. I won't use a block of code I don't understand. Unfortunately, I don't know C at all so I'm starting from ground zero.

If you come across any C examples for the micro-controller like Rich posted, please post them here.

There are some good ones in the manual but I need more details sometimes.

Thanks.

(sporkalicious: if you don't mind, i'm going to steal your code and try to understand it. :)

Post a Reply

Please log in to post a reply.

Did you know that you can turn a $20 digital scale into a live weight sensor using our kit with a few extra parts? Learn more...