I think it can be done a bit easier. 1. Calculating slope. slope=(full_scale-cal_zero)/100. Here a fixed point division would be useful that takes at least 10 bits for dividend, 7 bits for divisor and the result as fixed point, say 3Q8 (11 bits is 0.05% accuracy at the full scale). 2. Calculating real value. real_value=(measured_value-cal_zero)/slope. Here you need a subtraction and division again. A nice trick is possible to use just one divide routine! The only significant difference is that you need the result as 7Q8 (0-100 range with a few fraction bits). So, the common divide routine should take: dividend = 10 bits or more in integer format divisor = 15 bits in 7Q8 format and produce: quotient = 15 bits in 7Q8 format 3. Displaying the results. Depending on how much digits after the point you display, multiply the 7Q8 result by 10 (to get 1 fraction decimal digit) or 100 (2 fraction decimal digits) and leave only the integer bits of the result. Multiplication by a constant is easy, if you use the online constant multiplication code generator or a regular multiplication routine. Then convert the integer result to decimal, using a routine at piclist.com (there is one for 0-999 range and another for 0-65535 - one of them should fit). That's it! Try this for division: ;----------------------------------------------------------------------------- ; Input: ; a1:a0 - 10 bit dividend ; b1:b0 - 15 bit divisor in 7Q8 format (b1 is integer, b0 is ; fractional) ; Output: ; c1:c0 - 15 bit quotient in 7Q8 format ; ; Temporary: ; temp - current remainder extension (used for intermidiate calculations ; only) ; count - counter ; ;----------------------------------------------------------------------------- div_uint10_fxp7q8_fxp7q8 ;left align the dividend ; (shift accumulator left 1 bit to get the first result bit weight ; equal to 128) clrc rlf a0, f rlf a1, f ;initialize registers clrf temp ;clear remainder movlw 15 ;15 iterations movwf count clrf c0 ;clear result - it will be used clrf c1 ;to shift zeroes to dividend div_loop rlf c0, f ;shift in next result bit rlf c1, f rlf a0, f ;and shift out next bit of dividend rlf a1, f ;to remainder rlf temp, f movf b0, w ;load w with lower divisor byte btfsc temp, 7 ;if remainder positive - subtract, goto div_add ;if negative - add ;subract subwf a0, f movf b1, w skpc incfsz b1, w subwf a1, f movlw 1 skpc subwf temp, f goto div_next div_add ;add addwf a0, f movf b1, w skpnc incfsz b1, w addwf a1, f movlw 1 skpnc addwf temp, f div_next ;here carry has a new result bit decfsz count, f goto div_loop ;shift in last result bit rlf c0, f rlf c1, f return ;----------------------------------------------------------------------------- Good luck! Nikolai ---- Original Message ---- From: Vasile Surducan Sent: Monday, March 12, 2001 9:01:13 To: PICLIST@MITVMA.MIT.EDU Subj: [PIC]: math calibration algorithm ? > Dear piclist guru's, > I have to do an automatic calibration procedure for a transducer. > This will be read by pic internal 10bit AD converter. > Assuming the whole AD range is 1024 and the transducer characteristic > is linear one, I need to read 2 points to determine the correct slope. > Zero will be between 300...400 and full scale between 950 and 1023 and > depends by transducer characteristics and biasing. No external scaling > device like operational amplifiers will be used. > I need interchangeability between various transducers which will match > condition above. > I'm new in pic maths so I was thinking to the following procedure > exemplified with one transducer values, all numbers are in decimal > representation: > 1. measuring zero calibration value > cal_zero = 376 > at cal_zero, displayed value must be tmin=0 > 2. measuring full scale calibration value > full_scale = 978 > at full_scale, displayed value must be tmax=98.9 > 3. determine real scale > real_scale = full_scale - cal_zero > real_scale = 602 > 4. compute slope > slope = real_scale/tmax > slope = 602/98.9 = 6.08 > I want to use only fixed point unsigned math routine so I need some > trick > for this division: > integer_slope = 10*602/989 = 6, remainder_lo=86 > I will use 16bit division routine and check: > if remainder_hi = 0 then > 100*remainder_lo/tmax = fraction_slope_lo > fraction_slope_hi = 0 > 100*86/989 = 8; new_remainder is not important > elsif remainder_hi > 0 then > 10*remainder_hi:lo/tmax = fraction_slope_hi:lo > end if > At this moment I know 100*slope = 608 > 5. determine real displayed value > real_value = 100*(measured_value-376)/100*slope > real_value_t_max = 100*602/608 = 99.1 (full scale display) > real_value_t_min = 100*1/608 = 0.16 ( first display greater than 0 ) > This division will be computed in same way like above one. > I will have an error of about 0.2% at full scale which is enough. > Now the question: could be done this computation into an easy way ? > Here I must use 16b substraction, 16b multiply, 16b division and some > conversion from hex to decimal. > Thank's for your existence, > Vasile > -- > http://www.piclist.com hint: To leave the PICList > mailto:piclist-unsubscribe-request@mitvma.mit.edu -- http://www.piclist.com hint: PICList Posts must start with ONE topic: [PIC]:,[SX]:,[AVR]: ->uP ONLY! [EE]:,[OT]: ->Other [BUY]:,[AD]: ->Ads