CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

Big numbers and the PIC16F
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Ttelmah



Joined: 11 Mar 2010
Posts: 12965

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 2:10 pm     Reply with quote

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: 182

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 3:05 pm     Reply with quote

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: 12965

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 3:48 pm     Reply with quote

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: 20260

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 3:51 pm     Reply with quote

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: 12965

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 4:27 pm     Reply with quote

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: 182

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 4:42 pm     Reply with quote

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: 20260

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 5:07 pm     Reply with quote

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: 182

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 7:25 pm     Reply with quote

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: 20260

View user's profile Send private message

PostPosted: Mon Dec 11, 2017 7:37 pm     Reply with quote

printf and sprintf are defective. It's not your i2c. That's working now anyway.
Ttelmah



Joined: 11 Mar 2010
Posts: 12965

View user's profile Send private message

PostPosted: Tue Dec 12, 2017 2:32 am     Reply with quote

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: 182

View user's profile Send private message

PostPosted: Wed Dec 13, 2017 9:44 am     Reply with quote

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: 12965

View user's profile Send private message

PostPosted: Wed Dec 13, 2017 12:03 pm     Reply with quote

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: 182

View user's profile Send private message

PostPosted: Wed Dec 13, 2017 1:19 pm     Reply with quote

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: 12965

View user's profile Send private message

PostPosted: Wed Dec 13, 2017 1:34 pm     Reply with quote

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: 835

View user's profile Send private message

PostPosted: Thu Dec 14, 2017 5:17 am     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
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