Problems passing char array to subroutine

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

Hi guys

 

Need a bit of help if at all possible.

 

I'm writing a keyboard scanning routine for an ATmega 324P written in C. All is working fine with an attached 44780 LCD giving me the correct row and column address of keys pressed.

 

I just now need to map actual key letters (such as A, B, C, etc.) to row/column addresses.

 

My issue is that I cannot seem to pass a character array to my LCD text display routine.  I'm sure this is down to pointers, but this is an area where I'm not at all strong. Now, I do have a way around this (see the end of this post), but am curious if I'm right about passing a pointer across as opposed to the actual array?

 

Anyhoo, would someone mind casting an expert eye over my code to see where I'm going wrong?

 

This code generates: "passing argument 1 of 'LCD_sendStr' makes pointer from integer without a case"

LCD_sendStr(keymap[key2r][key2c]);

I tried:

 

LCD_sendStr(*keymap[key2r][key2c]);

And ended up with "invalid type argument of unary '*'"

 

 

 

This is my LCD_sendStr routine (which works fine other than with passing my array) :

// (wrapper) LCD routine for sending a string of characters using LCDsenddata
void LCD_sendStr(char *s)
{
	LCD_setRS(LCD_RS_data);		// set RS=1 / character

	int loop = 0;
	while (s[loop] != 0)
	{
		LCD_sendByte(s[loop]);
		_delay_us(45);
		loop++;
	}
}

 

And this is how I have defined my array. I've only gone to 2 rows of keys just as a test) :

#define KEY_ESC   255
#define KEY_F0    254
#define KEY_F1    253
#define KEY_F2    252
#define KEY_F3    251
#define KEY_F4    250
#define KEY_F5    249
#define KEY_F6    248
#define KEY_F7    247
#define KEY_F8    246
#define KEY_F9    245
#define KEY_RET   244
#define KEY_CUP   243
#define KEY_CDWN  242
#define KEY_CLT   241
#define KEY_CRT   240
#define KEY_COPY  239
#define KEY_DEL   238
#define KEY_TAB   237
#define KEY_CAPSL 236
#define KEY_SHFTL 235

const char keymap[2][13] = {
	{ KEY_ESC,KEY_F1,KEY_F2,KEY_F3,KEY_F5,KEY_F6,KEY_F8,KEY_F9,'\\',KEY_CRT,'4','5','2' },
	{ KEY_TAB,'Z',' ','V','B','M',',','.','/',KEY_COPY,'0','1','3' } }

 

 

This is my current work around (compiles, but not tested due to my AVR Dragon having disappeared from Atmel Studio 6.2 - working on that as well lol).

 

					sprintf(TestStr,"%c", keymap[key2r][key2c]);
					LCD_sendStr(TestSre);
Last Edited: Tue. Mar 27, 2018 - 10:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
char keymap[2][13];

means that each element of keymap is a char.

 

 

LCD_sendStr( keymap[key2r][key2c] );

is passing a single element of keymap - so that's  a char.

But

void LCD_sendStr(char *s)

means that the parameter supplied to LCD_sendStr() must be a char*; ie, a pointer to a char - so what you need is:

LCD_sendStr( &keymap[key2r][key2c] );

because '&' is the "address-of" operator in C; ie, it gives you a pointer to its operand.

 

 

LCD_sendStr(*keymap[key2r][key2c] );

is wrong because because '*' is the "pointer dereference" operator in C; ie, it turns a pointer into the pointed-to thing.

 

 

 

However, your actual  LCD_sendStr() function is not just expecting a single character; it is expecting a NUL-terminated string - so your code is not going to work ...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Bottom line: why are you trying to use a sendstr() function to print individual numeric values?

 

The elements in your array are things like:

KEY_CRT,'4','5','2' 

(and KEY_CRT is simply 240). So these are numeric values 240, 52, 53, 50. So if you were simply to say:

LCD_SendStr(52);

which is just the same as:

LCD_SensStr('4');

why would you expect that to work? The value passed into LCD_SendStr() is a "pointer". That is , it is the address of something (should be characters) in memory so why would 52 work? It could only work if memory address 52 happened to contain something looking like characters or more correctly, a number of characters that end with a byte containing 0x00.

 

If you really mean the LCD to show "4" when the key '4' is pressed you need to convert '4' into a string.

 

Maybe you also have an LCD_SendChar() ? if you do then for things like '4' that should work. But if you pass it KEY_CRT it will simply try to print character 240 which may or may not make much sense on an LCD!

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

Thanks for advising awneil - appreciated. I get what you're saying about the string with regards the lack of NULL char. I'm hoping that this will work (it certainly compiles):

LCD_sendStr(strcat(&keymap[key2r][key2c], NULL));

I wasn't even aware of '&' with regards to passing variables so there you go. I'll try (once again! :)) to get my head around passing variables (and references) in C.

 

Now to try and get Win 10 working with my AVR Dragon once more. Usual Jungo USB driver issue :/.

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

banedon wrote:
I'm hoping that this will work (it certainly compiles):

LCD_sendStr(strcat(&keymap[key2r][key2c], NULL));

Don't just "hope" or guess; If in doubt, RTFM - strcat is a standard C function - so you should be able to look it up in your C textbook

 

Or see: http://www.cplusplus.com/reference/cstring/strcat/

 

TL;DR: No, it won't.

 

The most obvious solution would seem to be to have an LCD_sendChar() function for sending a single char, and have your LCD_sendString() function use that for each character in the string.

 

I wasn't even aware of '&' with regards to passing variables

It has nothing specifically to do with passing parameters - it is a standard C language operator.

 

 

Here are some C learning & reference materials for you - including a free online textbook: http://blog.antronics.co.uk/2011...

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm trying to send the ascii values as chars, but will be putting in a catch for anything above 127 to print the special keys description. I hadn't gotten around to adding that yet as I ran into the original issue.

 

I.e.

if (key2r<=1)
{
	switch (keymap[key2r][key2c]) {
		case KEY_ESC   :  LCD_sendStr("[ESC]"); break;
		case KEY_F0    :  LCD_sendStr("[f0]"); break;
		case KEY_F1    :  LCD_sendStr("[f1]"); break;
		case KEY_F2    :  LCD_sendStr("[f2]"); break;
		case KEY_F3    :  LCD_sendStr("[f3]"); break;
		case KEY_F4    :  LCD_sendStr("[f4]"); break;
		case KEY_F5    :  LCD_sendStr("[f5]"); break;
		case KEY_F6    :  LCD_sendStr("[f6]"); break;
		case KEY_F7    :  LCD_sendStr("[f7]"); break;
		case KEY_F8    :  LCD_sendStr("[f8]"); break;
		case KEY_F9    :  LCD_sendStr("[f9]"); break;
		case KEY_RET   :  LCD_sendStr("[RET]"); break;
		case KEY_CUP   :  LCD_sendStr("[UP]"); break;
		case KEY_CDWN  :  LCD_sendStr("[DWN]"); break;
		case KEY_CLT   :  LCD_sendStr("[LT]"); break;
		case KEY_CRT   :  LCD_sendStr("[RT]"); break;
		case KEY_COPY  :  LCD_sendStr("[CPY]"); break;
		case KEY_DEL   :  LCD_sendStr("[DEL]"); break;
		case KEY_TAB   :  LCD_sendStr("[TAB]"); break;
		case KEY_CAPSL :  LCD_sendStr("[CLK]"); break;
		case KEY_SHFTL :  LCD_sendStr("[SLK]"); break;
		default		   :  LCD_sendStr(strcat(&keymap[key2r][key2c],NULL));

	}
}
else LCD_sendStr("   ");

 

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

Ok thanks for the info. I have quite some way to go with C, but I learn best by trying - just the way I'm wired. I'll certainly check out the book that you linked to though. Cheers :)

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

Sounds like something you'd put into your  LCD_sendChar() function...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But that won't work. The keys are NOT STRINGS! Either your default: case need to use something more like LCD_senChar() (assuming you have one and that the key symbol is "printable") or, to use LCD_sendStr() you need to convert the integer to a string first.

I suppose you could just use:

default		   :  {
                        char strval[2];
                        strval[0] = keymap[key2r][key2c];
                        strval[1] = 0;
                        LCDsenStr(strval);
                      }

That makes a short (2 byte) string out of the character you are trying to print.

 

But if you have an LCD_putChar() that's a much cleaner solution. (presumably the LCD_sendStr() routine itself is actually based on repeatedly calling some kind of LCD_putChar() ?)

 

If you are just learning C you'll find this kind of thing much easier to experiment with in a PC program. Standard C has puts() and putchar() which are the "terminal output" versions of your LCD_sendStr() and LCD_putChar()

Last Edited: Tue. Mar 27, 2018 - 11:57 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok modified the 'default:' line to:

						default		   :  LCD_sendChar(keymap[key2r][key2c]);

 

[edit] just seen your latest post clawson. as you can see I did get what you were saying :))

Last Edited: Tue. Mar 27, 2018 - 11:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just to advise all is working - many thanks for the advice.

 

Just got to get the USB side of things working now. What can go wrong? :p