Author Topic: C Code Problem  (Read 13000 times)

0 Members and 1 Guest are viewing this topic.

Offline DigibinTopic starter

  • Regular Contributor
  • *
  • Posts: 90
Re: C Code Problem
« Reply #25 on: January 16, 2015, 04:15:53 pm »
Oops, my function didn't actually operate on char_freq_Hz_avg so of course nothing is displayed. I've updated it to create the chars in a buffer array and then copy that array into 'char_freq_Hz_avg', and concatenate it with 'kHz':

Code: [Select]
static void itokhz(unsigned int freq, char* char_freq)
{ char buffer[8];
buffer[7] = '\0';
freq /= 100; // get to the hundreds
buffer[6]=(freq % 10) + '0'; // convert the hundreds to ASCII char
freq /= 10; // get to the thousands
buffer[5]='.'; // insert decimal point
buffer[4]=(freq % 10) + '0'; // convert the thousands to ASCII char
freq /= 10; // get to the ten thousands
if (freq) // if the ten thousands is non-zero
{ buffer[3]=(freq % 10) + '0'; // convert the ten thousands
freq /= 10; // get to the hundred thousands
}
if (freq) // if the hundred thousands is non-zero
{ buffer[2]=(freq % 10) + '0'; // convert the hundred thousands to ASCII char
freq /= 10;
}
if (freq) // if the millions is non-zero
{ buffer[1]=(freq % 10) + '0'; // convert the millions to ASCII char
freq /= 10;
}
if (freq) // if the tens of millions is non-zero
{ buffer[0]=(freq % 10) + '0'; // convert the tens of millions to ASCII char
freq /= 10;
}
strcpy(char_freq, buffer);
strcat(char_freq, " kHz");
}

I then call this using:

char char_freq_Hz_avg[16];
itokhz(freq_Hz_avg, char_freq_Hz_avg);

Full code attached. All I get on the display is " kHz". If in the function I create a test array buffer2 and give it some arbitrary content, and then call strcpy on buffer2, it's then displayed o the LCD. So this suggests that the buffer array is empty - am I writing to it incorrectly?
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5313
  • Country: gb
Re: C Code Problem
« Reply #26 on: January 16, 2015, 04:43:33 pm »
Either way, to be productive, ie realistically writing production code, for a new platform in three days froms scratch, is a very big ask indeed.
I have 30+ years experience--perhaps that's why it doesn't take me long to get up to speed on something new.

Sadly, next year I will have had 40 years' at it. I finally started on ARM anout six months ago having moved from PICs, with 20 years on them, and their precursor CP1600 and LP8000 chips from GI in the mid 70s, with a large helping of Z80, 6502, 6800 and x86 in between.

I found with ARM I spent an awful lot of time working out the difference between the various cores, and then doing a shootout between some Cortex M4s from TI and NXP. I now use both depending on the application. But I'd say it took several weeks to get up to speed. Have you ever looked at just the clocking on the LPC4300 series? That's not trivial in itself, and that's just one small facet. You need to to learn their peripheral libraries, most of the underlying peripherals at a register and hardware level, the subtleties and features of their IDEs to name but a few. The same applies to TI, although they have the dicotomy of too much documentation, in that it's hard to know which document to start with there's so much of it.

If you can port an RTOS from ARM to PIC32 in a week, mastered the IDE and debugging tools, and can present it as a finished product then well done. But don't forget, there's a lot more to a system than just that RTOS. You can spend an entire day just getting your head round DMA, or a serial peripheral for example.
 

Offline AndreasF

  • Frequent Contributor
  • **
  • Posts: 251
  • Country: gb
    • mind-dump.net
Re: C Code Problem
« Reply #27 on: January 16, 2015, 05:39:05 pm »
Quote
... Full code attached. All I get on the display is " kHz". If in the function I create a test array buffer2 and give it some arbitrary content, and then call strcpy on buffer2, it's then displayed o the LCD. So this suggests that the buffer array is empty - am I writing to it incorrectly?

There are two options for itokhz. Either eliminate the local creation of the buffer variable and use it directly with the external char array:
Code: [Select]
//static void itokhz(unsigned int freq, char* char_freq)
static void itokhz(unsigned int freq, char* buffer)
{
         //char buffer[8];

...
//char buffer2[8] = "0001.2";

//strcpy(char_freq, buffer2);
strcat(buffer, " kHz");
}

Or make a call to strcpy(char_freq, buffer) before strcat.

I would do the fist, as there is no need to create a whole new character array inside the function, only to then strcpy it to the external char array!

That's also what I was referring to earlier. You are creating a string (i.e. character array) which simply acts as a buffer of characters that then gets transmitted to the LCD. In my opinion that's wasteful, and you can directly transmit individual characters to the LCD (though you would have to start with the most significant digits).
my random ramblings mind-dump.net
 

Offline Brutte

  • Frequent Contributor
  • **
  • Posts: 614
Re: C Code Problem
« Reply #28 on: January 16, 2015, 07:35:09 pm »
I have enough memory, according to the Program Memory Usage and Data Memory Usage reported by the compiler, yes?

No.
(..)
Additionally functions may at run time dynamically allocate memory from the heap. 
Stack overflows are PITA on tinies. It is a little easier on megas, but still PITA. Zillions of posts on the subject on avrfreaks - please help yourself.
As for heap - avrgcc and avrlibc does not use heap implicitly. The malloc() is the only way to use heap with that library. All scanfs, printfs and alike are stack based only.

@OP: My suggestion for you would be to use <assert.h>

EDIT: OMG, attiny48?

My suggestion for you would be to grow up.
 

Offline Sal Ammoniac

  • Super Contributor
  • ***
  • Posts: 1660
  • Country: us
Re: C Code Problem
« Reply #29 on: January 16, 2015, 08:48:44 pm »
Sadly, next year I will have had 40 years' at it. I finally started on ARM anout six months ago having moved from PICs, with 20 years on them, and their precursor CP1600 and LP8000 chips from GI in the mid 70s, with a large helping of Z80, 6502, 6800 and x86 in between.

My list includes 6502, Z80, 68000, x86, 8X305, AMD2901, ARM, SH, PDP-11, VAX, and several that I'm probably forgetting.

Quote
Have you ever looked at just the clocking on the LPC4300 series? That's not trivial in itself, and that's just one small facet.

Yes, in fact my most recent development board for ARM has an LPC4357 on it. The clocking, although complex, is not difficult, just tedious.

Quote
You need to to learn their peripheral libraries

I never use a manufacturer's peripheral libraries. I write my own peripheral drivers directly on the bare metal. I find this takes less time than trying to understand the operation and bugs of someone else's libraries. When I write my own code, I know how it works and it's not just a black box to me.

Quote
If you can port an RTOS from ARM to PIC32 in a week, mastered the IDE and debugging tools, and can present it as a finished product then well done. But don't forget, there's a lot more to a system than just that RTOS. You can spend an entire day just getting your head round DMA, or a serial peripheral for example.

That is true, especially for some MCUs with needlessly complex peripherals.
Complexity is the number-one enemy of high-quality code.
 

Offline zapta

  • Super Contributor
  • ***
  • Posts: 6189
  • Country: us
Re: C Code Problem
« Reply #30 on: January 16, 2015, 08:54:43 pm »
lcd_puts() is fine.

The issue is with the conversion of freq_Hz_avg to a string, when freq_Hz_avg is less than 1000.

You used a lot of string functions, particularly sprintf(). They are quite expensive in terms of space + time. Try to think something else.

In the mean time, you can replace the whole section with a one-liner:

Code: [Select]
sprintf(char_freq_Hz_avg, "%lu.%lu kHz   ", freq_Hz_avg/1000, (freq_Hz_avg % 1000) / 100);

No %0n prefix for the second %lu ?
 

Offline DigibinTopic starter

  • Regular Contributor
  • *
  • Posts: 90
Re: C Code Problem
« Reply #31 on: January 16, 2015, 10:24:56 pm »
I may have been having some issues with the LCD display. It started flashing on and off (backlight too). The supply voltage was fine so I think the LCD hardware may be going bust. Swapped it for an old one I have lying around which works fine, but is only 2x8 as opposed to 2x16.

I would do the fist, as there is no need to create a whole new character array inside the function, only to then strcpy it to the external char array!

I did try it that way but couldn't get it to work. However I followed your suggestions and have modified the function to:

Code: [Select]
static void itokhz(unsigned long int freq, char* buffer)
{ if (freq >= 100000)
{// buffer = "OVERLOAD";
buffer[0] = 'O';
buffer[1] = 'V';
buffer[2] = 'E';
buffer[3] = 'R';
buffer[4] = 'L';
buffer[5] = 'O';
buffer[6] = 'A';
buffer[7] = 'D';
buffer[8] = '\0'; 
}
else
{ buffer[4] = '\0';
freq /= 100; // get to the hundreds
buffer[3]=(freq % 10) + '0'; // convert the hundreds to ASCII char
freq /= 10; // get to the thousands
buffer[2]='.'; // insert decimal point
buffer[1]=(freq % 10) + '0'; // convert the thousands to ASCII char
freq /= 10; // get to the ten thousands
if (freq) // if the ten thousands is non-zero
{ buffer[0]=(freq % 10) + '0'; // convert the ten thousands
freq /= 10; // get to the hundred thousands
}
else
{ buffer[0]=' '; }
strcat(buffer, " kHz");
}
}

This now works, and I get the string displayed on the lcd. Due to the limit of 8 chars I can't display '100.0 kHz' so I've added an overload message in this case.

The reason I couldn't get this to work before was because I was using '*buffer' instead of just 'buffer'. Doesn't 'buffer' itself store the address of the passed char variable? I thought that to modify the variable it's pointed to you need to use '*buffer'.

Also, in that function there's a line commented out. If I use that line instead of setting each individual element seperately, the overload message doesn't display - instead the last frequency measurement persists on the display. Why's this?
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4064
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: C Code Problem
« Reply #32 on: January 16, 2015, 11:13:08 pm »
The reason I couldn't get this to work before was because I was using '*buffer' instead of just 'buffer'. Doesn't 'buffer' itself store the address of the passed char variable? I thought that to modify the variable it's pointed to you need to use '*buffer'.
Using the initializer string literal: char *buffer = "text"; Will make buffer a pointer to the constant char array "buffer" somewhere in memory which is probably not mutable.
If you want to intialize some string into buffer whilst keeping it in ram, you'd need memcpy or strcpy. Which is basically what the compiler would do implicitly if C had the syntax for it.
 

Offline IanB

  • Super Contributor
  • ***
  • Posts: 11771
  • Country: us
Re: C Code Problem
« Reply #33 on: January 16, 2015, 11:44:08 pm »
The reason I couldn't get this to work before was because I was using '*buffer' instead of just 'buffer'. Doesn't 'buffer' itself store the address of the passed char variable? I thought that to modify the variable it's pointed to you need to use '*buffer'.

If you have a declaration like char *buffer then buffer is a pointer to a char.

This being the case, *buffer resolves to a single character, not a string. The expression *buffer is identical to buffer[0], since in C buffer[offset] translates to *(buffer + offset).
 

Offline DigibinTopic starter

  • Regular Contributor
  • *
  • Posts: 90
Re: C Code Problem
« Reply #34 on: January 17, 2015, 01:41:47 pm »
Using the initializer string literal: char *buffer = "text"; Will make buffer a pointer to the constant char array "buffer" somewhere in memory which is probably not mutable.
If you want to intialize some string into buffer whilst keeping it in ram, you'd need memcpy or strcpy. Which is basically what the compiler would do implicitly if C had the syntax for it.

I'm not intialising it though. The string itself is already initialised before the function is called, so I just want to point to each element of the char array to edit it. Which is why I thought it should be '*buffer[n]' because that gives the actual value stored in the address, rather than the address itself. So why does 'buffer[n]' allow you to modify the contents of the array? In my understanding that's just giving the address of the string, not the actual values.

If you have a declaration like char *buffer then buffer is a pointer to a char.

This being the case, *buffer resolves to a single character, not a string. The expression *buffer is identical to buffer[0], since in C buffer[offset] translates to *(buffer + offset).

Okay so how do you declare a pointer to a string? With 'char* buffer[]'?
 

Offline Howardlong

  • Super Contributor
  • ***
  • Posts: 5313
  • Country: gb
Re: C Code Problem
« Reply #35 on: January 17, 2015, 01:57:53 pm »
Using the initializer string literal: char *buffer = "text"; Will make buffer a pointer to the constant char array "buffer" somewhere in memory which is probably not mutable.
If you want to intialize some string into buffer whilst keeping it in ram, you'd need memcpy or strcpy. Which is basically what the compiler would do implicitly if C had the syntax for it.

I'm not intialising it though. The string itself is already initialised before the function is called, so I just want to point to each element of the char array to edit it. Which is why I thought it should be '*buffer[n]' because that gives the actual value stored in the address, rather than the address itself. So why does 'buffer[n]' allow you to modify the contents of the array? In my understanding that's just giving the address of the string, not the actual values.

If you have a declaration like char *buffer then buffer is a pointer to a char.

This being the case, *buffer resolves to a single character, not a string. The expression *buffer is identical to buffer[0], since in C buffer[offset] translates to *(buffer + offset).

Okay so how do you declare a pointer to a string? With 'char* buffer[]'?

The same, char *c or char *s. It's how your program (or the standard C library) interpretes it that is the difference. The language itself doesn't know the difference. What's key is that it knows the size of a char, and that has repurcussions when using the array syntax and pointer arithmetic, both of which are fundamental parts of the language.
 

Offline AndreasF

  • Frequent Contributor
  • **
  • Posts: 251
  • Country: gb
    • mind-dump.net
Re: C Code Problem
« Reply #36 on: January 17, 2015, 02:11:26 pm »
...
Okay so how do you declare a pointer to a string? With 'char* buffer[]'?

That's an array of pointers to char variables.

This might help: https://www.cs.bu.edu/teaching/c/string/intro/
my random ramblings mind-dump.net
 

Offline DigibinTopic starter

  • Regular Contributor
  • *
  • Posts: 90
Re: C Code Problem
« Reply #37 on: January 17, 2015, 06:04:55 pm »
This might help: https://www.cs.bu.edu/teaching/c/string/intro/

Very useful, thanks. Clears things up a lot. So C itself can't change the contents of an array, only the individual elements. And so you either change the elements individually yourself or you use the string.h library functions.

Okay so having moved away from sprintf() and implemented my own conversion functions, I can now use my integer array without any issues. The original issue of the LCD displaying random characters has been resolved, so it must have been sprintf() at fault. It's strange though that the functions worked just fine until I tried to implement and use an integer array, even when sprintf() had nothing to do with the array.

So thanks to everyone for your help. Not only is the issue resolved but my code is a lot cleaner and to be honest I understand it better now. Now I can move on to the next job - a BQ24250 battery management chip that for some reason isn't charging a flat Li-ion battery pack.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf