View previous topic :: View next topic |
Author |
Message |
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Big numbers and the PIC16F |
Posted: Sun Dec 10, 2017 1:42 pm |
|
|
I have some equations with int64 variables that are supposed to run on an Aduino. I need to run them on a PIC16F866.
A few simple tests on a PIC16F886 reveals that it is easy to overflow and get garbage with no warnings.
Code: | float32 SENS;
SENS = 123456789; |
results in displaying SENS = -5392220.13
displays as 12345678.08
Code: | SENS = 1.23456789E6; |
displays as 1234567.92
Code: | SENS = 1.23456789E7; |
displays as 12345679.36
Code: | SENS = 1.23456789E8; |
displays as -5392220.13
where did I see that before (above)
So the following gives garbage, unlike my HP48 calculator that gives the correct answer.
Code: | float32 SENS; // or just float SENS;
dT=6.8261E4;
C1=3.4857E4;
C3=2.0538E4;
SENS = (C1*3.2768E4) + ((C3*dT)/256); |
What am I doing wrong and what should I do?
Why does the compiler not complain or warn?
The big numbers are coming from a sensor via I2c and the original code uses in64 for several variables.
Switching to a 24bit PIC was suggested but the compiler is $400 which is a bit much to solve one problem.
I would think the compiler would round off the numbers to maximum digits and get the correct answer.
Any other suggestions? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Sun Dec 10, 2017 1:54 pm |
|
|
Quote: |
I have some equations with int64 variables that are supposed to run on an Aduino. I need to run them on a PIC16F866.
A few simple tests on a PIC16F886 reveals that it is easy to overflow and get garbage with no warnings.
Code:
float32 SENS;
SENS = 123456789;
results in displaying SENS = -5392220.13
|
How are you seeing this 'result'.
What is your compiler version?.
The maths doesn't overflow like this. What it does do is give the small errors like you have in your next part. However all FP systems do give these to some extent. There are numbers (1/3 for example), that just won't represent in binary FP. The 4 byte version typically gives about 6 digits of usable accuracy.
A wrong display may occur on some compiler versions if you don't specify a 'width' for an FP output.
So %f may give a display error like this. Try %7f instead and you may well find this problem disappears.
It happens when the output can't decide if it should display normally or in exponential form. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Sun Dec 10, 2017 4:12 pm |
|
|
Thanks Ttelmah, here is more of my code. The results are displayed on a 4 line x 20 LCD. It has worked well so I don't suspect it. I was using %f and changing as you suggested gave completely different values.
%f gave -5392220.13
%7f gave -2030.024528 for both OFFSET and SENS
PCM compiler ver 5.05 MPLAB v 8.92 PIC16F886
Code: | float32 SENS = 0;
float OFFSET = 0;
text_position(0,2); // 1st column, 3rd line
OFFSET = 123456789;
sprintf(buff, "offset %7f", OFFSET);
send_str(buff);
SENS = 1.23456789E8;
text_position(0,3); // 1st column, 4th line
sprintf(buff, "Sens %7f", SENS);
send_str(buff); |
I am away this evening but will check back tomorrow. Thanks. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Mon Dec 11, 2017 4:38 am |
|
|
There isn't any such compiler version as 5.05. CCS versions are always x.xxx
However if this is 5.005, then this was an early beta. The V5 compilers need to be around 5.012, before they started working at all well.... |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Dec 11, 2017 8:18 am |
|
|
Sorry, I was in a hurry to leave yesterday. My compiler is:
CCS PCM C Compiler, Version 5.055
I will strip my code (several pages) down to minimum and post the whole thing but I don't think it will make any difference. Except for where the definitions are located the rest of the code is one block in main() so it should not matter what happened to the variables before that.
I could buy the latest version but if it doesn't work then I may have to consider going to the 24 bit PIC which would be wasted money on the update. I really don't want to run the code on an Arduino either.
My problems with the Arduino from my original post was explained to me:
"The reason you are unable to print at int64_t is because there is no "Serial.print" function definition for Serial.print(int64_t var). The math libraries support the 64 bit operations but you cannot print the numbers with Arduino's current code." |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Mon Dec 11, 2017 8:29 am |
|
|
re:
My problems with the Arduino from my original post was explained to me:
"The reason you are unable to print at int64_t is because there is no "Serial.print" function definition for Serial.print(int64_t var). The math libraries support the 64 bit operations but you cannot print the numbers with Arduino's current code."
gee ain't that great....NO way to confirm/deny the numbers are right !! |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Dec 11, 2017 9:22 am |
|
|
Here is my full code stripped down to minimum:
Code: | /* Pre-processor directives */
#include <16F886.H>
#include <math.h>
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT, BROWNOUT, MCLR
#use delay (clock=2000000)
#use I2C (master, SCL=PIN_C3, SDA=PIN_C4)
#byte portc = getenv("SFR:PORTC")
// define I2C address, constants, & global variables
#define LCD_WRT_ADDR 0X4E // LCD display
#define buff_size 21 // characters per line plus one
// Function prototypes
void clear_LCD (void); // Clear LCD
void text_position (int line, int column); // set start for next text
void Set_Col_Rows(char col, char row); // set #columns & rows
void send_str(char *buff); // Send string to LCD
// The main function
void main(void)
{
// setup
set_tris_c (0x00); // all outputs
char buff[buff_size];
float32 SENS = 0;
float OFFSET = 0;
delay_ms(1000); // allow I2C display module to start
clear_LCD(); // clear the LCD
// Set_Col_Rows(20,4); // 20 columns, 4 rows
text_position(0,2); // 1st column, 3rd line
OFFSET = 123456789;
sprintf(buff, "offset %f", OFFSET);
send_str(buff);
SENS = 1.23456789E8;
text_position(0,3); // 1st column, 4th line
sprintf(buff, "Sens %6f", SENS);
send_str(buff);
} // end of main function
// Functions
// ** Clear Display
void clear_LCD (void)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('C'); // C CL to clear display
I2C_WRITE ('L'); // L
I2C_STOP (); // stop I2C
}
// ** Set position of next text
void text_position(int line, int column)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('T'); // T, TP set text position
I2C_WRITE ('P'); // P
I2C_WRITE (line); // line position
I2C_WRITE (column); // column position
I2C_STOP (); // stop I2C
}
// ** Set Text Columns and Rows
void Set_Col_Rows(char col, char row)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('S'); // STCRT, set Col & Row
I2C_WRITE ('T');
I2C_WRITE ('C');
I2C_WRITE ('R');
I2C_WRITE (col); // # columns
I2C_WRITE (row); // # rows
I2C_WRITE (0x80);
I2C_WRITE (0xC0);
I2C_WRITE (0x94);
I2C_WRITE (0xD4);
I2C_STOP (); // stop I2C
}
// ** Send string to LCD
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<buff_size; i++)
{
I2C_WRITE(buff[i]); // start with a Z
}
I2C_WRITE(0);
I2C_STOP (); // stop I2C
}
// end |
OFFSET displays as -5392220.13 (using %f)
SENS displays as -2030.024528 (using %6f)
interestingly SENS also displays as -2030.024528 (using %2f or %7f)
I get -5392220.132 (using %f2)
Edit:
Code: | OFFSET = 123456789;
OFFSET = OFFSET - 123456788;
sprintf(buff, "offset %f", OFFSET);
send_str(buff); |
gives OFFSET as 8.00 not as good as my HP48 calculator which gives 1. I just had to check.
and
Code: |
OFFSET = 123456789;
OFFSET = OFFSET - 123450000; |
gives 6792.00 which is close but not good enough. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Dec 11, 2017 10:05 am |
|
|
Disaster:
I found I had a CCS PCM C Compiler, Version 5.064 downloaded but never installed (if it ain't broke don't fix it).
I installed it but now even my LCD display does not work. It compiles, programs the PIC and verifies, clears it, etc. but just a blank LCD. That's why I hate installing the latest updates.
Was this a bad version?
Help! How do I go back to the old version? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Mon Dec 11, 2017 11:35 am |
|
|
Quote: |
Code:
OFFSET = 123456789;
OFFSET = OFFSET - 123456788;
sprintf(buff, "offset %f", OFFSET);
send_str(buff);
gives OFFSET as 8.00 not as good as my HP48 calculator which gives 1. I just had to check.
and
Code:
OFFSET = 123456789;
OFFSET = OFFSET - 123450000;
gives 6792.00 which is close but not good enough.
|
They are both as good as you are going to get.
Float (On the PIC18, there is only one type), has a 23.5 bit mantissa. It is coded as a 23 bit mantissa, with an invisible starting '1'. So numbers that code as 11111111... get 24 bit equivalent accuracy, but anything requiring a '0' at the end, only gets 23 bits. 6.8 digits of equivalent decimal 'accuracy'.
Also though coding as binary fractions in this way has limitations. Some numbers expand to infinite series, and will give errors no matter how many digits you have.
Your values shown are integer. Int32, gives 9.4 digits supported. Your maths would work perfectly in integer.
Float is designed to give _flexibility_ by automatically scaling numbers to display the most significant digits, but at a lot of precision.
Just re-install the old version from your backup.
However that 5.064 doesn't work may well be showing that there is something fundamentally flawed in the code. The later compiler will almost certainly default to using the I2C hardware, and will clock it as fast as possible. Are you sure your LCD can support this rate?. Specify a baud rate in the setup. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 11, 2017 11:42 am |
|
|
rovtech wrote: |
How do I go back to the old version?
|
1. If you have the old installer file (.exe file) for vs. 5.055, just run it.
2. If you have System Restore enabled on your Windows PC, you can go
back to a previous restore point. Choose the latest one, just before you
installed vs. 5.064. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 11, 2017 12:08 pm |
|
|
Ttelmah, to me it looks like a bug in printf. The test program shown below,
compiled with vs. 5.075, gives the following output in MPLAB vs. 8.92
simulator. The 2nd number is incorrect:
Quote: |
1234567.040
-539224.061
|
If I look at the .LST file for the 2nd case, I see this encoding:
Code: | ..... temp = 12345678.0;
01ED: MOVLW 4E
01EE: MOVWF temp+3
01EF: MOVLW 61
01F0: MOVWF temp+2
01F1: MOVLW 3C
01F2: MOVWF temp+1
01F3: MOVLW 96
01F4: MOVWF temp
|
I next use the floatconv.exe program from this Zip file:
http://www.piclist.com/images/floatconv10.zip
I set the format to "MicroChip 32bit".
If I plug the numbers from the .LST file into the floatconv.exe program as follows,
Code: | BYTE1 BYTE2 BYTE3 BYTE4
96 3C 61 4E |
I get this number in the "float" box at the top:
It's correct. So that tells me the problem is in printf.
Test program:
Code: | #include <16F886.H>
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT, BROWNOUT, MCLR
#use delay (clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
//======================================
void main(void)
{
float temp;
temp = 1234567.0;
printf("%7.3f \r", temp);
temp = 12345678.0;
printf("%7.3f \r", temp);
while(TRUE);
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Mon Dec 11, 2017 12:15 pm |
|
|
Just worth adding that calculators generally use BCD arithmetic, not floats. It is not hard to use a BCD library on the PIC.
The PIC does include two features that help with BCD. Swap (allows a nibble to be swapped in one instruction), and the DC bit which flags a carry from the bottom nibble.
Also as a comment, on the PIC24/30/33 the int64 type does print correctly. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Mon Dec 11, 2017 1:43 pm |
|
|
Windows restore did not restore ver 5.055
I cannot find the 5.055 ver install file
I installed ver 5.019 which does the same as 5.064 and my LCD is still blank with blinking cursor top left.
It looks like the update somehow messed up my LCD serial driver, most likely changed it's address. I will sort this out.
The install says it saved a copy of 5.055 but I cannot find instructions on how to open it. I may as well use 5.064.
So the problem is in printf but will purchasing the latest pcm fix the problem?
I don't mind that but pcd is another matter and probably means new circuit boards, a learning curve, and who knows, besides the cost. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 11, 2017 1:46 pm |
|
|
I did my testing with the latest version (vs. 5.075). It has the problem. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Mon Dec 11, 2017 2:01 pm |
|
|
There is another problem. Your functions are fundamentally flawed.
send_str, will keep punching out data past the end of the string. Could be anything....
Then if the compiler switches to exponential format, there is nothing to stop the data overflowing the buffer. This will then result in garbage being displayed.
Make your buffer larger. 32 characters. Then only print the 20 your display supports. You also say 'start with a Z', but don't do so. Does the display need this?. Hopefully you will then see the data, and can work out how much it is actually overflowing. |
|
|
|