|
|
View previous topic :: View next topic |
Author |
Message |
Ttelmah
Joined: 11 Mar 2010 Posts: 19219
|
|
Posted: Mon Dec 11, 2017 2:10 pm |
|
|
PCM's findings are interesting. There was for a long time a fault with printf when number got large, but I've not seen it for ages. The one common feature is compiling for the F886. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Dec 11, 2017 3:05 pm |
|
|
I am still trying to get my display working.
The newer compiler may be less tolerant of my mistakes.
Can someone check if I have used the pointer correctly in send_str(buff);
I am getting compile errors of pointer types do not match even trying to use a different LCD and another program that used to work.
I can read a PIC and write it to another and it drives the LCD but the compiled program does not.
I am now using a PIC16F1938 but cannot get my LCD working even though the compiler goes through the motions and gives warnings or errors for things I change. I may have to go back to an LED and start from scratch. This all started immediately after installing ver 5.064
Will PCD work with my PIC16F and up to the 22 bit? I just feel I'm digging the hole deeper. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19219
|
|
Posted: Mon Dec 11, 2017 3:48 pm |
|
|
Make your buffer a little larger.
Then stop when the character you get to is a null (0), or when you read the display width.
At present you keep sending characters that can be whatever is left in RAM after you reach the string null. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 11, 2017 3:51 pm |
|
|
I compiled the minimal program that you posted and it has no build errors
or warnings.
One thing I noticed is that the compiler sets pins C3 and C4 to be inputs
in the init code at the start of main(). This is in the .LST file:
Code: | 0295: MOVWF @TRIS_C
0296: BSF @TRIS_C.3 // Set pin C3 to be an input
0297: MOVF @TRIS_C,W
0298: BSF STATUS.RP0
0299: MOVWF TRISC
029A: BCF STATUS.RP0
029B: BSF @TRIS_C.4 // Set pin C4 to be an input
029C: MOVF @TRIS_C,W |
This is per the PIC data sheet. It wants this to be done.
But then, you override the compiler by setting all PortC pins to be outputs:
Quote: |
void main(void)
{
// setup
set_tris_c (0x00); // all outputs
char buff[buff_size];
float32 SENS = 0;
float OFFSET = 0; |
I would delete the line shown in bold. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19219
|
|
Posted: Mon Dec 11, 2017 4:27 pm |
|
|
There was a fix published some time ago, but I can't find it. They added a new value you could configure, which specified the maximum number of digits before it switched to outputting in exponential format. Sure it was in the readme.
The problem appears when you try to output more digits in front of the decimal than the float actually supports.
The maximum number of digits in total allowed is 9, and remember this includes the decimal place. However only 6 are significant.
It's far worse than I remember it being.
You can generate your own switcher and limit the digits to what is supported with something like:
Code: |
#include <16F886.H>
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT, BROWNOUT, MCLR
#use delay (clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
//======================================
void dprintf(float val)
{
if (val>999999.) //6 digits
printf("%8.5e \r", val);
else
printf("%8.1f \r",val);
}
void main(void)
{
float temp;
temp=123456.7;
dprintf(temp);
temp = 1234567.0;
dprintf(temp);
temp = 12345678.0;
dprintf(temp);
while(TRUE);
}
|
|
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Dec 11, 2017 4:42 pm |
|
|
Between ver 5.055 and 5.064 the I2c in the compiler was changed so that it reverts to hardware I2C if the pins are specified (my older manual says software is used unless force_hw is used). I had to add Force_sw as below to get my LCD working again.
Code: | #use I2C (master, SCL=PIN_C3, SDA=PIN_C4, FORCE_SW) |
Next I found that I can still download the old version 5.055 if I can find my invoice and get the Reference number, which I did so I can go back and double check. Since the install that I did says it saved a copy of 5.055 I wonder how I can access it. No matter my problem is solved although I don't understand why the force is required if the pins are the same for hardware or software.
Now I can try the suggestions, thank you all. I thought I had gone through a time warp into another dimension.
Edit:
Looking back at Ttelmah's post I think that his comment about LCD baud rate explains why the I2C running as hardware does not work. I will check that as well as the other suggestions.
"Start with a Z" is a left over comment from getting the LCD display working.
Last edited by rovtech on Mon Dec 11, 2017 6:32 pm; edited 2 times in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 11, 2017 5:07 pm |
|
|
Quote: | Since the install that I did says it saved a copy of 5.055 I wonder how I can access it. |
Find or guess the name of the file. Then do a search on your entire C:\
drive (or whatever drive) for that filename or part of it. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Dec 11, 2017 7:25 pm |
|
|
Moving on:
I tried these suggested changes (only showing what is relevant, 32 did not help)
Code: | #define buff_size 48 // enough for float
char buff[buff_size];
text_position(0,2); // 1st column, 3rd line
OFFSET = 123456789;
sprintf(buff, "O %f", OFFSET);
send_str(buff);
SENS = 1.23456789E8;
text_position(0,3); // 1st column, 4th line
sprintf(buff, "S %7f", SENS);
send_str(buff);
void send_str(char *buff)
{
int i;
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE('T'); // send TT for text coming
I2C_WRITE('T');
for (i=0; i<21; i++) // only 20 char max
{
I2C_WRITE(buff[i]);
}
I2C_WRITE(0);
I2C_STOP (); // stop I2C
} |
and still get -5392220.13 for OFFSET and -2030.024528 for SENS.
The actual variables used in the Bar30 calculations (google the data sheet) are large positive and negative numbers and were int16, int32, signed int32, and signed int64 (e.g. 2,381,326,464 with my commas for clarity)
The sprintf() and send_str () do not appear to put any garbage because the lines display with 7 and 6 blanks after the numbers. Garbage in the buffer would display something, but the display is consistent and clean.
I deleted set_tris_c(0x00); as PCM programmer suggested but it has no effect. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 11, 2017 7:37 pm |
|
|
printf and sprintf are defective. It's not your i2c. That's working now anyway. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19219
|
|
Posted: Tue Dec 12, 2017 2:32 am |
|
|
Look at the dprint routine I posted.
You need to be using this once you go beyond 6 digits. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Wed Dec 13, 2017 9:44 am |
|
|
I used the dprintf method that Ttelmah suggested, and understand that, so now I can print intermediate results to check the compiler. The print now works but the math is wrong. The problem is mixing different variable types, for example:
Code: | signed int32 dT; // should calculate to 68261
unsigned int32 D2 = 6749349; // is calculated correctly elsewhere
unsigned int16 CAL = 26098; // is CAL[5] read from the sensor
dT = D2-CAL[5]*256; // gives 6864991
dT = D2-26098*256; // gives 246320
dT = D2-6681088; // gives 246884
dT = 6749349-6681088; // gives 68261 which is correct |
I used
Code: | sprintf(buff, "dT %Ld", dT); |
which should be OK to print 68261
This is not very complicated math. Any suggestions?
I had started to convert every variable to float when I ran into the problem of the printing large numbers. There are several more equations that get into the signed int64 variables.
Edit:
Oops. Give me a few minutes. If D2 is made = 649349 in the global declaration I get the wrong answers. If I make it = just before the above it is OK. I will check and add the result here.
Edit2:
D2 is actually calculated (correctly) so give slightly different numbers each run. I still get bad math unless I use the integer value instead of D2. I don't think the compiler likes mixing variable types.
Edit3:
I reduced the program to simplest:
Code: | // print test result
CAL[5] = 26098;
text_position(0,1);
sprintf(buff, "Cal[5] %Lu", CAL[5]);
send_str(buff);
D2 = 6749349;
text_position(0,2);
sprintf(buff, "D2 %Lu", D2);
send_str(buff);
unsigned int16 nn = 26098;
dT = D2-nn*256; // does not work
// dT = D2-6681088; // works, yes it did not like it on a previous
// dT = 6749349-nn*256; // does not work
text_position(0,3); // 1st column, 4th line
sprintf(buff, "dT %Ld", dT);
send_str(buff); |
The variable values always display OK. The simple equation does not unless I use integers instead of both variable names. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19219
|
|
Posted: Wed Dec 13, 2017 12:03 pm |
|
|
This is the importance of using casts when mixing types.
In the first sum, CAL is an int16. 256 also fits in an int16, so the first multiplication is done using int16 arithmetic. Result overflows about 100*. The remainder of this is then subtracted.
The same applies in different forms to all the others.
You need to always cast one item in each side of a sum up to the type you want the sum performed in. If you cast up the item that is 'innermost' in the execution of the sum this will give the required result.
Since multiplication is performed before subtraction:
dT = D2-CAL[5]*256LL; //forces the 256 to be a int32
dT = D2-(int32)CAL[5]*256; //forces CAL[5] to be an int32. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Wed Dec 13, 2017 1:19 pm |
|
|
Thank you Ttelmah, that works.
So CCS C does not have Automatic type conversion. I will read that chapter in my C manual ("Teach Yourself C in 21 Days" - try 21 months!).
I had been wondering about the printf() and fprintf() functions which list formats c, s, u, d, LU, Ld, etc but do not have LLu or LLd.
So u and d are 8 bit, Lu and Ld are 16 bit, but what handles 32 bit? I have been using Lu and Ld which seem to work but LLu gives a compile error.
I can now get as far as the 32 bit equations but then have to use the results to calculate the 64 bit signed integers. Can I use float variables and cast to them in the equation?
Example:
Offset = CAL[2] * 2e16 + (CAL[4]*dT)/2e7 (=2,381,326,464 typical)
where Offset is signed int64, CAL[n] are unsigned int16, dT is signed int32.
if I use float for Offset then can I cast all the others to float. Would you mind showing me how as this is strange territory for me. I can use this as a template for the other equations. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19219
|
|
Posted: Wed Dec 13, 2017 1:34 pm |
|
|
C does not do this. Not just CCS C.
In C, the variable type used for any arithmetic operation, is the highest type of the operand(s). So multiply an int16 by an int8, and it'll use int16.
Now some C's do promote 'by accident'. If (for instance) you multiply in a PC, it will (on any modern machine) use the maths co-processor, and this will promote. However this is not the C standard. Run the same code on an old PC without the co-processor and the promotion does not occur. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Thu Dec 14, 2017 5:17 am |
|
|
rovtech wrote: | So CCS C does not have Automatic type conversion. |
Yes, as Ttelmah say, it does, and the rules are well defined in the C language. The problem, as with so many of these things where people come here and say "so-and-so doesn't work" is that it works as the C standard say it should, but it doesn't work as you expected. The issue so often is incorrect expectations, not incorrect code.
Certainly the automatic type casts of C are not as intuitive as more recent languages. This is, in part, a result of relatively limted hardware when C was defined. Instead of what tends to happen in more modern langauges on modern hardware, where larger datatypes, e.g. int32, are as simple, fast and efficient as smaller ones such as int8. Indeed, on PCs, looping with int8 is often slower than with the "native" int32. With shorter word lengths and limited processor resources, such as no FP hardware, the C way is more efficient but leaves the programmer with more to think about. Personally I'm so used to the C way that I have no problem with it. The C# way, for instance, tends to feel grossly bloated and wasteful to me. That element of the mindset though, is part of what makes an embedded programmer different from other programmers, and is a big part of why I tend fot feel a greater sense of satisfaction in writing 1000 lines of PIC code than 10000 lines of PC application code. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|