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 » Help needed on counting program

January 18, 2010
by omer921
omer921's Avatar

I am trying o create a simple program that will count from 1 to 300 but after i download it to my MCU the LCD is blank when I checked to see if other programs run on it they do so I don't get what is wrong with it. Here is my program.

#define F_CPU 14745600

#include <stdio.h>

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

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

int main() {

  while(1) {
  // fire up the LCD
  lcd_init();
  lcd_home();
char i;
char g;
while(1) {
char * const g = i+1 ;  
delay_ms(2000);
lcd_write_data(g);

    }

  }

  return 0;
}
January 18, 2010
by Solorbob
Solorbob's Avatar

I would try moving the LCD_init() call before you get into your while loop. That's what I would try first.

January 18, 2010
by N3Roaster
N3Roaster's Avatar

When you ran make on that, you may have noticed the compiler giving some warnings. Specifically,

warning: initialization makes pointer from integer without a cast
warning: passing argument 1 of 'lcd_write_data' makes integer from pointer without a cast
warning: unused variable 'g'
warning: 'i' is used uninitialized in this function

There are some other oddities here as well, such as placing the call to lcd_init() inside a loop and I don't see any logic that would have the count stopping at 300.

Now, when I run this, yes, initially the LCD is blank. It then starts to fill the display one character at a time with a pair of vertical bars, first filling the first line, then the third, then the second, and finally the fourth. I'm going to assume that you wanted the digits of your number displayed. lcd_write_data() is the wrong function for that. What lcd_write_data() does is write a single character to the display. You can use this to get a degree sign, for example.

So, how to fix it? The outer while loop is useless as the inner while loop never exits. That statement and its braces can be removed. Then you've got two separate declarations of the variable g and you're declaring them as different types, but you aren't really using them as characters. You don't need g at all, so get rid of those lines. As for i, you probably want to use that as a counter, but you never increment it. That is, you're never changing the value of i, just assigning g the value of one greater than the unchanging i. To make the intention of the variable clearer, that should be changed to something like a uint16_t (for 16 bit unsigned integer type). Now, why 16 instead of 8? I'll leave that explanation as an exercise for you. Hint: What's 2^8?

In order to get something on the display immediately, we can move the call to delay_ms() to the bottom of the loop, and we should probably switch it from a while to a for in order to get the counting and end condition.

Now, for actually displaying something, first we should clear the display so we aren't just writing new data next to the old data. This causes some flashing and if the delay is removed or substantially reduced you won't see what you're printing, so you may want to instead just reposition the cursor. That works in this case because we're never writing fewer characters than the previous write. Then, we can go to our old friend fprintf_P(). To use this, you'll need to set up a FILE pointer to the LCD. See the projects in the example code download. Finally, since the for loop will eventually exit, we need to place an infinite loop at the end so that we reach the end of the program.

Now, stop reading this post and try to write it yourself. Read the rest of the post if you're stuck.

In the end, you have something that looks like this:

int main() {
    lcd_init();
    FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
    uint16_t i;
    for(i = 1; i < 301; i++) {
        lcd_clear_and_home();
        fprintf_P(&lcd_stream, PSTR("%d"), i);
        delay_ms(2000);
    }
    for(;;);
    return 0;
}

Of course, having a working solution for this problem doesn't necessarily mean that you'll understand how to do something more complicated. For this, a solid understanding of the C language and your libraries will be required. The C Programming Language (Kernighan and Ritchie) is a good starting point. The learning curve there is rather high, but the payoff is worth it. Your local public library will probably have a copy if you don't want to buy it. Once you've gone through that, you'll be set to tackle the avr-libc user manual (Don't have a link handy, Google should pull it right up). Go ahead and skim most of that just to have an idea of what's available in the library. You can always go back to it when you need some portion of that.

As for the lessons to take away from this:

1) Never ignore your compiler warnings. Even if the project builds and gets uploaded, it probably isn't going to do what you had in mind.

2) Use variable types that make clear how you intend to use the variable.

Exercise: This isn't the only way to do it and isn't even the most efficient way to do it. Devise and implement another approach.

January 18, 2010
by N3Roaster
N3Roaster's Avatar

End of paragraph 7, that should be "don't reach the end of the program." One of these days I'll learn to proof read.

January 19, 2010
by pbfy0
pbfy0's Avatar

I'd do it like this

#define F_CPU 14745600

#include <stdio.h>

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

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

int main() {
    // fire up the LCD
    lcd_init();
    lcd_home();
    FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
    uint16_t i;
    for(i = 1; i <= 300; i++){
        lcd_home();
        fprintf_P(&lcd_stream, PSTR("%i"), i);
        delay_ms(2000);
    }
    return 0;
}

Post a Reply

Please log in to post a reply.

Did you know that you can use printf and scanf functions to talk to your computer from your USB NerdKit? Learn more...