|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
| Thread Tools | Rate Thread | Display Modes |
|
#1
|
||||
|
||||
|
I hate "C"
I'm having a very tedious coding problem and I know it has something to do with the types/type casting in C.
I was writing/testing some PID code. It worked fine(I was just tweaking gains), but I noticed some overflow, so I changed alot of my variables from ints to longs. Now when I try to print, nearly everything prints as zero. Here is the code in question: Code:
/*
* pid_output
*
* This function outputs a value using a PID control loop for the specified PID struct.
* Takes a measurement, maximum output, and index of the gains for this loop in EEPROM.
*/
int Pid_Output(Pid_Struct * pid, long measurement,int maxOutput,int eeprom_index)
{
int output = 0;
//Get smaller names for the gains.
int pn = EEPROM_Read(eeprom_index);
int pd = EEPROM_Read(eeprom_index+1);
int in = EEPROM_Read(eeprom_index+2);
int id = EEPROM_Read(eeprom_index+3);
int dn = EEPROM_Read(eeprom_index+4);
int dd = EEPROM_Read(eeprom_index+5);
long p, i, d;
pid->error = pid->setPoint-measurement;
if( ABS(pid->error) < (long)pid->tolerance )
pid->error = 0;
//Accumlate error into the error_i and set the last error.
pid->error_i+=pid->error;
pid->error_d = (pid->error - pid->error_last);
pid->error_last = pid->error;
//This is the PID part:
p =((pid->error * (long)pn) / (long)pd);
i= ((pid->error_i * (long)in) / (long)id);
d= (((long)pid->error_d * (long)dn) / (long)dd);
output = p + i + d;
//DEBUG UNCONVENTIONAL
printf("\rMeasure: %d Target: %d Err: %d Err_I: %d Err_d: %d Output: %d Max: %d",measurement,pid->setPoint,
(int)p,(int)i,(int)d, (int)output, (int)maxOutput );
//Make sure we're in bounds
if(ABS(output) > maxOutput )
output = maxOutput*SIGN(output);
output+=pid->offset;
return output;
}
so what is happening here? the value for "output" prints out fine, but everything else comes up as zero... pn, pd, etc are non zero... Maybe I'm just too tired/lazy to figure this out. |
|
#2
|
||||
|
||||
|
Re: I hate "C"
I could be wrong, I havent done much with any thing other than ints on the robot but If you are overflowing an int and declared the variable as a long instead then when you print dont you need to put long in front of the variable name in the print statement rather than int.
James |
|
#3
|
|||
|
|||
|
Re: I hate "C"
You know, I don't quite see why you converted everything to long. The two types are essentially the exact same: both are signed, 4 byte numerical variables. It is strange that you would have this problem by switching this yes, but I don't see why you would think it would change anything. In my experiences, I've never seen any difference at all between the two, except for the name. (I may be missing something, but if I am, then I'll learn something here too) If you were trying to make the variable larger, to prevent overflow, the only way you can go bigger is to use a long long or long long int.
Also, could you provide some sample values that those variables might have. If it is indeed a casting problem, and I have an idea of what those values should be, I can run some test code and probably figure it out. Last edited by Jake M : 20-01-2007 at 00:33. |
|
#4
|
||||
|
||||
|
Re: I hate "C"
Quote:
EDIT: Also, neither are unsigned, I have no idea where you got this from. |
|
#5
|
|||
|
|||
|
Re: I hate "C"
Quote:
C18 2.1 Data Types and Limits in user guide: char : signed 8 bits int, short : signed 16 bits short long: signed 24 bits long : signed 32 bits float : 32 bits double : 32 bits The v2.4 C18 library guide says it supports size qualifiers, so could try %ld instead of %d for the long variables. Drop the int cast if using %ld. Last edited by dcbrown : 20-01-2007 at 00:45. |
|
#6
|
||||
|
||||
|
Re: I hate "C"
Matt,
There is a lot of your declarations not shown (such as your pid structure) but I'm guessing your issue is with the printf statement. "measurement" is declared as a long at the top of your function and being passed to printf as a long but printf is expecting an int. It should be cast as "(int) measurement". This would throw off all of your stack variables by two bytes each. Output may be non-zero but I doubt it is correct. Good Luck... Mike |
|
#7
|
||||
|
||||
|
Re: I hate "C"
Quote:
ha....it sickens me that this was actually the problem. This was the THIRD time I have been screwed by those printf's in C(used to java, C++). Thank You. That fixed the problem, but I'm curious as to how this works. Why does it throw off the stack variables by two bytes each?(Not that I know much about the "stack" anyways ) and how did you know this? Could you point me to a paper or something that explains how some of these "inner workings" work?EDIT: I knew it expected ints and I forgot that I changed measurement to a long, but I still wouldn't have expected that one mistake to mess up the rest of the function. |
|
#8
|
|||
|
|||
|
Re: I hate "C"
http://www.drpaulcarter.com/pcasm/
Well, you can't really call this a paper, but it's certainly got what you're looking for, and then some. It's one of the most influential documents in my "career" as a programmer. It deals with assembly language, the lowest programming language there is, unless you count binary as a language. It's pretty mind-boggling stuff, but if you can grasp the basic concepts, you won't believe how much your programming skills will improve. If you can learn and understand assembly, diagnosing code and logic problems will become almost intuitive and you'll be just as much better at coding them in the first place. Knowing assembly gives you a deep understanding of how C and other languages actually work, and how computers and processors themselves work. Of course you could just skip to the section on the Stack, and other things, but I'd recommend reading as much of it as you can, eventually. However, you do still have a slight problem, I believe. You're casting your 4 byte longs as 2 byte ints. So, when looking at the prints, it may seem like they're overflowing, because you're not seeing the entire variable through the printf function. In memory, though, the value is not overflowing (if it's large enough to overflow 2 bytes) because its being stored as 4 bytes. If you wanted to see the whole variable, you need to use a printf escaped character (like %i and %d) that is used for longs. I can't remember what it is at the moment, though. Last edited by Jake M : 20-01-2007 at 01:16. |
|
#9
|
|||
|
|||
|
Re: I hate "C"
printf can be passed a variable number of arguments. The passed arguments are saved onto the stack and end up just a long list of bytes - no delimiters. The format statement is parsed to determine the number and size of the passed arguments. So, if measurement is a long - 4 bytes are passed because the caller knows its data type. But if the format statement says %d - print out an int - then the only the first two bytes are pulled from the list of argument bytes. The next %d will then print out the last two bytes of measurement, etc. In C, this is a varargs routine.
Last edited by dcbrown : 20-01-2007 at 01:01. |
|
#10
|
||||
|
||||
|
Re: I hate "C"
Quote:
I never was really into that whole delimeter thing. |
|
#11
|
|||
|
|||
|
Re: I hate "C"
I should put a caveat on this... if you did a %c - print out a character, printf wouldn't pull just one byte from the argument list... it would pull two bytes. Thats because C18 promotes all smaller sized arguments to int before passing them to printf.
And don't hate C just because the C18 implementation of C is somewhat, um, quirky. Last edited by dcbrown : 20-01-2007 at 01:21. |
|
#12
|
|||
|
|||
|
Re: I hate "C"
Hear, hear. When it follows the standard, C is one of the most powerful languages around. Windows was written in C.
|
|
#13
|
||||
|
||||
|
Re: I hate "C"
Quote:
dcbrown's explanation is correct. When viewed from a pure "software" perspective, the fact that this processor passes parameters on the stack is, perhaps, confusing. C allows a variable argument list and it is up to the called function (in this case, printf) to parse the format string (the first parameter of the function is actually a pointer to a string) and determine how many variables there are and how large each one is. Your first %d in your format string indicated a 2 byte variable was the second parameter on the stack. When you put a long variable in the calling statement, 4 bytes were pushed onto the stack. That meant that all of your subsequent parameters were 2 bytes off... I would refer you to K&R for more details. It was the bible back in the 70's and, in my opinion, it is still the bible. For specifics on C as implemented for this processor, I'd look here. Regards, Mike |
|
#14
|
||||
|
||||
|
Re: I hate "C"
heh, maybe. but coming from Java and C++....C is definetely a step down.
|
|
#15
|
||||
|
||||
|
Re: I hate "C"
Quote:
Last time I'll make a printf mistake...once tried to concatenate strings in a prtinf...printf("measurement: "+measurement);..have to start remembering what language I'm in ![]() |
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| New NEMO White Papers! "Creating a Killer Packet" and "25 Ways to Sponsor" | Jessica Boucher | Team Organization | 0 | 10-08-2005 10:55 |
| "Thunderbirds" Vs. "Team America" Which one will rule the box office? | Elgin Clock | Chit-Chat | 3 | 07-09-2004 19:53 |
| Conflict between "Initialize_Tracker()" and "pwm13 & pwm15"? Kevin? | gnormhurst | Programming | 3 | 22-02-2004 02:55 |
| how tall is the ramp when in "up" and "balanced" position??? | archiver | 2001 | 1 | 24-06-2002 00:54 |
| I "hate" the new first site | Dima | General Forum | 11 | 06-01-2002 19:40 |