This is a multi-part message in MIME format. ------=_NextPart_000_003E_01C10567.100DE140 Content-Type: text/plain; charset="utf-7" Content-Transfer-Encoding: 7bit I have a piece of C code that does piecewise linearization of an analog input, for a thermistor curve which is plenty nonlinear. You can look at it if you'd like. It's not plug-and-play, you'll have to mess around with it a lot. Here's the basic theory:' 1. Use Excel or Mathcad to generate a table of the desired number of steps. I used an array of 16 rows by 2 columns, of two-byte longs. Each number in the first column maps an analog input to a corresponding output in the second column. Or, in plain english, Column 1 is the inputs, Column 2 is the corresponding outputs. 2. Your code then indexes through the table until the raw data from the A/D is greater than the number in Column 1. Keep track of the index number here. 3. Linear interpolate by looking up the numbers corresponding to (index -1), and (index +- 1), thus: A +AD0- Table+AFs-0+AF0AWw-Index-1+AF0AOw- B +AD0- Table+AFs-0+AF0AWw-Index-1+AF0AOw- C +AD0- Table+AFs-1+AF0AWw-Index-1+AF0AOw- D +AD0- Table+AFs-1+AF0AWw-Index+AF0AOw- Result1 +AD0- (rawdata - A) +ACo- (D - C) / (B - A) +- C+ADs- // interpolate into the table 4. Believe me, all those diehards that think C is for wimps would have a fun time coding a two dimensional lookup table of two byte longs in ASM. Do this in C. 5. Anybody who has coded a two byte two dimensional lookup table in ASM in the last 5 years, lemme know, I'll buy you a free beer when you are in my town. -- Lawrence Lile ----- Original Message ----- From: +ACI-Drew Vassallo+ACI- +ADw-snurple+AEA-HOTMAIL.COM+AD4- To: +ADw-PICLIST+AEA-MITVMA.MIT.EDU+AD4- Sent: Sunday, July 01, 2001 8:54 AM Subject: +AFs-PIC+AF0-: Scaling of a curve +AD4- Math geniuses of PICLIST: +AD4- +AD4- I have a series of 40 points that represent a curve. It's not a linear +AD4- curve. In fact, it doesn't necessarily even have a positive slope +AD4- throughout. What I want to do is to create a scaling that is variable +AD4- depending on the position on the curve. It's probably best to give an +AD4- example: +AD4- +AD4- point 40 +AD0- 100 (dec.) +AD4- point 30 +AD0- 80 +AD4- point 20 +AD0- 75 +AD4- point 10 +AD0- 70 +AD4- point 1 +AD0- 35 +AD4- +AD4- Let's say at point 30, we want to add an additional 10+ACU- to the value. So, I +AD4- want to add an additional 10+ACU- also at all the other points (3 or 4 at point +AD4- 1 and 10 at point 40). This will, of course, change the characteristics of +AD4- the curve as a whole, but it is necessary in this application. +AD4- +AD4- Any quick ways? My initial idea was to take the percentage and try to +AD4- multiply it out, but I'm not sure how this would work over the entire +AD4- percentage range (i.e., I could be adding as little as 1+ACU- or as much as +AD4- 200+ACU-) and I would probably need some sort of floating point math for any +AD4- sort of precision at the lower values. +AD4- +AD4- My other idea was just to take the endpoints, find the ratio between them, +AD4- and linearly scale the intermediate points, even though that's not entirely +AD4- accurate, but it's better than nothing. +AD4- +AD4- Thanks, +AD4- --Andrew +AD4- +AF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXwBfAF8AXw- +AD4- Get your FREE download of MSN Explorer at http://explorer.msn.com +AD4- +AD4- -- +AD4- http://www.piclist.com hint: PICList Posts must start with ONE topic: +AD4- +AFs-PIC+AF0-:,+AFs-SX+AF0-:,+AFs-AVR+AF0-: -+AD4-uP ONLY+ACE- +AFs-EE+AF0-:,+AFs-OT+AF0-: -+AD4-Other +AFs-BUY+AF0-:,+AFs-AD+AF0-: -+AD4-Ads +AD4- +AD4- ------=_NextPart_000_003E_01C10567.100DE140 Content-Type: application/octet-stream; name="piecewise.c" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="piecewise.c" /////////////////////////////////////////////////////////////////////////= ////* Prediction.C = //// ////* P = //// ////* //// ////* Revision Hisory: = //// ////* = //// /* 1 6-25-20011 Created from 34859.c Version 3 //// 2 6-29-2001 Piecewise linear interpolation of thermistor implemented =20 NOTE: This is untested code. No guarantees or warantees of any kind = are expressed or implied It is not warranted for any purpose whatsoever. So you can't sue me if = it doesn't do what you expect. =20 Enjoy! I hope you can use this to your advantage. =20 =20 /////////////////////////////////////////////////////////////////////////= /// I/O LIST: /////////////////////////////////////////////////////////////////////////= /// PORTA Analog Inputs: AN0 Meat Probe 10K thermistor 4700 ohm series PortA digital outputs: RA1 Beeper PORT B: RB0 =09 RB1=09 RB2 =09 RB4=09 RB5 RB6 Programming clock =09 RB7 Programming Data Port C: RC0=09 RC1 =20 RC2 =20 RC3 Rs232 Transmit Pin=20 RC4=09 RC5 =09 RC6 =09 RC7=20 Port D: NOT NEEDED */ =20 /////////////////////////////////////////////////////////////////////////= ////////////////////// //************************************ INCLUDES and preprocessor = directives *********************************************// /////////////////////////////////////////////////////////////////////////= ////////////////////// #define test 1 // TEST MODE ON #define device16 1 // tell compiler to use 16 bit memory = addresses #include <16F877.H> // Sets microcontroller device // Warning - custom modified 16F877.H, must include it with the code for = proper compile! #fuses XT, WDT, NOPROTECT, BROWNOUT, PUT, NOLVP, NOCPD // = Microcontroller device options #use delay(clock=3D18432000, restart_WDT) // 18.432mhz clock // Tells = compiler what clock speed // Timer1 =3D 524280 machine cycles =3D 524 milliseconds // Preload Timer1 with 3035 and it will time out in 0.5 seconds #use rs232(BAUD=3D9600,XMIT=3DPIN_C3,RCV=3DPIN_C4, INVERT ) // set up = RS232 #include // Math functions #include // string.h must be called after #USE RS232 #zero_ram // Zero all internal registers before starting program //#reserve 0x110:0x16F // RAM reserved for history array and no = other functions /////////////////////////////////////////////////////////////////////////= ////////////////////// //************************************ Variables and defines = *********************************************// /////////////////////////////////////////////////////////////////////////= ////////////////////// // DEFINES for standard PIC hardware addresses: #Byte Tmr0 =3D 0x01 #BYTE status =3D 0x03 #DEFINE carry 0 #Byte PortA =3D 0x05 #Byte PortB =3D 0x06 #Byte PortC =3D 0x07 #Byte PortD =3D 0x08 #Byte PortE =3D 0x09 #byte INTCON =3D 0x0B #byte T1Con =3D 0x10 #byte ADCON0 =3D 0x1F #BYTe adcon1 =3D 0X9F #BYTE ADRESH =3D 0x1E #BYTE ADRESL =3D 0x9F // DEFINES for hardware I/O #define Meatsensor 0 // AD0 #define Beeper 0 // RC0 // Defines for sending tones out Beeper //1st octave above middle C #define c1 523 #define g1 784 // 2nd octave above middle C #define c2 1047 #define g2 1568 #define C3 2094 int MirrorC; // Controls portC outputs long history[48]; // ARRAY used to store temperature history #BYTE history =3D 0x110 // locate history array in Bank 2 of RAM // PIC cannot use array > 96 bytes because of bank switching long history2[16]; // therefore locate the rest of the 64 byte = history array in bank 3 #BYTE history2 =3D 0x190 // Variables used in program control int State; // used to determine the State of cooking #define defaultState 0 // Startup State #define CookingState 1 // Cooking now #define DoneCookingState 2 // Done Cooking long minutes; int Seconds; int deciSecs; short timeflag; Long oldtemperature; Long MeatTemperature; Long DoneTemperature; Long EndTime; /////////////////////////////////////////////////////////////////////////= ////////////////////// //************************************ Lookup tables Long CONST piecewise[2] [16] =3D {{ 70, // piecewise interpolation of = Thermistor Data from Steinhart-Hart.xls 87 , //Column 1 is thermostor reading scaled to 1024, 137 , // column 2 is resulting temperature in C multiplied by 10 = to avoid 151 , // floating point math 172 , 216 , 271 , 336 , 413 , 499 , 590 , 680 , 764 , 837 , 888 , 1024 }, { 2500 , 1245 , 1156 , 1067 , 978 , 889 , 800 , 711 , 622 , 533 , 444 , 356 , 267 , 178 , 10 , 0 } }; /////////////////////////////////////////////////////////////////////////= ////////////////////// //************************************ SUBROUTINES = *********************************************// /////////////////////////////////////////////////////////////////////////= ///////////////////// /////////////////////////////////////////////////////////////////////////= ////////////////////// //************************************ InterruptS = *********************************************// /////////////////////////////////////////////////////////////////////////= ////////////////////// ///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////= ////////////////////// //************************************ Subroutines = *********************************************// /////////////////////////////////////////////////////////////////////////= ////////////////////// /////////////////////////////////////////////////////////////////////////= ////////////////////// // // //************************************ Measure = *********************************************// // // /////////////////////////////////////////////////////////////////////////= //////////////////// Long Measure(){ // Measure meat temperature long rawdata; long result1; int k; long A, B, C, D; result1 =3D 0; k =3D 0; rawdata =3D read_ADC(); // 10 bit right justified value // piecewise linearization!! do{ // find our location in the table result1 =3D piecewise[0] [k]; k =3D k + 1; // find the index of that location }while (result1 < rawdata); // now K points to the data in the table that most closely matches // the raw data input A =3D piecewise[0][K-1]; B =3D piecewise[0][K-1]; C =3D piecewise[1][K-1]; D =3D piecewise[1][K]; Result1 =3D (rawdata - A) * (D - C) / (B - A) + C; // interpolate into = the table return(result1); // Result is scaled to 10 times the temperature in = Degrees C // to avoid having to use floating point math! }// End of Measure /////////////////////////////////////////////////////////////////////////= ////////////////////// // // //************************************ MAIN = *********************************************// // // /////////////////////////////////////////////////////////////////////////= ////////////////////// main() { int j; restart_WDT(); portA =3D 0; portB =3D 0; portC =3D 0; portD =3D 0; SET_TRIS_A(0B11111101); =20 SET_TRIS_B(0 ); SET_TRIS_C(0B11110111); SET_TRIS_D(0B11111111); // 18.432 MHz clock =3D 217 nS machine cycles SETUP_COUNTERS(RTCC_DIV_256,WDT_18MS); // 217 nS * 256 * 256 =3D 14.22 = mS timeout SETUP_TIMER_1(T1_INTERNAL|T1_DIV_BY_8); // 0.1 sec interrupts at = 18.423 mhz if stuffed with 7935 // 18.432E6 / 4 =3D 4.608e6 machine cycle frequency // 1:8 prescale =3D 576e3 // 65535 - 7935 =3D 57.6e3 // 576e3 / 57.6e3 =3D 0.1 sec interrupts SETUP_ADC_PORTS(RA0_RA1_RA3_ANALOG); // RA0 RA1 RA3 Ref=3DVdd Setup_ADC(ADC_CLOCK_DIV_32); // Analog Digital Converter uses system = clock / 32 for timing Set_ADC_Channel(Meatsensor); // read meat sensor next time ADC is = read // Default positions for variables State =3D DefaultState; EndTime =3D 0; MeatTemperature =3D 0; Seconds =3D 0; =09 =09 =09 =09 Enable_Interrupts(Global); =09 #ASM BCF status, 5 BCF Status, 6 movlw 0b10001001 movwf ADCON0 #ENDASM Enable_Interrupts(INT_TIMER1); //////////////////////////////////////////////////////////// /// //////////////////MAIN LOOP////////////////////////////// //////////////////////////////////////////////////////////// DO{ restart_WDT(); // feed the dog MeatTemperature =3D measure(); // Measure meat temperature }WHILE(TRUE); } // end MAIN ------=_NextPart_000_003E_01C10567.100DE140-- -- http://www.piclist.com hint: To leave the PICList mailto:piclist-unsubscribe-request@mitvma.mit.edu