> From: Joao Batista > Subject: linearization of table Although not an exact solution to the PSI-to-Volts problem posed, the following code is probably directly usable with little modification. It's an example of piece-wise linearization. Ie., a sensor that's very non-linear over its full-range is often "linear enough" across segments of its range. This is 1st-pass, *but* functional code; a fragment of a 12c672 based temperature sensor project. Optimization is clearly possible, especially for register use. But, the simple "block" code is more straight-forward. To build the piece-wise linearization tables, calculate the x_data points (0-255 atod values) for convenient y_data points (deg_F with perfect deg_C equivalents in this case). +---[ thermistor ]---< Vdd 12c672 GP0/AN0: o----+ 10k +-------\/\/\/-------> Vss ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cblock _ram_ ; registers x_dat ;copy of adc data idx ;coordinate look-up index, bit count x1,x2 ;x1,x2 coordinates y1,y2 ;y1,y2 coordinates rpt,xpt,ypt,zpt ;linearization multiply,division regs endc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; use example: movlw 89 ;example adc value call set_xy ;set x1,x2 y1,y2 coordinates call lin_xy ;linearize ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; entered with w=X, returns x1,x2 and y1,y2 coordinates from x_tbl,y_tbl ; such that X is between x1,x2 (x1<=X= tbl_dat call nxtbl ;get data at tbl+idx movwf x1 ;save movlw x_tbl+1 call nxtbl ;get data at tbl+idx movwf x2 ;save movlw y_tbl call nxtbl ;get data at tbl+idx movwf y1 ;save movlw y_tbl+1 call nxtbl ;get data at tbl+idx movwf y2 ;save return nxtbl: addwf idx,w ;index table location movwf pcl ;returns data at pcl in w ; x,y coordinate pair lookup tables for -22F (-30C) to 122F (+50C) ; equal length, in ascending order, 1st & last xy_pairs for range guard ; x= (ysi44006 thermistor to vdd with 10k to vss), y= (deg_f) x_tbl: dt 0, 18, 23,29,36,44,54,65,76,89,101,115,128,140,152,164,174,184,255 y_tbl: dt -40,-22,-13,-4, 5,14,23,32,41,50, 59, 68, 77, 86, 95,104,113,122,212 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; coordinate linearization: x1,x2 -- y1,y2 ; return w= ((y2-y1)/(x2-x1)) * (X-x1) + y1 lin_xy: movf x1,w subwf x_dat,w ;w= x_dat-x1 movwf xpt ;set x_part= x_dat-x1 movf y1,w subwf y2,w ;w= y2-y1 movwf zpt ;set z_part= y2-y1 movf x1,w subwf x2,w ;w= x2-x1 movwf ypt ;set y_part= x2-x1 call scale ;xpt= xpt*zpt/ypt movf xpt,w addwf y1,w ;w= xpt+y1 return scale: ; x= x*z/y y & z are unchanged ; x,y,z are 8-bit, (x*z) <= 15-bits #define bcnt idx mult: ; r:x <- x*z movlw 8 movwf bcnt ;set bit count clrf rpt ;clear ms8 of product bcf status,c ;clear carry rrf xpt,f ;lsb of multiplier into carry mul1: btfss status,c goto mul2 ;carry was clear movf zpt,w addwf rpt,f ;prod_ms8 += multiplicand mul2: rrf rpt,f ;align 16-bit product, r:x rrf xpt,f ;(prod_ls8 replaces multiplier) decfsz bcnt,f ;loop thru bits goto mul1 divi: ; x <- r:x/y (remainder in r) movlw 8 movwf bcnt ;set bit count div1: bcf status,c ;dividend *2 rlf xpt,f rlf rpt,f movf ypt,w ;subtract divisor from dividend ms_8 subwf rpt,f btfss rpt,7 ;check if msb set goto div2 ;ok -- bit clear movf ypt,w ;else set -- undo previous sutraction addwf rpt,f goto div3 div2: incf xpt,f ;count previous subtraction div3: decfsz bcnt,f ;loop thru bits goto div1 #define round_up ifdef round_up ; round-up result -- destroys remainder bcf status,c ;remainder *2 for rounding rlf rpt,f movf ypt,w ;subtract divisor from rmdr*2 subwf rpt,f btfss status,c ;skip next on carry set goto divx ;else carry clear -- 2*r < divisor incf xpt,f ;round x up divx: endif return -- evd@gwis.com .