Hello

I am trying to scale some measurements acquired in counts, such as the measurement variation will be between 0.000(%) to 100.000(%). The microcontroller is PIC16F877 at 20MHz. This is the device I have, and I will consider a newer approach (such as PIC16F887) after I will get this done.

I am using the Microchip floating point routines (the file is fp.zip) for PBP, which are written in assembly. I did not find any detailed explain so I am posting here.

These are the conditions:

All measurements are acquired in counts. The lowest measurement I get is 22600 (this is low_count_span). The highest measurement is 46461 (high_count_span).

This means that for 22600 counts I have to store 0.000 (low_%_span).

For 46461 I must store 100.000 (high_%_span).

It may happen for the measurements to go off-scale, this is why I need 100.000 and not strictly 99.999.

These percentages must be stored, because later I have to transmit them to a 16-bit 4..20mA industrial line, to a serial line and to LCD (via lcdout).

this means the math is this one:

y[%] = [ (high_%_span - low_count_span) / high_count_span] * measured_counts + low_count_span

for now I just test the numbers to see if the operation works:

y[%] = [(100000 - 22600)/46461 ] * measured_counts + 22600

Basically, I am trying to do this: y = [( A - B) / C ] * D + B and store "y" somewhere for later processing.

A = 100000; B = 22600; C = 46461; D = measured counts (between 22600 and 46461).

The code is not working and I am sure it is related to the big "100000" (in float it gets three more digits after).

I am posting here because I studied the assembly routines in fp32.a16 which explains the principles: all the math results are stored in AARG which is accessed via aint. So far it is not working. I get only 65535.65535 on the LCD.

Thank you very much for your patience.

For first, this is what I tried so far and it is not working:

I am trying to scale some measurements acquired in counts, such as the measurement variation will be between 0.000(%) to 100.000(%). The microcontroller is PIC16F877 at 20MHz. This is the device I have, and I will consider a newer approach (such as PIC16F887) after I will get this done.

I am using the Microchip floating point routines (the file is fp.zip) for PBP, which are written in assembly. I did not find any detailed explain so I am posting here.

These are the conditions:

All measurements are acquired in counts. The lowest measurement I get is 22600 (this is low_count_span). The highest measurement is 46461 (high_count_span).

This means that for 22600 counts I have to store 0.000 (low_%_span).

For 46461 I must store 100.000 (high_%_span).

It may happen for the measurements to go off-scale, this is why I need 100.000 and not strictly 99.999.

These percentages must be stored, because later I have to transmit them to a 16-bit 4..20mA industrial line, to a serial line and to LCD (via lcdout).

this means the math is this one:

y[%] = [ (high_%_span - low_count_span) / high_count_span] * measured_counts + low_count_span

for now I just test the numbers to see if the operation works:

y[%] = [(100000 - 22600)/46461 ] * measured_counts + 22600

Basically, I am trying to do this: y = [( A - B) / C ] * D + B and store "y" somewhere for later processing.

A = 100000; B = 22600; C = 46461; D = measured counts (between 22600 and 46461).

The code is not working and I am sure it is related to the big "100000" (in float it gets three more digits after).

I am posting here because I studied the assembly routines in fp32.a16 which explains the principles: all the math results are stored in AARG which is accessed via aint. So far it is not working. I get only 65535.65535 on the LCD.

Thank you very much for your patience.

For first, this is what I tried so far and it is not working:

Code:

include "fp2032.bas" ' Include file for 14-bit core with RAM at $20 (32-bit) DEFINE LCD_DREG PORTA DEFINE LCD_DBIT 0 ' 4 bit selected DEFINE LCD_RSREG PORTE DEFINE LCD_RSBIT 0 ' Reset Pin DEFINE LCD_EREG PORTE DEFINE LCD_EBIT 1 ' Enable Pin DEFINE LCD_LINES 4 define LCD_DATAUS 250 ; I need those for a 2-controller single LCD, 4 lines x 80 chars. the other ports are busy with SPI, i2c and 4..20mA outputs Define __16F877 1 cinput con 100 dinput con 1000 ADCON1 = 7 ' Set PORTA and PORTE to digital. Otherwise no output to LCD. Low PORTE.2 ' activates first two rows on LCD. high -> activates rows 3 and 4 lcdout $FE, 1 ; init LCD loop: aint = cinput ; load 100 gosub itofa ; and convert it to float bint = dinput ; load 1000 gosub itofa ; convert it to float gosub fpmul ; multiply and get 100000 (later will be 100 with 6 decimals after) ; result is transfered in aint bint = 22600 ; lowest measurement at initial calibration gosub itofb ; convert measurement to float gosub fpsub ; in aint I get 100000 - 22600 bint = 46461 ; this is the highest count I hope I will ever measure. Big trouble in the lab if this gets off-scale gosub itofb ; convert that to float gosub fpdiv ; at this time I have (100000 - 22600) / 46461 bint = 30000 ; this is some "measured value from the process" gosub itofb ; which I want to convert to percentages (%) gosub fpmul ; at this time in aint I get [(100000 -22600) / 46462 ] * measured_counts bint = 22600 ; store low span again gosub itofb ; and convert it to float gosub fpadd ; aint <- aint + bint fpplaces = 3 : gosub fpdisplayr ; put the percentage result on LCD with three decimals pause 3000 lcdout $FE,1 : lcdout $FE, 2 ; clear and go to first line, first row goto loop ; back to the zoo ; the rest of the code is not modified, according to 4func32.bas fpdisplayr: If fpplaces=0 Then ' Set floating point barg to 0.5 bexp = $7E bargb0 = $00 bargb1 = $00 bargb2 = $01 Endif If fpplaces=1 Then ' Set floating point barg to 0.05 bexp = $7A bargb0 = $4C bargb1 = $CC bargb2 = $CD Endif If fpplaces=2 Then ' Set floating point barg to 0.005 bexp = $77 bargb0 = $23 bargb1 = $D7 bargb2 = $0B Endif If fpplaces=3 Then ' Set floating point barg to 0.0005 bexp = $74 bargb0 = $03 bargb1 = $12 bargb2 = $6F Endif If fpplaces=4 Then ' Set floating point barg to 0.00005 bexp = $70 bargb0 = $51 bargb1 = $B7 bargb2 = $17 Endif Gosub fpadd ' add barg to aarg fpdisplay: bexp = aexp ' Store the FP value of aarg to the barg variables bargb0 = aargb0 bargb1 = aargb1 bargb2 = aargb2 Gosub ftoia ' Convert aarg to integer ahold = aint ' Save this value for the final display Gosub itofa ' Convert integer back to float Swap aexp,bexp ' Swap the FP values of aarg and barg before subtraction Swap aargb0,bargb0 Swap aargb1,bargb1 Swap aargb2,bargb2 Gosub fpsub ' Subtract the integer portion from the full number bint = 10 ' Make bint = 10 E fpplaces If fpplaces=2 Then bint = 100 Endif If fpplaces=3 Then bint = 1000 Endif If fpplaces=4 Then bint = 10000 Endif bhold = bint ' Save the integer value of bint for zeros loop Gosub itofb ' Convert bint to integer prior to FP multiply Gosub fpmul ' Multiply the decimal portion x 10 E fpplaces Gosub ftoia ' Convert result to aint integer Lcdout dec ahold ' Display integer portion ' Serout2 spin,sbaud,[dec ahold] ' Use for 2400 bps serial output If fpplaces > 0 Then Lcdout "." ' Display decimal point ' Serout2 spin,sbaud,["."] ' Use for 2400 bps serial output zeros: bhold = bhold / 10 ' Set bhold to be next place to right If (aint < bhold) AND (bhold > 1) Then ' Check for leading zero in decimal Lcdout "0" ' Display leading zero ' Serout2 spin,sbaud,["0"] ' Use for 2400 bps serial output Goto zeros ' loop to check for another zero Endif Lcdout dec aint ' Display the rest of the decimal portion ' Serout2 spin,sbaud,[dec aint] ' Use for 2400 bps serial output Endif aint = ahold ' Restore the original value of aint Return

## Comment