2

I've got an LCD, connected to an Atmega32, working with single characters using this function:

void send_char(uint8_t c){
    PORTD = c; // set the output pins to the ascii value of the char
    PORTB |= 0x05;
    _delay_us(1);
    PORTB &= 0xfa;
    _delay_us(60);
    PORTD = 0x00;
    update_cursor();
}

I can call this with a character as an argument: send_char('a'); and it works.

Then I tried wrapping a send_string function around it:

void send_string(const char * msg){
    while (*msg != '\0'){
        send_char(*msg++);
    }
}

This just puts gibberish on my LCD indicating that the ASCII value has been far off. And when I try passing an empty string (send_string("")) a minimum of three gibberish characters get displayed on the LCD.

fasseg
  • 17,504
  • 8
  • 62
  • 73
  • 1
    Sending with the empty string should be a do-nothing, since `*msg == '\0'`. Is there code being executed after this that might garble your display? Is the display being initialized properly? – nmichaels Nov 23 '10 at 19:19
  • the display seems to be initialized correctly since i can send any number of chars using send_char() and everything is fine and nothing else gets send to the display except an update of the cursor position from send_char. – fasseg Nov 23 '10 at 19:22

4 Answers4

3

First, it seems that you are using the avr-gcc compiler. When making questions for embedded devices, you always need to say which compiler you are using.

I will now try to help you understand what is wrong with your code and why your solution works. The function you have defined:

void send_string(const char * msg);

expects a string pointer in RAM. It doesn't matter that you have used the const keyword, the compiler still expects the string to be in RAM. So if you have a string in ROM:

const char msg[] PROGMEM = "Test";

and you try to pass it in your function:

send_string(msg);

it just passes an invalid address to it and thus gibberish are displayed. If instead you copy it first to RAM, as you did in your solution, it works fine:

char buf[strlen(msg)];
strcpy_P(buf,msg);
send_string(buf);

If you want to define a function that will directly read a ROM string, you can do it like this:

void send_string_P(const char *data)
{
    while (pgm_read_byte(data) != 0x00)
        send_char(pgm_read_byte(data++));
} 

Notice the _P suffix. This is the general convention used to distinct functions that operate on ROM from the ones that operate on RAM.

All these and more are nicely explained here. I also suggest that you try the AVR Freaks forum for these kind of questions. People there will be certainly more experienced in these issues than Stack Overflow users and are always happy to help.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kgiannakakis
  • 103,016
  • 27
  • 158
  • 194
1

I don't see anything obviously wrong with your code (not that I know how to talk to an Atmega32). Try running it under a debugger and print c on every invocation to send_char, or just put printf("%d\n", (int)c); as the first line to send_char.

Keith Randall
  • 22,985
  • 2
  • 35
  • 54
1

This works for me:

#include <stdio.h>
#include <stdint.h>

void send_char(uint8_t c)
{
    printf("%c", c);
}

void send_string(const char * msg)
{
    while (*msg != '\0')
    {
        send_char(*msg++);
    }
}

int main()
{
    send_string("Stackoverflow!");

    return 0;
}

In your code, insert sleep(1); after the send_char() call and see if it changes the behavior you are observing.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
karlphillip
  • 92,053
  • 36
  • 243
  • 426
1

This works on my Atmel controller (although I don't know why):

First one has to add the literal to the ROM via PROGMEM from <avr/pgmspace.h>:

const char msg[] PROGMEM = "Test";

Then copy the literal to a buffer in the controller's RAM:

char buf[strlen(msg)];
strcpy_P(buf,msg);

Now send_string(msg) can be used as expected..

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
fasseg
  • 17,504
  • 8
  • 62
  • 73
  • you did not show us how msg was defined beforehand, how you call send_string() – lImbus Nov 23 '10 at 23:40
  • @limubs: like i wrote in the question i was calling send_string(""). and even with an empty string i would get garbled characters... – fasseg Nov 24 '10 at 13:08
  • @caf: since it's the same as saying const char msg="Test" but the char array has to be in the ROM first in the Atmega32 this did not work. – fasseg Nov 24 '10 at 13:10
  • @smeg4brains: `char buf[] = "Test"` will create `buf` in data space, just like `char buf[strlen(msg)];` does. – caf Nov 24 '10 at 21:04
  • @smeg4brains: That looks like a bug - what does `char buf[1] = "";` do? What about `char buf[1] = { 0 };`? – caf Nov 25 '10 at 00:34
  • @caf: `char buf[1]="";` produces the same garbled result but `char buf[2]={97,0}` does prints an 'a' on the lcd.. – fasseg Nov 25 '10 at 00:49
  • @smeg4brains: You should also be able to use `{'a', '\0'}` if `{97, 0}` works. I would submit this as a compiler bug to the vendor - `char buf[2] = { 'a', '\0'};` and `char buf[2] = "a";` are supposed to be *exactly* the same. – caf Nov 25 '10 at 01:31