Issues with ATTINY2313 and 16x2 LCD with H44780 driver in my C program.

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have the following code and the string 'You won.' is appearing at 0x88 on the LCD (the counter value is flashing in as well).

http://pastie.org/10061802

 

This string is appearing at the start of the run - I'm not sure why this is happening. Do you know what I could be doing wrong? :(

 

Here is a picture of my circuit and what's happening... but everything there seems sound.

 

 

This topic has a solution.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

topstring and winner are not proper strings. They don't have null terminators.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All strings in code (delimited by double quotes "") are automatically null-terminated by the compiler. So unless I'm missing something my strings ARE null terminated and this is not the issue.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All strings in code (delimited by double quotes "") are automatically null-terminated by the compiler.

 But you must give the compiler room to put the null terminator. Both of those strings have 8 characters, so they need at least 9 element arrays to put them into.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:

All strings in code (delimited by double quotes "") are automatically null-terminated by the compiler.

 But you must give the compiler room to put the null terminator. Both of those strings have 8 characters, so they need at least 9 element arrays to put them into.

 

Thank you. I removed the numbers inside the array bracket that determined the size and let the compiler decide the size. It worked out then. I wasn't sure if I could put \0 inside the double quotes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wasn't sure if I could put \0 inside the double quotes.

You can, but it would be the wrong thing to do. The compiler would still add its own NUL character at the end, so if you changed the 8 to a 9, you would still be overflowing the array. Removing the size constraint is the best way to ensure that the array is big enough. Also, since these are fixed string, you should consider putting them into flash.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:

I wasn't sure if I could put \0 inside the double quotes.

You can, but it would be the wrong thing to do. The compiler would still add its own NUL character at the end, so if you changed the 8 to a 9, you would still be overflowing the array. Removing the size constraint is the best way to ensure that the array is big enough. Also, since these are fixed string, you should consider putting them into flash.

 

I am very noob when it comes to AVR. What advantages would I have by putting them in flash? Is there a decent tutorial on how to do this?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No advantage till you get about 1.5K of strings and the ram is all filled up. THEN its nice to have them in flash.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there a decent tutorial on how to do this?

In the most recent versions of the compiler "__flash" is the preferred method. It's not widely documented yet but most of what you need to know is already on this page in the user manual:

 

https://gcc.gnu.org/onlinedocs/g...

 

So your strings would become:

	const __flash char topstring[] = {"SCORE = "}; // this is the string that will be written on the top row along with the
	const __flash char winner[] = {"You won."};

However you are then using those strings with:

Lcd_Send_String(topstring);

But it uses:

void Lcd_Send_String(char a[]);

yet "topstring" no longer matches this. I think the simplest answer is simply to add a new function such as:

void Lcd_Send_Flash_String(const __flash char a[]);

then implement it as:

void Lcd_Send_Flash_String(const __flash char a[])
// This function will send an entire character array to the display
{
    int theLen,i; // set up length variable and index for topstring
    theLen=strlen_P((const char *)a);	//the length of the string we are sending in (we cast the variable to a constant to be used here because strlen requires it)
    for (i=0; i < theLen;i++)
    {
        Lcd_Send(a[i]);     // put ASCII hex code for the given letter/character out on PORTB for the LCD data pins. The ASCII hex codes are handled in the compiler, nice!
    }
    
}

In fact you can do the same in your existing Lcd_Send_String. You don't need the body of the Lcd_Send() code in Lcd_Send_String() - just call Lcd_Send() anyway.

 

Of course if you follow my simple suggestion here you end up with two functions that look almost identical (apart from the type of string pointer passed in and the calls to strlen() or strlen_P()).

 

The "better" solution in my opinion is to ditch the call to strlen() and use a __memx pointer so:

void Lcd_Send_String(__memx char a[])
// This function will send an entire character array to the display
{
	while (*a)
	{
		Lcd_Send((unsigned char)*a++);     // put ASCII hex code for the given letter/character out on PORTB for the LCD data pins. The ASCII hex codes are handled in the compiler, nice!
	}
	
}

__memx is a type of memory pointer that can point to strings in both RAm and Flash so you can call this either with "topstring" (as a __flash pointer) or "variable" (as a RAM pointer to the output of itoa) and it should handle both. It will recognize when "a" is in Flash and will use SPM to access it. When "a" is in RAM it will just use LD.