Components and supplies
Arduino UNO
Rotary Potentiometer - 100k Ohm, Logarithmic (Panel Mount)
Project description
Code
LInDev.h
h
Generic outline header to virtualise a non-linear analog device as a linear function using the LInterp.h PROGMEM interpolation array generator
1/* LInDev.h <<c) dxb 2022 */ 2/* prototype codes to produce linear output from a */ 3/* non-linear analog device using the LInterp array */ 4/* generator within the Arduino hardware platform */ 5 6/* replace all occurrences of "DEV" in this file with */ 7/* a unique device identifier and change the filename */ 8/* to match. Comment out or delete definitions / code */ 9/* not relevant to your device definition or specs. */ 10 11/* if the following library is omitted, LInterp will */ 12/* declare and initialise the array in RAM instead */ 13#include <avr/pgmspace.h> /* declare array in PROGMEM */ 14 15/* define our particular Arduino card ADC specs: */ 16#define DEV_CHAN A0 /* (analog channel) */ 17#define ANALOG_RNG 5000 /* (mV) */ 18#define ADC_LEV_RNG 1024 /* (ADC levels) */ 19 20/* analog device INPUT range definitions */ 21#define DEV_IN_MIN 0L /* (mV) */ 22#define DEV_IN_MAX 5000L /* (mV) */ 23 24/* Analog device OUTPUT range definitions */ 25#define DEV_OUT_MIN 0.0 /* (arb units) */ 26#define DEV_OUT_MAX 1.0 /* (arb units) */ 27#define DEV_OUT_SCL 1.0 /* (arb units) */ 28 29/* retained LInterp array definitions */ 30#define DEV_INTERP 5 /* (ADC levels) */ 31 32/* temporary LInterp array definitions */ 33#define LI_ARR DEV_LI_ARR /* device array name */ 34#define LI_CAL ADC_LEV_RNG 35#define LI_RNG ANALOG_RNG 36#define LI_SCL ( DEV_OUT_MAX - DEV_OUT_MIN ) 37#define LI_OFS DEV_OUT_MIN 38#define LI_INT DEV_INTERP 39 40/* optional processing definitions */ 41//#define LI_TYP int /* array (integer) elt type */ 42//#define LI_RAM /* declare array in RAM */ 43//#define LI_VAR /* make (RAM) array modifiable */ 44 45/* device ordinate map */ 46#define LI_P0 1000 /* (mV) */ 47#define LI_P1 1000 48#define LI_P2 1000 49#define LI_P3 1000 50#define LI_P4 1000 51#define LI_P5 1000 52#define LI_P6 1000 53#define LI_P7 1000 54#define LI_P8 1000 55#define LI_P9 1000 56#define LI_P10 1000 57#define LI_P11 1000 58#define LI_P12 1000 59#define LI_P13 1000 60#define LI_P14 1000 61#define LI_P15 1000 62#define LI_P16 1000 63#define LI_P17 1000 64#define LI_P18 1000 65#define LI_P19 1000 66#define LI_P20 1000 67#define LI_P21 1000 68#define LI_P22 1000 69#define LI_P23 1000 70#define LI_P24 1000 71#define LI_P25 1000 72#define LI_P26 1000 73#define LI_P27 1000 74#define LI_P28 1000 75#define LI_P29 1000 76#define LI_P30 1000 77#define LI_P31 1000 78 79#include "LInterp.h" /* declare and init array */ 80 81/* setup analog channel device */ 82/* CALL this function from setup() in the sketch */ 83void DEV_Setup( void ) { 84/* ... your device setup code ... */ 85} 86 87/* Array read macros */ 88#define DEV_ARRAY( i ) pgm_read_float( DEV_LI_ARR + i ) 89//#define DEV_ARRAY( i ) pgm_read_byte( DEV_LI_ARR + i ) 90//#define DEV_ARRAY( i ) pgm_read_int( DEV_LI_ARR + i ) 91//#define DEV_ARRAY( i ) pgm_read_long( DEV_LI_ARR + i ) 92 93/* Linearise supplied device output */ 94float DEV_Linear( long level ) { 95float interp_start, interp_end; 96long dev_mV, index; 97dev_mV = level * ANALOG_RNG / ADC_LEV_RNG; 98if ( dev_mV < DEV_IN_MIN ) /* bottom end of range */ 99 level = DEV_IN_MIN * ADC_LEV_RNG / ANALOG_RNG; 100else if ( dev_mV >= DEV_IN_MAX ) /* top end of range */ 101 level = DEV_IN_MAX * ADC_LEV_RNG / ANALOG_RNG; 102level -= (long) DEV_IN_MIN * ADC_LEV_RNG / ANALOG_RNG; 103index = level / DEV_INTERP; 104interp_start = DEV_ARRAY( index ); 105interp_end = DEV_ARRAY( index + 1 ); 106return ( interp_start + ( interp_end - interp_start ) * 107 ( level % DEV_INTERP ) / DEV_INTERP ); 108} 109 110/* read analog device and linearise output */ 111float DEV_Read() { 112return( DEV_Linear( analogRead( DEV_CHAN ) ) ); 113} 114 115/* read averaged analog device and linearise output */ 116float DEV_ReadAvg() { 117int samps; 118long ADClevel = 0; 119/* take an average of several analog channel readings */ 120for ( samps = 0; samps < 20; samps++ ) { 121 ADClevel += analogRead( DEV_CHAN ); 122 delay( 5 ); 123 } 124return ( DEV_Linear( ADClevel / samps ) ); 125} 126 127 128
PotUnLog.ino
arduino
Example Arduino program using LInterp.h to linearise part of the range of a logarithmic potentiometer
1/* PotUnLog.ino <<c) dxb 2022 */ 2/* Demo program for LInterp PROGMEM array generator */ 3/* assumes Arduino IDE serial monitor is active */ 4 5/* if the following library is omitted, LInterp will */ 6/* declare and initialise the array in RAM instead */ 7#include <avr/pgmspace.h> /* declare array in PROGMEM */ 8 9/* Example: linear transform for part of the range of */ 10/* a logarithmic potentiometer attached to an analog */ 11/* input of (any) Arduino board. The ends of the pot */ 12/* should be connected to (analog) +V and GND with */ 13/* the pot sweep terminal connected to the input pin. */ 14 15/* first, define our desired pot output specs: */ 16#define LogPotLinFrom 3.0 /* (arb units) */ 17#define LogPotLinTo 7.0 /* (arb units) */ 18#define LogPotScale 10.0 /* (arb units) */ 19/* define the array specs we need to retain */ 20#define LogPotLinOfs 1330L /* (mV) */ 21#define LogPotLinEnd 3500L /* (mV) */ 22#define LogPotRes 5 /* (ADC levels) */ 23/* define our particular Arduino card ADC specs: */ 24#define PotChan A0 /* (analog channel ID) */ 25#define AnalogRange 5000 /* (mV) (NOMINAL!) */ 26#define ADCLevels 1024 /* (ADC levels) */ 27 28/* next, give LInterp our pot specs for the array def */ 29/* all LI_.. defs will be deleted after the array dec */ 30#define LI_ARR LParray /* our xfrom array name */ 31#define LI_CAL ADCLevels /* arr ordinate scale (L) */ 32#define LI_RNG AnalogRange /* input map pt scale (L) */ 33#define LI_SCL ( LogPotLinTo - LogPotLinFrom ) 34#define LI_OFS LogPotLinFrom 35#define LI_INT LogPotRes /* interpolation width */ 36 37#define LI_P0 1330 /* (mV) pot voltage map */ 38#define LI_P1 1570 /* assume regular spacing */ 39#define LI_P2 1810 /* by angular increments */ 40#define LI_P3 2100 /* of pot rotation sweep */ 41#define LI_P4 2370 42#define LI_P5 2705 43#define LI_P6 2955 44#define LI_P7 3230 /* min of 4 points ... */ 45#define LI_P8 3500 /* ... max of 32 points */ 46 47#include "LInterp.h" /* declare and init array */ 48/* ... repeat the declaration list for another array */ 49 50/* define a macro to hide the PROGMEM array funtion */ 51#define LogPotLinPart( i ) pgm_read_float( LParray + i ) 52 53float ReadPot() { /* read pot level and scale it */ 54float interp_start, interp_end, pot_value; 55int samps, index; 56/* these are declared long to prevent int overflows: */ 57long pot_mV, pot_ADClevel = 0; 58/* take an average of several analog channel readings */ 59for ( samps = 0; samps < 20; samps++ ) { 60 pot_ADClevel += analogRead( PotChan ); 61 delay( 10 ); 62 } 63pot_ADClevel /= samps; 64/* uncorrected log pot voltage from analog channel */ 65pot_mV = pot_ADClevel * AnalogRange / ADCLevels; 66/* check bounds of our linear part and scale outside */ 67if ( pot_mV < LogPotLinOfs ) /* bottom end of range */ 68 pot_value = LogPotLinFrom * pot_mV / LogPotLinOfs; 69else if ( pot_mV >= LogPotLinEnd )/* top end of range */ 70 pot_value = ( LogPotScale - LogPotLinTo ) * 71 pot_mV / ( AnalogRange - LogPotLinEnd ); 72/* otherwise pot is within our transform array range */ 73else { /* subtract the array offset in ADC levels */ 74 pot_ADClevel -= LogPotLinOfs * ADCLevels / AnalogRange; 75 /* divide by the interp size to gat the array index */ 76 index = pot_ADClevel / LogPotRes; 77 /* get the array elt containing this pot ADC level */ 78 interp_start = LogPotLinPart( index ); 79 /* get the next array elt to interpolate in-between */ 80 interp_end = LogPotLinPart( index + 1 ); 81 /* linear interpolation b/w bounding array entries */ 82 pot_value = interp_start + ( interp_end - interp_start ) * 83 ( pot_ADClevel % LogPotRes ) / LogPotRes; 84 } 85/* return the pot voltage encoded as a knob-position */ 86return( pot_value ); 87} 88 89void setup() { /* check: print array values */ 90int i = 0; 91Serial.begin( 9600 ); 92Serial.println( "Press any key to start" ); 93while ( !Serial.available() ) delay( 100 ); 94while ( Serial.available() ) Serial.read(); 95Serial.print( "const float LParray[] PROGMEM = {\ 96" ); 97/* this is how to get the array size, in elements */ 98while ( i < sizeof( LParray ) / sizeof( float ) ){ 99 Serial.print( LogPotLinPart( i ), 2 ); 100 /* print values in blocks of 15 */ 101 if ( ( i + 1 ) % 15 ) Serial.print( "\ " ); 102 else Serial.print( "\ 103" ); 104 i++; 105 }; 106Serial.print( "}\ 107Array size: " ); 108Serial.println( i ); 109Serial.println( "press any key to continue" ); 110while ( !Serial.available() ) delay( 100 ); 111while ( Serial.available() ) Serial.read(); 112} 113 114void loop() { 115Serial.println( ReadPot(), 2 ); 116delay( 300 ); 117} 118
LInDev.h
h
Generic outline header to virtualise a non-linear analog device as a linear function using the LInterp.h PROGMEM interpolation array generator
1/* LInDev.h <<c) dxb 2022 */ 2/* prototype codes to produce linear output from a */ 3/* non-linear analog device using the LInterp array */ 4/* generator within the Arduino hardware platform */ 5 6/* replace all occurrences of "DEV" in this file with */ 7/* a unique device identifier and change the filename */ 8/* to match. Comment out or delete definitions / code */ 9/* not relevant to your device definition or specs. */ 10 11/* if the following library is omitted, LInterp will */ 12/* declare and initialise the array in RAM instead */ 13#include <avr/pgmspace.h> /* declare array in PROGMEM */ 14 15/* define our particular Arduino card ADC specs: */ 16#define DEV_CHAN A0 /* (analog channel) */ 17#define ANALOG_RNG 5000 /* (mV) */ 18#define ADC_LEV_RNG 1024 /* (ADC levels) */ 19 20/* analog device INPUT range definitions */ 21#define DEV_IN_MIN 0L /* (mV) */ 22#define DEV_IN_MAX 5000L /* (mV) */ 23 24/* Analog device OUTPUT range definitions */ 25#define DEV_OUT_MIN 0.0 /* (arb units) */ 26#define DEV_OUT_MAX 1.0 /* (arb units) */ 27#define DEV_OUT_SCL 1.0 /* (arb units) */ 28 29/* retained LInterp array definitions */ 30#define DEV_INTERP 5 /* (ADC levels) */ 31 32/* temporary LInterp array definitions */ 33#define LI_ARR DEV_LI_ARR /* device array name */ 34#define LI_CAL ADC_LEV_RNG 35#define LI_RNG ANALOG_RNG 36#define LI_SCL ( DEV_OUT_MAX - DEV_OUT_MIN ) 37#define LI_OFS DEV_OUT_MIN 38#define LI_INT DEV_INTERP 39 40/* optional processing definitions */ 41//#define LI_TYP int /* array (integer) elt type */ 42//#define LI_RAM /* declare array in RAM */ 43//#define LI_VAR /* make (RAM) array modifiable */ 44 45/* device ordinate map */ 46#define LI_P0 1000 /* (mV) */ 47#define LI_P1 1000 48#define LI_P2 1000 49#define LI_P3 1000 50#define LI_P4 1000 51#define LI_P5 1000 52#define LI_P6 1000 53#define LI_P7 1000 54#define LI_P8 1000 55#define LI_P9 1000 56#define LI_P10 1000 57#define LI_P11 1000 58#define LI_P12 1000 59#define LI_P13 1000 60#define LI_P14 1000 61#define LI_P15 1000 62#define LI_P16 1000 63#define LI_P17 1000 64#define LI_P18 1000 65#define LI_P19 1000 66#define LI_P20 1000 67#define LI_P21 1000 68#define LI_P22 1000 69#define LI_P23 1000 70#define LI_P24 1000 71#define LI_P25 1000 72#define LI_P26 1000 73#define LI_P27 1000 74#define LI_P28 1000 75#define LI_P29 1000 76#define LI_P30 1000 77#define LI_P31 1000 78 79#include "LInterp.h" /* declare and init array */ 80 81/* setup analog channel device */ 82/* CALL this function from setup() in the sketch */ 83void DEV_Setup( void ) { 84/* ... your device setup code ... */ 85} 86 87/* Array read macros */ 88#define DEV_ARRAY( i ) pgm_read_float( DEV_LI_ARR + i ) 89//#define DEV_ARRAY( i ) pgm_read_byte( DEV_LI_ARR + i ) 90//#define DEV_ARRAY( i ) pgm_read_int( DEV_LI_ARR + i ) 91//#define DEV_ARRAY( i ) pgm_read_long( DEV_LI_ARR + i ) 92 93/* Linearise supplied device output */ 94float DEV_Linear( long level ) { 95float interp_start, interp_end; 96long dev_mV, index; 97dev_mV = level * ANALOG_RNG / ADC_LEV_RNG; 98if ( dev_mV < DEV_IN_MIN ) /* bottom end of range */ 99 level = DEV_IN_MIN * ADC_LEV_RNG / ANALOG_RNG; 100else if ( dev_mV >= DEV_IN_MAX ) /* top end of range */ 101 level = DEV_IN_MAX * ADC_LEV_RNG / ANALOG_RNG; 102level -= (long) DEV_IN_MIN * ADC_LEV_RNG / ANALOG_RNG; 103index = level / DEV_INTERP; 104interp_start = DEV_ARRAY( index ); 105interp_end = DEV_ARRAY( index + 1 ); 106return ( interp_start + ( interp_end - interp_start ) * 107 ( level % DEV_INTERP ) / DEV_INTERP ); 108} 109 110/* read analog device and linearise output */ 111float DEV_Read() { 112return( DEV_Linear( analogRead( DEV_CHAN ) ) ); 113} 114 115/* read averaged analog device and linearise output */ 116float DEV_ReadAvg() { 117int samps; 118long ADClevel = 0; 119/* take an average of several analog channel readings */ 120for ( samps = 0; samps < 20; samps++ ) { 121 ADClevel += analogRead( DEV_CHAN ); 122 delay( 5 ); 123 } 124return ( DEV_Linear( ADClevel / samps ) ); 125} 126 127 128
LInterp.h
h
Arduino C-compiler pre-processor script to generate interpolation / translation / lookup arrays in PROGMEM
1/* LInterp.h Linear interpolation array generator */ 2/* <<c) dxb 1982 - 2022 */ 3 4#if defined( LI_ELT ) /* generate array elt */ 5#if LI_LEV < LI_BND && !defined( LI_EOI ) 6 #if ( LI_ELT <= LI_S( LI_LEV, LI_NXT ) + ( LI_LEV == LI_BND - 1 ) ) 7 ,(LI_TYP) ( LI_RND + LI_OFS + LI_SCL * ( LI_LEV + 8 ( LI_ELT - LI_R( 0, LI_LEV ) + LI_P( 0, LI_LEV ) ) / 9 LI_R( LI_LEV, LI_NXT ) ) / LI_BND ) 10 #else 11 #define LI_EOI 12 #endif 13#endif 14#undef LI_ELT 15 16#elif defined( LI_LEV ) /* process intervals */ 17#define LI_ELT 1 18#include "LInterp.h" 19#define LI_ELT 2 20#include "LInterp.h" 21#define LI_ELT 3 22#include "LInterp.h" 23#define LI_ELT 4 24#include "LInterp.h" 25#define LI_ELT 5 26#include "LInterp.h" 27#define LI_ELT 6 28#include "LInterp.h" 29#define LI_ELT 7 30#include "LInterp.h" 31#define LI_ELT 8 32#include "LInterp.h" 33#define LI_ELT 9 34#include "LInterp.h" 35#define LI_ELT 10 36#include "LInterp.h" 37#define LI_ELT 11 38#include "LInterp.h" 39#define LI_ELT 12 40#include "LInterp.h" 41#define LI_ELT 13 42#include "LInterp.h" 43#define LI_ELT 14 44#include "LInterp.h" 45#define LI_ELT 15 46#include "LInterp.h" 47#define LI_ELT 16 48#include "LInterp.h" 49#define LI_ELT 17 50#include "LInterp.h" 51#define LI_ELT 18 52#include "LInterp.h" 53#define LI_ELT 19 54#include "LInterp.h" 55#define LI_ELT 20 56#include "LInterp.h" 57#define LI_ELT 21 58#include "LInterp.h" 59#define LI_ELT 22 60#include "LInterp.h" 61#define LI_ELT 23 62#include "LInterp.h" 63#define LI_ELT 24 64#include "LInterp.h" 65#define LI_ELT 25 66#include "LInterp.h" 67#define LI_ELT 26 68#include "LInterp.h" 69#define LI_ELT 27 70#include "LInterp.h" 71#define LI_ELT 28 72#include "LInterp.h" 73#define LI_ELT 29 74#include "LInterp.h" 75#define LI_ELT 30 76#include "LInterp.h" 77#define LI_ELT 31 78#include "LInterp.h" 79#define LI_ELT 32 /* <- repeat these lines for more */ 80#include "LInterp.h" /* <- interps, with inc elt idxs */ 81/* ... */ 82#if LI_LEV < LI_BND && !defined( LI_EOI ) 83#error LInterp: Too many interps in one interval. Add mapping pts or decrease LI_INT 84#endif 85#undef LI_EOI 86#undef LI_LEV 87#undef LI_NXT 88 89#else /* define array params */ 90#if !defined( LI_P0 ) || !defined( LI_P1 ) || !defined( LI_P2 ) || !defined( LI_P3 ) 91#error LIinterp: define at least 4 mapping values LI_P0 to LI_Pnn (nn < 32) 92#endif 93#if !defined( LI_TYP ) 94#define LI_TYP float /* default array type */ 95#define LI_RND 0 /* no rounding */ 96#else /* all integer types! */ 97#define LI_RND 0.5 /* for float-int convs */ 98#endif 99#if !defined( LI_ARR ) 100#define LI_ARR LInterp /* default array name */ 101#endif 102#if !defined ( LI_RNG ) /* input ordinate range */ 103#error LInterp: Define an ordinate mapping scale LI_RNG 104#endif 105#if !defined( LI_CAL ) /* array indexing scale */ 106#error LInterp: Define an array-base indexing scale LI_CAL 107#endif 108#if !defined( LI_INT ) 109#define LI_INT 1 /* interp interval */ 110#endif 111#if !defined( LI_SCL ) 112#define LI_SCL 1 /* array value scale */ 113#endif 114#if !defined( LI_OFS ) 115#define LI_OFS 0 /* array value offset */ 116#endif 117#if !defined( LI_VAR ) 118#define LI_VAR const /* array value offset */ 119#endif 120 121#if !defined( LI_P4 ) 122#define LI_BND 3 123#elif !defined( LI_P5 ) 124#define LI_BND 4 125#elif !defined( LI_P6 ) 126#define LI_BND 5 127#elif !defined( LI_P7 ) 128#define LI_BND 6 129#elif !defined( LI_P8 ) 130#define LI_BND 7 131#elif !defined( LI_P9 ) 132#define LI_BND 8 133#elif !defined( LI_P10 ) 134#define LI_BND 9 135#elif !defined( LI_P11 ) 136#define LI_BND 10 137#elif !defined( LI_P12 ) 138#define LI_BND 11 139#elif !defined( LI_P13 ) 140#define LI_BND 12 141#elif !defined( LI_P14 ) 142#define LI_BND 13 143#elif !defined( LI_P15 ) 144#define LI_BND 14 145#elif !defined( LI_P16 ) 146#define LI_BND 15 147#elif !defined( LI_P17 ) 148#define LI_BND 16 149#elif !defined( LI_P18 ) 150#define LI_BND 17 151#elif !defined( LI_P19 ) 152#define LI_BND 18 153#elif !defined( LI_P20 ) 154#define LI_BND 19 155#elif !defined( LI_P21 ) 156#define LI_BND 20 157#elif !defined( LI_P22 ) 158#define LI_BND 21 159#elif !defined( LI_P23 ) 160#define LI_BND 22 161#elif !defined( LI_P24 ) 162#define LI_BND 23 163#elif !defined( LI_P25 ) 164#define LI_BND 24 165#elif !defined( LI_P26 ) 166#define LI_BND 25 167#elif !defined( LI_P27 ) 168#define LI_BND 26 169#elif !defined( LI_P28 ) 170#define LI_BND 27 171#elif !defined( LI_P29 ) 172#define LI_BND 28 173#elif !defined( LI_P30 ) 174#define LI_BND 29 175#elif !defined( LI_P31 ) 176#define LI_BND 30 177/* repeat following defn block for more mapping points */ 178/* increasing iterators as per sequence above */ 179/* also add matching interval inits at end of file */ 180#elif !defined( LI_P32 ) 181#define LI_BND 31 182/* ... */ 183#else 184#error LInterp: Too many mapping points defined. Add extra point defs to LInterp.h 185#endif 186 187#define LI_V( i ) ( LI_P##i ) /* compile pass */ 188#define LI_Q( i ) ( LI_V( i ) * 1L * LI_CAL ) 189#define LI_P( i, j ) ( ( LI_Q( j ) - LI_Q( i ) ) / ( 1L * LI_INT * LI_RNG ) ) 190#define LI_R( i, j ) ( (float) ( LI_Q( j ) - LI_Q( i ) ) / ( LI_INT * LI_RNG ) ) 191#define LI_S( i, j ) ( LI_P( 0, j ) - LI_P( 0, i ) ) 192 193#if defined( PROGMEM ) && !defined( LI_RAM ) 194const LI_TYP LI_ARR[] PROGMEM = { LI_OFS 195#else 196LI_VAR LI_TYP LI_ARR[] = { LI_OFS 197#endif 198#define LI_LEV 0 199#define LI_NXT 1 200#include "LInterp.h" 201#define LI_LEV 1 202#define LI_NXT 2 203#include "LInterp.h" 204#undef LI_P1 205#define LI_LEV 2 206#define LI_NXT 3 207#include "LInterp.h" 208#undef LI_P2 209#define LI_LEV 3 210#define LI_NXT 4 211#include "LInterp.h" 212#undef LI_P3 213#define LI_LEV 4 214#define LI_NXT 5 215#include "LInterp.h" 216#undef LI_P4 217#define LI_LEV 5 218#define LI_NXT 6 219#include "LInterp.h" 220#undef LI_P5 221#define LI_LEV 6 222#define LI_NXT 7 223#include "LInterp.h" 224#undef LI_P6 225#define LI_LEV 7 226#define LI_NXT 8 227#include "LInterp.h" 228#undef LI_P7 229#define LI_LEV 8 230#define LI_NXT 9 231#include "LInterp.h" 232#undef LI_P8 233#define LI_LEV 9 234#define LI_NXT 10 235#include "LInterp.h" 236#undef LI_P9 237#define LI_LEV 10 238#define LI_NXT 11 239#include "LInterp.h" 240#undef LI_P10 241#define LI_LEV 11 242#define LI_NXT 12 243#include "LInterp.h" 244#undef LI_P11 245#define LI_LEV 12 246#define LI_NXT 13 247#include "LInterp.h" 248#undef LI_P12 249#define LI_LEV 13 250#define LI_NXT 14 251#include "LInterp.h" 252#undef LI_P13 253#define LI_LEV 14 254#define LI_NXT 15 255#include "LInterp.h" 256#undef LI_P14 257#define LI_LEV 15 258#define LI_NXT 16 259#include "LInterp.h" 260#undef LI_P15 261#define LI_LEV 16 262#define LI_NXT 17 263#include "LInterp.h" 264#undef LI_P16 265#define LI_LEV 17 266#define LI_NXT 18 267#include "LInterp.h" 268#undef LI_P17 269#define LI_LEV 18 270#define LI_NXT 19 271#include "LInterp.h" 272#undef LI_P18 273#define LI_LEV 19 274#define LI_NXT 20 275#include "LInterp.h" 276#undef LI_P19 277#define LI_LEV 20 278#define LI_NXT 21 279#include "LInterp.h" 280#undef LI_P20 281#define LI_LEV 21 282#define LI_NXT 22 283#include "LInterp.h" 284#undef LI_P21 285#define LI_LEV 22 286#define LI_NXT 23 287#include "LInterp.h" 288#undef LI_P22 289#define LI_LEV 23 290#define LI_NXT 24 291#include "LInterp.h" 292#undef LI_P23 293#define LI_LEV 24 294#define LI_NXT 25 295#include "LInterp.h" 296#undef LI_P24 297#define LI_LEV 25 298#define LI_NXT 26 299#include "LInterp.h" 300#undef LI_P25 301#define LI_LEV 26 302#define LI_NXT 27 303#include "LInterp.h" 304#undef LI_P26 305#define LI_LEV 27 306#define LI_NXT 28 307#include "LInterp.h" 308#undef LI_P27 309#define LI_LEV 28 310#define LI_NXT 29 311#include "LInterp.h" 312#undef LI_P28 313#define LI_LEV 29 314#define LI_NXT 30 315#include "LInterp.h" 316#undef LI_P29 317#define LI_LEV 30 /* <- repeat this set of defs */ 318#define LI_NXT 31 /* <- with increasing indices */ 319#include "LInterp.h" /* <- for further map defn pts */ 320#undef LI_P30 /* <- */ 321/* ... */ 322#undef LI_P31 /* change to match LI_BND defn */ 323}; 324 325#undef LI_P0 326#undef LI_ARR 327#undef LI_SCL 328#undef LI_TYP 329#undef LI_RND 330#undef LI_RNG 331#undef LI_CAL 332#undef LI_INT 333#undef LI_SCL 334#undef LI_OFS 335#undef LI_BND 336#undef LI_RAM 337#undef LI_VAR 338#undef LI_V 339#undef LI_Q 340#undef LI_P 341#undef LI_R 342#undef LI_S 343#undef LI_N 344#undef LI_W 345#endif 346 347/* EOF LInterp.h */ 348
PotUnLog.ino
arduino
Example Arduino program using LInterp.h to linearise part of the range of a logarithmic potentiometer
1/* PotUnLog.ino <<c) dxb 2022 */ 2/* Demo program for LInterp PROGMEM array generator */ 3/* assumes Arduino IDE serial monitor is active */ 4 5/* if the following library is omitted, LInterp will */ 6/* declare and initialise the array in RAM instead */ 7#include <avr/pgmspace.h> /* declare array in PROGMEM */ 8 9/* Example: linear transform for part of the range of */ 10/* a logarithmic potentiometer attached to an analog */ 11/* input of (any) Arduino board. The ends of the pot */ 12/* should be connected to (analog) +V and GND with */ 13/* the pot sweep terminal connected to the input pin. */ 14 15/* first, define our desired pot output specs: */ 16#define LogPotLinFrom 3.0 /* (arb units) */ 17#define LogPotLinTo 7.0 /* (arb units) */ 18#define LogPotScale 10.0 /* (arb units) */ 19/* define the array specs we need to retain */ 20#define LogPotLinOfs 1330L /* (mV) */ 21#define LogPotLinEnd 3500L /* (mV) */ 22#define LogPotRes 5 /* (ADC levels) */ 23/* define our particular Arduino card ADC specs: */ 24#define PotChan A0 /* (analog channel ID) */ 25#define AnalogRange 5000 /* (mV) (NOMINAL!) */ 26#define ADCLevels 1024 /* (ADC levels) */ 27 28/* next, give LInterp our pot specs for the array def */ 29/* all LI_.. defs will be deleted after the array dec */ 30#define LI_ARR LParray /* our xfrom array name */ 31#define LI_CAL ADCLevels /* arr ordinate scale (L) */ 32#define LI_RNG AnalogRange /* input map pt scale (L) */ 33#define LI_SCL ( LogPotLinTo - LogPotLinFrom ) 34#define LI_OFS LogPotLinFrom 35#define LI_INT LogPotRes /* interpolation width */ 36 37#define LI_P0 1330 /* (mV) pot voltage map */ 38#define LI_P1 1570 /* assume regular spacing */ 39#define LI_P2 1810 /* by angular increments */ 40#define LI_P3 2100 /* of pot rotation sweep */ 41#define LI_P4 2370 42#define LI_P5 2705 43#define LI_P6 2955 44#define LI_P7 3230 /* min of 4 points ... */ 45#define LI_P8 3500 /* ... max of 32 points */ 46 47#include "LInterp.h" /* declare and init array */ 48/* ... repeat the declaration list for another array */ 49 50/* define a macro to hide the PROGMEM array funtion */ 51#define LogPotLinPart( i ) pgm_read_float( LParray + i ) 52 53float ReadPot() { /* read pot level and scale it */ 54float interp_start, interp_end, pot_value; 55int samps, index; 56/* these are declared long to prevent int overflows: */ 57long pot_mV, pot_ADClevel = 0; 58/* take an average of several analog channel readings */ 59for ( samps = 0; samps < 20; samps++ ) { 60 pot_ADClevel += analogRead( PotChan ); 61 delay( 10 ); 62 } 63pot_ADClevel /= samps; 64/* uncorrected log pot voltage from analog channel */ 65pot_mV = pot_ADClevel * AnalogRange / ADCLevels; 66/* check bounds of our linear part and scale outside */ 67if ( pot_mV < LogPotLinOfs ) /* bottom end of range */ 68 pot_value = LogPotLinFrom * pot_mV / LogPotLinOfs; 69else if ( pot_mV >= LogPotLinEnd )/* top end of range */ 70 pot_value = ( LogPotScale - LogPotLinTo ) * 71 pot_mV / ( AnalogRange - LogPotLinEnd ); 72/* otherwise pot is within our transform array range */ 73else { /* subtract the array offset in ADC levels */ 74 pot_ADClevel -= LogPotLinOfs * ADCLevels / AnalogRange; 75 /* divide by the interp size to gat the array index */ 76 index = pot_ADClevel / LogPotRes; 77 /* get the array elt containing this pot ADC level */ 78 interp_start = LogPotLinPart( index ); 79 /* get the next array elt to interpolate in-between */ 80 interp_end = LogPotLinPart( index + 1 ); 81 /* linear interpolation b/w bounding array entries */ 82 pot_value = interp_start + ( interp_end - interp_start ) * 83 ( pot_ADClevel % LogPotRes ) / LogPotRes; 84 } 85/* return the pot voltage encoded as a knob-position */ 86return( pot_value ); 87} 88 89void setup() { /* check: print array values */ 90int i = 0; 91Serial.begin( 9600 ); 92Serial.println( "Press any key to start" ); 93while ( !Serial.available() ) delay( 100 ); 94while ( Serial.available() ) Serial.read(); 95Serial.print( "const float LParray[] PROGMEM = {\ 96" ); 97/* this is how to get the array size, in elements */ 98while ( i < sizeof( LParray ) / sizeof( float ) ){ 99 Serial.print( LogPotLinPart( i ), 2 ); 100 /* print values in blocks of 15 */ 101 if ( ( i + 1 ) % 15 ) Serial.print( "\ " ); 102 else Serial.print( "\ 103" ); 104 i++; 105 }; 106Serial.print( "}\ 107Array size: " ); 108Serial.println( i ); 109Serial.println( "press any key to continue" ); 110while ( !Serial.available() ) delay( 100 ); 111while ( Serial.available() ) Serial.read(); 112} 113 114void loop() { 115Serial.println( ReadPot(), 2 ); 116delay( 300 ); 117} 118
Downloadable files
Logarithmic potentiometer
Produces a non-linear voltage increase with rotation angle attached to an analog input
Logarithmic potentiometer
Logarithmic potentiometer
Produces a non-linear voltage increase with rotation angle attached to an analog input
Logarithmic potentiometer
Comments
Only logged in users can leave comments
dxb_
0 Followers
•0 Projects
0
0