Language Reference Map()

techElder

Well-known member
Here's a challenge. Haven't seen a PICAXE routine that will do what the 'C' Map() function will do. That would be very handy converting ADC values 0-1023 to LED string values 1-144. I'm trying to understand what the constraints would be.

Re-maps a number from one range to another. That is, a value of fromLow would get mapped to toLow, a value of fromHigh to toHigh, values in-between to values in-between, etc.

Does not constrain values to within the range, because out-of-range values are sometimes intended and useful. The constrain() function may be used either before or after this function, if limits to the ranges are desired.

Syntax

map(value, fromLow, fromHigh, toLow, toHigh)

Parameters

value: the number to map

fromLow: the lower bound of the value’s current range

fromHigh: the upper bound of the value’s current range

toLow: the lower bound of the value’s target range

toHigh: the upper bound of the value’s target range
Code:
For the mathematically inclined, here’s the whole function

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
 

BESQUEUT

Senior Member
Here's a challenge. Haven't seen a PICAXE routine that will do what the 'C' Map() function will do. That would be very handy converting ADC values 0-1023 to LED string values 1-144. I'm trying to understand what the constraints would be.

Code:
For the mathematically inclined, here’s the whole function

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
First attempt, supposing in is readadc10, so : in_min=0, in_max=1023 ==> in_max-in_min +1 =1024
N=(x-in_min)*(out_max-out_min) that is N = x * (out_max-out_min)
N <65536
So there can't be more than 64 differents values for result.

Of course, Picaxe users will do some optimisation depending from the out_max-out_min factor...
For example, supposing out_max = 5000 mV and out_min=0mV
out=x*50/32*25/8

(IMHO, it will be very difficult (but nothing is really difficult for Mr Hippy...) to write an universal map macro and/or subroutine. But, this seems to be a good challenge for some form of pre-compiler as my ROSLYN project...)
 
Last edited:

techElder

Well-known member
Dang it! I'll never fully like ... this forum's search functions. I looked for "map*", but got 500+ results and decided that most of them would be about "mapping" to RAM.

Good one, Buzby.

I'm still interested in what BESQUEUT comes up with.

BESQUEUT, don't let Hippy's solution get the best of you! :D :D :D
 

AllyCat

Senior Member
Hi,

The basic principle is also at the heart of my "interpolation" thread that I've recently been updating. It includes a few methods for handling overflow issues, primarily by restricting one of the axes to multiples of 256 (i.e. bytes) to keep the maths simpler (personal view ;) ).

Or if you want a thorough handling of the maths, search for Jeremy Leach's several posts for solving " A*B/C ", for example here .

Cheers, Alan.
 

techElder

Well-known member
So, translating hippy's solution from JSDL's question to my 144 LED string ... (not meaning to attribute these new numbers to hippy's preferences):

LEDs = 1 to 144
Or
LEDs = ( 0 to 143 ) + 1
So you need to convert your pot of '0 to 1023' to ' 0 to 143' ...
0 to 143 = ( 0 to 1023 ) * 143 / 1023
So ...
LEDs = pot * 143 / 1023 + 1
But with 'pot' at 1023 * 143 will overflow 16-bits, so you need to either divide top and bottom by 10 and use ...
LEDs = pot * 14 / 102 + 1
or, more accurately, by dividing top and bottom by 3 ...
LEDs = pot * 47 / 341 + 1
or convert 143/1023 to 9160/65536 and then use ...
FIRST SOLUTION: LEDs = pot ** 9160 + 1
Because 1023 * 47 does not overflow I would personally go for ...
SECOND SOLUTION: LEDs = pot * 47 / 341 + 1

I think hippy's comments apply to "143" as they did to "150" although there is more loss with dividing 143 by 3 than 150 by 3 (2/3's of an LED), so the first solution seems to more closely track the needed response. However, there's only a one LED difference. I'm sure "noise" will have more effect than that.

Code:
w0 = 1023 ** 9160 + 1   ; first solution
w1 = 1023 * 47/341 + 1  ; second solution
w2 = 511 ** 9160 + 1
w3 = 511 * 47/341 + 1
w4 = 255 ** 9160 + 1
w5 = 255 * 47/341 + 1
w6 = 127 ** 9160 + 1
w7 = 127 * 47/341 + 1
 
Last edited:

mikeyBoo

Senior Member
Converting Whatever to Whatever... (unitsA -> unitsB, volts -> bit values, apples -> oranges)
If someone would like to expand to convert larger numbers, that would be useful.

Code:
; USED WITH linearConversion proc shown below
; Following Always Need to be Reserved for Doing Scale Conversions :_
symbol scale1Lo    = w6   ; place to put "from" scale bottom
symbol scale1Hi    = w7   ; place to put "from" scale top
symbol scale2Lo    = w8   ; place to put "to" scale bottom
symbol scale2Hi    = w9   ; place to put "to" scale top
symbol span1       = w10  ; place to put "from" scale span
symbol span2       = w11  ; place to put "to" scale span
symbol scale1Val   = w12  ; place to put input value (value to be converted)
symbol outValue    = w13  ; place to put output value (result of conversion)
symbol outValueLo  = b26  ; lo-byte of output value (result of conversion)
symbol outValueHi  = b27  ; hi-byte of output value (result of conversion)

; linearConversion --  (v1.00a by M. Ballew 02-01-2015)
;       convert value between linear scales
;       be aware that Picaxe can only deal with numbers 0...65535, so if the proc gets an
;       answer > 65535, it will be incorrect
;       i.e. ((scale1Val - scale1Lo) * span2) Must be < 65536
;       to verify you're not going over 65535, need to know:
;          maxInputValue (which should be = scale1Hi)
;               scale1Lo (usually 0, but may be offset)
;                  span2 (scale2Hi - scale2Lo)
;         e.g. to display battery voltage range 0..15.0vdc (1 decimal place)
;              scale1Hi (our max input value) = 255, span2Value = 150, scale1Lo = 0
;              to test:  (255 - 0) * 150 = 38250  (good, well under 65536)
;
; Status: (works ok)
;         Don't like that this proc uses so many byte/word registers.
;         Consider using RAM (28...511) registers for plugging in conversion scales
;         this would cause a loss of speed, but would not tie up so many word regs
;
; Revisions:
;       none
;
; Arguments:
;        scale1Lo  "from" scale bottom
;        scale1Hi  "from" scale top
;        scale2Lo    "to" scale bottom
;        scale2Hi    "to" scale top
;       scale1Val  "from" scale value to be converted
;
; Results:
;       outValue  contains scale2 equivalent of scale1Val
;       w4...w13  altered
;
; Example:
;       let scale1Lo = 0 : let scale1Hi = 255 : let scale2Lo = 0 : let scale2Hi = 5000 ; plug in scales
;       let scale1Val = 112 ; value to convert
;       gosub linearConversion
;
linearConversion:
    let span1 = scale1Hi - scale1Lo
    let span2 = scale2Hi - scale2Lo
    let outValue = scale1Val - scale1Lo * span2 / span1 + scale2Lo
    ; round off remainder
    let w5 = scale1Val * span2 // span1 ; get remainder
    let w4 = span1 / 2
    if w5 > w4 then
        let outValue = outValue + 1
    endif
    return


; Simpler Version Where Scales are assumed to have bottoms = 0

; Following Need to be Reserved for Doing Simplified Scale Conversions :_
; following are used in linearConversionNoLowOffset proc
; Note that some word registers serve double-duty in conversion proc
symbol scale1Hi    = w10  ; place to put "from" scale top
symbol halfScale   = w10  ; used for testing remainder
symbol scale2Hi    = w11  ; place to put "to" scale top
symbol remainder   = w11  ; remainder of scale conversion calc
symbol scale1Val   = w12  ; place to put input value (value to be converted)
symbol outValue    = w13  ; place to put output value (result of conversion)
symbol outValueLo  = b26  ; lo-byte of output value (result of conversion)
symbol outValueHi  = b27  ; hi-byte of output value (result of conversion)

; linearConversionNoLowOffset --  (v1.00a by M. Ballew 02-21-2015)
;       TAKE NOTE: this is a simplified version of the linearConversion procedure
;                  THIS PROC ASSUMES THAT THE SCALES BOTH HAVE A BOTTOM VALUE = 0
;       The ONLY reason for using this proc over linearConversion is to save Picaxe program memory
;       be aware that Picaxe can only deal with numbers 0...65535, so if the proc gets an
;       answer > 65535, it will be incorrect
;       i.e. (scale1Val * scale2Hi) Must be < 65536
;       to verify you're not going over 65535, need to know:
;          maxInputValue (which should be = scale1Hi)
;               scale2Hi
;         e.g. to display battery voltage range 0..15.0vdc (1 decimal place)
;              scale1Hi (our max input value) = 255, scale2Hi = 150
;              to test:  255 * 150 = 38250  (good, well under 65536)
;
; Status: (works ok)
;
; Revisions:
;       none
;
; Arguments:
;        scale1Hi  "from" scale top
;        scale2Hi    "to" scale top
;       scale1Val  "from" scale value to be converted
;
; Results:
;       outValue  contains scale2 equivalent of scale1Val
;
;
; Example:
;       let scale1Hi = 255 : let scale2Hi = 150 : let scale1Val = 112 ; plug in scales & value to convert
;       gosub linearConversionNoLowOffset ; outValue <- convert scale1Val (based on scale1Hi & scale2Hi)
linearConversionNoLowOffset:
    let outValue = scale1Val * scale2Hi / scale1Hi
    let remainder = scale1Val * scale2Hi // scale1Hi ; get remainder
    let halfScale = scale1Hi / 2
    if remainder > halfScale then
        let outValue = outValue + 1
    endif
    return
 

hippy

Technical Support
Staff member
(IMHO, it will be very difficult (but nothing is really difficult for Mr Hippy...) to write an universal map macro and/or subroutine.
You are right; it is difficult to come up with a single universal routine which can deal with an arbitrary mix of bytes and words for input or output without causing jumps in value, loss of resolution, or not giving full mapping at the limits.

I don't think any Map code for other microcontrollers guarantees to achieve it perfectly.

It all depends upon what value ranges one is inputting and outputting. While one can optimise particular cases it doesn't work so well for the general case. There probably is a general case solution but that's probably going to be far more complicated and involved than it needs to be for most specific cases.

To map from 0..1023 to 1..144 is -

output = input * 143 / 1023 + 1

I don't seen any greatest common denominator solution to reduce 143/1023 down to anything which avoids overflow and keeps accurate resolution. These are close -

Code:
output = input * 64 / 462 + 1   ; 1..142

output = input ** 9160 + 1      ; 1..143
 

stan74

Senior Member
You could convert this-
function scale ( in l_map as word, in l_fromLow as integer, in l_fromHigh as integer, in l_toLow as integer, in l_toHigh as integer) as integer
dim l_syscalc as integer
dim l_syscalcF as long
l_syscalcf = 0
repeat (l_toHigh - l_toLow)
l_syscalcf = l_syscalcf + ( l_map - l_fromLow )
end Repeat
l_syscalc = ( l_fromHigh - l_fromLow )
scale = (l_syscalcf / l_syscalc) + l_toLow
end function
 

techElder

Well-known member
output = input * 143 / 1023 + 1
I know its your day off, hippy, so cutting you some slack! :D

Input can be 1023, so "input * 143" = 146,289. :D

You solved that above by dividing by 3 which is your SECOND SOLUTION above and part of my proof-of-concept example.

Like I wrote earlier, there is only one LED different between the following:

FIRST SOLUTION: LEDs = pot ** 9160 + 1

SECOND SOLUTION: LEDs = pot * 47 / 341 + 1
 

AllyCat

Senior Member
Hi,

It's debateable whether the divisor should be 1023 or 1024, because the Microchip data sheet shows a step of 1.5 LSBs after the $3FF level (Figure 16.5 in my 08M2 base data sheet). But it probably doesn't matter and you could use whichever number is more convenient (probably 1024 for a divisor).

Converting Whatever to Whatever... (unitsA -> unitsB, volts -> bit values, apples -> oranges). If someone would like to expand to convert larger numbers, that would be useful.
To continue with the aim for a "general purpose" solution: Personally I find it annoying to have to download a file to run in the PE simulator, only to find that it has syntax errors or have other issues. :(

So here is Jeremy's program module (linked in #5) posted in-line. Unfortunately it did throw a few syntax errors so I replaced the undefined XFER_Wx symbols with S_Wx and inserted labels for the two undefined subroutines (which may be quite easy to create with an X2 and PE6). Sadly, I haven't found the other modules to which he refers, in the forum, but the listing below does compile to about 200 bytes of program code.

Code:
#rem
#############################################################################
#                                                                           #
#   MODULE TITLE       :WordAWordBDivWordC                                  #
#                                                                           #
#   Module Tag         :                                                    #
#   Code Version       :1C                                                  #
#   Date               :July 2007                                           #
#   PICAXE Type        :28X1 (although could be modified for others)        #
#   Firmware           :Unlikely to matter                                  #
#   Editor Software    :5.1.5                                               #
#   Refers to Modules  :None                                                #
#   Author             :Jeremy Leach                                        #
#                                                                           #
#############################################################################

MODULE DESCRIPTION:
===================
This module allows the exact calculation of (WordA * WordB) / WordC without overflow, give a whole and remainder
'result.
	
NOTE: THIS ROUTINE ONLY WORKS IF THE WHOLE PART OF THE RESULT IS A SINGLE WORD VALUE.

WordAWordBDivWordC = (WordA * WordB) / WordC 

= [(MSW * 65536) + LSW]/WordC   
where MSW and LSW are the most and least significant works of the calculation of WordA * WordB.

= [(MSW * 65535) + MSW + LSW]/WordC

= [(65535/WordC) * MSW] + (MSW/WordC) + (LSW/WordC)

If we define P and Q to be the whole and remainder parts of the division 65535/WordC, then

= [(P + (Q/WordC)) * MSW] + (MSW/WordC) + (LSW/WordC)

= (P * MSW) + [(Q * MSW)/WordC] + (MSW/WordC) + (LSW/WordC)  

= (P * MSW) + [(MSW * (Q+1))/WordC] + (LSW/WordC)

= TermA     + TermB                 + TermC

Because the result is a single Word value, then none of these terms will be greater than a Word.
TermA is simple to calculate without overflow.
TermC can again be simply calculated, and split into a whole and remainder part.
TermB is in the form (WordA * WordB) / WordC, and so the values can be put back into another
iteration.

The code works by accumulating whole and remainder values through the iterations. It actually
only takes between 1 to 3 iterations to complete, for any set of WordA,WordB,WordC. 

#endrem

'############################################################################
'#    LOCAL XFER AND STORAGE NAMES                                          #
'############################################################################

Symbol XFER_WordA 		= s_W1  ;		Was XFER_W0, etc.
Symbol XFER_WordB		= s_w2
Symbol XFER_WordC 		= s_W3

Symbol XFER_ResWholeW 		= s_W4
Symbol XFER_ResRemainderW 	= s_W5
  
'############################################################################
'#    LOCAL CONSTANTS & VARIABLES                                           #
'############################################################################
 
'LOCAL CONSTANTS:
'================

'LOCAL VARIABLES:
'================
'Word0 (b0 and b1)
Symbol WordA			= w0
Symbol LessThanWordC		= w0
Symbol ResWholeW			= w0
'Word2 (b4 and b5)
Symbol WordB			= w2
Symbol LSW				= w2
'Word4 (b8 and b9)
Symbol WordC			= w4
'Word6 (b12 and b13)
Symbol WholeW			= w6
'Word8 (b16 and b17)
Symbol RemainderW			= w8
'Word10 (b20 and b21)
Symbol MSW				= w10
'Word12 (b24 and b25)
Symbol ResRemainderW		= w12

'############################################################################
'#    SUBS CALLED BY CODE EXTERNAL TO THIS MODULE                           #
'############################################################################

WordAWordBDivWordC:
	'ON ENTRY: 	XFER_WordA holds WordA
	'		XFER_WordB holds WordB
	'		XFER_WordC holds WordC
	'ON EXIT: 	XFER_ResWholeW holds the Whole part of the result.
	'		XFER_ResRemainderW holds the remainder of the result.
 	
 	Gosub PushVariables
	Peek XFER_WordA,Word WordA,Word WordB,Word WordC

	'Set result to 0
	Poke XFER_ResWholeW,0,0,0,0

	Do 
		'Calculate the MSW and LSW of WordA * WordB
		MSW = WordA ** WordB
		LSW = WordA * WordB
		
		'Add TermA to result.
		WholeW = -1 / WordC * MSW '65535 / WordC * MSW, but takes less code space.
		RemainderW = 0
		Gosub AddWRToResult

		'Add TermC to result
		WholeW = LSW/WordC
		RemainderW = LSW // WordC
		Gosub AddWRToResult

		'Load WordA and WordB
		WordA = - 1 // WordC + 1 '(65535 // WordC) + 1, but takes less code space.
		WordB = MSW
	
		'Loop until WordB = 0, when the next iteration would give Whole and Remainder of 0.
	Loop Until WordB = 0
	
	'The result is now complete.

	Gosub PopVariables
Return

'############################################################################
'#    SUBS CALLED BY CODE INTERNAL TO THIS MODULE                           #
'############################################################################

AddWRToResult:
	'Adds Whole and Remainder values to the Result.
	
	'ON ENTRY:	WholeW holds the Whole value to add.
	'		RemainderW holds the Remainder value to add.
	
	'ON EXIT:	The Result stored in XFER_ResWholeW and XFER_ResRemainderW is updated. 		

	'Get the Result remainder value
	Peek XFER_ResRemainderW,Word ResRemainderW
	
	'Calculate how far the ResRemainderW is less than WordC.
	LessThanWordC = WordC - ResRemainderW
	
	ResRemainderW = ResRemainderW + RemainderW
	
	'If the sum of the remainders is >= WordC then increment ResWholeW and calculate the 
	'correct new remainder.
	If RemainderW >= LessThanWordC Then
		ResRemainderW = ResRemainderW - WordC 'Note:Overflow doesn't stop the result 
						  		  'of this calculation being correct. 
		Inc WholeW
	EndIf

	'Add the whole values.
	Peek XFER_ResWholeW,Word ResWholeW
	ResWholeW = ResWholeW + WholeW
	
	'Save the new result totals.
	Poke XFER_ResWholeW,Word ResWholeW,Word ResRemainderW
Return

PushVariables:		; Not documented in the file
return

PopVariables:		; Not documented in the file

return
But, if / when I need such a function, I will probably still use one of the "double-word" division subroutines that I've previously posted. They might not be as elegant or fast as his, but do have a smaller "footprint" for the variables and program space. Basically, the Numerator High Word is calculated by wordA ** wordB , the Low Word by wordA * wordB and the Divisor is simply wordC. My smaller routine needs only 3.5 Words of RAM and around 50 bytes of program space, with the same restriction as Jeremy's that the result must fit into a single word. But a further restriction of a maximum 31 bit numerator (because the MS bit is used as a Carry flag).

The full double word routine still uses only 4.5 words of RAM and less than 100 program bytes, but can use a full 32-bit numerator and produce a double-word result (with a single-word remainder).

Cheers, Alan.
 

mikeyBoo

Senior Member
Hi,
To continue with the aim for a "general purpose" solution: Personally I find it annoying to have to download a file to run in the PE simulator, only to find that it has syntax errors or have other issues.
Cheers, Alan.
hi Alan,
Sorry 'bout the confusion. The code I posted was for 2 alternate methods. I've tried both in the simulator with no problems (restricted to the 65535 value limit of the Picaxe). Only 1 of the 2 procs may be used at a time.

Simple example for degC -> degF temperature conversion, offset scales allowed (tested in simulator):
Code:
; linearConversion Example.bas
; in simulator OPEN Code Explorer window, answer is in variable outValue
; USED WITH linearConversion proc shown below
; Following Always Need to be Reserved for Doing Scale Conversions :_
symbol scale1Lo    = w6   ; place to put "from" scale bottom
symbol scale1Hi    = w7   ; place to put "from" scale top
symbol scale2Lo    = w8   ; place to put "to" scale bottom
symbol scale2Hi    = w9   ; place to put "to" scale top
symbol span1       = w10  ; place to put "from" scale span
symbol span2       = w11  ; place to put "to" scale span
symbol scale1Val   = w12  ; place to put input value (value to be converted)
symbol outValue    = w13  ; place to put output value (result of conversion)
symbol outValueLo  = b26  ; lo-byte of output value (result of conversion)
symbol outValueHi  = b27  ; hi-byte of output value (result of conversion)

; Simple Temperature Scales Conversion
let scale1Lo = 0 : let scale1Hi = 100   ; degC
let scale2Lo = 32 : let scale2Hi = 212  ; degF
let scale1Val = 75 ; value to convert from degC -> degF
gosub linearConversion
end

; linearConversion --  (v1.00a by M. Ballew 02-01-2015)
;       convert value between linear scales
;       be aware that Picaxe can only deal with numbers 0...65535, so if the proc gets an
;       answer > 65535, it will be incorrect
;       i.e. ((scale1Val - scale1Lo) * span2) Must be < 65536
;       to verify you're not going over 65535, need to know:
;          maxInputValue (which should be = scale1Hi)
;               scale1Lo (usually 0, but may be offset)
;                  span2 (scale2Hi - scale2Lo)
;         e.g. to display battery voltage range 0..15.0vdc (1 decimal place)
;              scale1Hi (our max input value) = 255, span2Value = 150, scale1Lo = 0
;              to test:  (255 - 0) * 150 = 38250  (good, well under 65536)
;
; Status: (works ok)
;         Don't like that this proc uses so many byte/word registers.
;         Consider using RAM (28...511) registers for plugging in conversion scales
;         this would cause a loss of speed, but would not tie up so many word regs
;
; Revisions:
;       none
;
; Arguments:
;        scale1Lo  "from" scale bottom
;        scale1Hi  "from" scale top
;        scale2Lo    "to" scale bottom
;        scale2Hi    "to" scale top
;       scale1Val  "from" scale value to be converted
;
; Results:
;       outValue  contains scale2 equivalent of scale1Val
;       w4...w13  altered
;
; Example:
;       let scale1Lo = 0 : let scale1Hi = 255 : let scale2Lo = 0 : let scale2Hi = 5000 ; plug in scales
;       let scale1Val = 112 ; value to convert
;       gosub linearConversion
;
linearConversion:
    let span1 = scale1Hi - scale1Lo
    let span2 = scale2Hi - scale2Lo
    let outValue = scale1Val - scale1Lo * span2 / span1 + scale2Lo
    ; round off remainder
    let w5 = scale1Val * span2 // span1 ; get remainder
    let w4 = span1 / 2
    if w5 > w4 then
        let outValue = outValue + 1
    endif
    return
Simple example for reading battery voltage: (tested in simulator):
Code:
; linearConversionNoLowOffset Example.bas
; in simulator OPEN Code Explorer window, answer is in variable outValue
; Following Need to be Reserved for Doing Simplified Scale Conversions :_
; following are used in linearConversionNoLowOffset proc
; Note that some word registers serve double-duty in conversion proc
symbol scale1Hi    = w10  ; place to put "from" scale top
symbol halfScale   = w10  ; used for testing remainder
symbol scale2Hi    = w11  ; place to put "to" scale top
symbol remainder   = w11  ; remainder of scale conversion calc
symbol scale1Val   = w12  ; place to put input value (value to be converted)
symbol outValue    = w13  ; place to put output value (result of conversion)
symbol outValueLo  = b26  ; lo-byte of output value (result of conversion)
symbol outValueHi  = b27  ; hi-byte of output value (result of conversion)

; bottom of both scales assumed to be 0
let scale1Hi = 255 ; a binary value (0...255) from an analog input (0...+15vdc)
let scale2Hi = 150 ; actual battery voltage value (1 decimal place, 150 = 15.0vdc)
let scale1Val = 254
gosub linearConversionNoLowOffset
end

; linearConversionNoLowOffset --  (v1.00a by M. Ballew 02-21-2015)
;       TAKE NOTE: this is a simplified version of the linearConversion procedure
;                  THIS PROC ASSUMES THAT THE SCALES BOTH HAVE A BOTTOM VALUE = 0
;       The ONLY reason for using this proc over linearConversion is to save Picaxe program memory
;       be aware that Picaxe can only deal with numbers 0...65535, so if the proc gets an
;       answer > 65535, it will be incorrect
;       i.e. (scale1Val * scale2Hi) Must be < 65536
;       to verify you're not going over 65535, need to know:
;          maxInputValue (which should be = scale1Hi)
;               scale2Hi
;         e.g. to display battery voltage range 0..15.0vdc (1 decimal place)
;              scale1Hi (our max input value) = 255, scale2Hi = 150
;              to test:  255 * 150 = 38250  (good, well under 65536)
;
; Status: (works ok)
;
; Revisions:
;       none
;
; Arguments:
;        scale1Hi  "from" scale top
;        scale2Hi    "to" scale top
;       scale1Val  "from" scale value to be converted
;
; Results:
;       outValue  contains scale2 equivalent of scale1Val
;
; Example:
;       let scale1Hi = 255 : let scale2Hi = 150 : let scale1Val = 112 ; plug in scales & value to convert
;       gosub linearConversionNoLowOffset ; outValue <- convert scale1Val (based on scale1Hi & scale2Hi)
linearConversionNoLowOffset:
    let outValue = scale1Val * scale2Hi / scale1Hi
    let remainder = scale1Val * scale2Hi // scale1Hi ; get remainder
    let halfScale = scale1Hi / 2
    if remainder > halfScale then
        let outValue = outValue + 1
    endif
    return
 

BESQUEUT

Senior Member
It's debateable whether the divisor should be 1023 or 1024, because the Microchip data sheet shows a step of 1.5 LSBs after the $3FF level (Figure 16.5 in my 08M2 base data sheet). But it probably doesn't matter and you could use whichever number is more convenient (probably 1024 for a divisor).
IMHO, this is absolutely not debateable : there are exactly 1024 steps numbered from 0 to 1023.

If vref- is 0V and Vref + is 5V :
anything from -0.002 441 V to +0.002 440 V gives ADC10=0
anything from +0.002 441 V to +0.007 323 V gives ADC10=1
anything from +0.007 324 V to +0.012 207 V gives ADC10=2

...
anything from +4,987 793 V to 4,992 674 V gives ADC10=1022
anything from +4,992 675 V to 4,997 558 V gives ADC10=1023

The 4,997 559 V to 5,002 441 V slice should gives ADC10 =1024, but it is not possible !

So to have 5V in the target, Microship says that the last slice is 1,5 LSB...

Actually, anything greater than 4,997 558 V is 1023...
So 5V and more gives 1023...
 
Last edited:

hippy

Technical Support
Staff member
I know its your day off, hippy, so cutting you some slack! :D

Input can be 1023, so "input * 143" = 146,289. :D

You solved that above by dividing by 3 which is your SECOND SOLUTION above and part of my proof-of-concept example.
I don't consider that "solved" because 143/3 is not 47. Close to 47 but not actually 47.

The issue does come down to what one considers to be "solved". If having fewer LED's than 144 on when the input is 1023 is acceptable then it has been solved. If one wants all 144 LED's on when the input is 1023 then none of the simple divide or multiply tricks achieve that.

One can get an accurate result, all 144 LEDs on for input 1023 by using 18-bit arithmetic, repeatedly subtracting 1023, and I would presume an 18-bit divided by 10-bit routine would work.
 

hippy

Technical Support
Staff member
It's debateable whether the divisor should be 1023 or 1024, because the Microchip data sheet shows a step of 1.5 LSBs after the $3FF level (Figure 16.5 in my 08M2 base data sheet).
I would describe that as 1.5 LSBs at the top end giving $3FF (1023). That's what my 12F1840 (08M2) datasheet shows but the 18F25K22 (28X2) shows the top 0.5 LSB giving $3FF (1023).

Whether one needs a 1024, 1023 or something else for the division to convert an ADC reading into a input value depends on what one wants to see as an input value.

Doing it properly, taking into account any half LSBs, a $3FF reading should be shown as representing "An input value greater or equal to 4.995V" or something like that.

But, while that is correct when a 5V signal is applied, it's not what people expect or want to see; they want to see "5.000V".

That's okay for a 28X2 because "greater or equal to 4.995V" is the same as "5.000V +/- 0.005V" or whatever the actual value is.

For the 08M2 it may be more complicated if we assume the figure in the datasheet is correct.

It is all very complicated because a single ADC reading represents a range of input values. How we consider a single ADC reading value depends on what we want to achieve and how we wish to convert it back to a range, real or notional, accurately or not.

Division by 1023 allows an ADC reading to be converted from a zero to full reading. That's different to what input voltage ranges produce zero to full and values in between.
 

BESQUEUT

Senior Member
But, while that is correct when a 5V signal is applied, it's not what people expect or want to see; they want to see "5.000V".
If they want to see 5V for 1023, they can scale to 5,005V, but there are still 1024 steps numbered from 0 to 1023...
Step 1023 will cover 4.997 6 V to 5.002 5 V
and round to nearest integer, (add 1/2 before last divide)

Or scale to 5.010 V :
Step 1023 will cover 5.002 6 V to 5.007 5 V
and round to integer.

Going back to the general challenge, I think that any formula able to give 1024 differents results, linear with input is OK.

For #1 challenge :
Code:
output = input * 64 / 462 + 1   ; 1..142
output = input * 64 / 457 + 1 ; 1..144
 
Last edited:

techElder

Well-known member
There are some differences at the top end of the ADC output.

Code:
goto second

w0 = 1023 ** 9160 + 1   ' result = 143 ; first solution
w1 = 1023 * 64/457 + 1  ' result = 144 ; BESQUEUT solution
w2 = 511 ** 9160 + 1    ' result = 72 
w3 = 511 * 64/457 + 1   ' result = 72 ; BESQUEUT
w4 = 255 ** 9160 + 1    ' result = 36 
w5 = 255 * 64/457 + 1   ' result = 36 ; BESQUEUT
w6 = 127 ** 9160 + 1    ' result = 18 
w7 = 127 * 64/457 + 1   ' result = 18 ; BESQUEUT

end

second:
' LEDs = pot * 47 / 341 + 1 ; SECOND SOLUTION
w0 = 1023 * 47 / 341 + 1' result = 142 ; second solution
w1 = 1023 * 64/457 + 1  ' result = 144 ; BESQUEUT solution
w2 = 511 * 47 / 341 + 1 ' result = 71 
w3 = 511 * 64/457 + 1   ' result = 72 ; BESQUEUT
w4 = 255 * 47 / 341 + 1 ' result = 36 
w5 = 255 * 64/457 + 1   ' result = 36 ; BESQUEUT
w6 = 127 * 47 / 341 + 1 ' result = 18 
w7 = 127 * 64/457 + 1   ' result = 18 ; BESQUEUT

end
 

hippy

Technical Support
Staff member
output = input * 64 / 457 + 1 ; 1..144
Agreed; that works.

Eight input values (0-7) give an output result of 1, but only two input values (1022-1023) give an output of 144. A better solution would have roughly the same number of input values for every particular output value.

There should be mostly seven input values per output value. And with that in mind ...

output = input * 64 / 455 + 1 ; 1..144
 
Last edited:

techElder

Well-known member
Now, how does that third solution with an input range of 0 - 511 (0v to 2.5v)? Some projects involve half of the supply voltage or it could be a more sensitive range by adding granularity to the input.

My initial try would be to halve the division: output = input * 64 / 228 + 1
That doesn't quite work the way I was thinking it should.

Code:
fourth:
' LEDs = pot * 64 / 228 + 1 ; FOURTH SOLUTION
w0 = 511 * 64 / 228 + 1 ' result = 144 ; fourth solution
w1 = 511 * 64/457 + 1   ' result = 72 ; BESQUEUT solution
w2 = 255 * 64 / 228 + 1 ' result = 72 
w3 = 255 * 64/457 + 1   ' result = 36 ; BESQUEUT
w4 = 127 * 64 / 228 + 1 ' result = 36 
w5 = 127 * 64/457 + 1   ' result = 18 ; BESQUEUT
w6 = 63 * 64 / 228 + 1  ' result = 18 
w7 = 63 * 64/457 + 1    ' result = 9 ; BESQUEUT


PS. :D Y'all are trying to ditch this challenge as fast as you can, and I keep adding parameters! :D
 

BESQUEUT

Senior Member
My initial try would be to halve the division: output = input * 64 / 228 + 1
That doesn't quite work the way I was thinking it should.
output = input * 128 / 455 + 1

For Hippy #18 criteria :
- 3 values for LED 144
- 4 values for LED 143
- 3 values for LED 142
etc ...

NB1 : 1024/144=7.1 => 7 values for each LED, and sometimes 8...
NB2 : 512/144=3.5 => 3 to 4 values for each LED...
NB3 : not tested with PE6; quicker to use Excel :
=ENT($A4*128/455)+1


For the general Challenge :
From Excel...
Code:
out_max	out_max	out_max	         Num	Denum     Num        Num	                         Denum
       /1024        /1024                        /Denum
                    fraction

1000 	0,977	   125/128	 125	128	0,977	 5 *  5 *  5        	         2 *  2 *  2 *  2 *  2 *  2 *  2
2000 	1,953	1   61/64 	 125	64	1,953	 5 *  5 *  5	                 2 *  2 *  2 *  2 *  2 *  2
3000 	2,930	2 119/128	 375	128	2,930	 3 *  5 *  5 *  5	         2 *  2 *  2 *  2 *  2 *  2 *  2
4000 	3,906	3   29/32 	 125	32	3,906	 5 *  5 *  5	                 2 *  2 *  2 *  2 *  2
5000 	4,883	4 113/128	 625	128	4,883	 5 *  5 *  5 *  5	                 2 *  2 *  2 *  2 *  2 *  2 *  2
6000 	5,859	5   55/64  	 375	64	5,859	 3 *  5 *  5 *  5	                 2 *  2 *  2 *  2 *  2 *  2
7000 	6,836	6 107/128	 875	128	6,836	 5 *  5 *  5 *  7	                 2 *  2 *  2 *  2 *  2 *  2 *  2
8000 	7,813	7  13/16 	 125	16	7,813	 5 *  5 *  5	                 2 *  2 *  2 *  2
9000 	8,789	8 101/128	1125	128	8,789	 3 *  3 *  5 *  5 *  5	         2 *  2 *  2 *  2 *  2 *  2 *  2
10000	9,766	9  49/64 	 625	64	9,766	 5 *  5 *  5 *  5	                 2 *  2 *  2 *  2 *  2 *  2
15000	14,648	14  83/128	1875	128	14,648	 3 *  5 *  5 *  5 *  5	                        2 *  2 *  2 *  2 *  2 *  2 *  2
20000	19,531	19  17/32 	 625	32	19,531	 5 *  5 *  5 *  5	                               2 *  2 *  2 *  2 *  2
25000	24,414	24  53/128	3125	128	24,414	 5 *  5 *  5 *  5 *  5	               2 *  2 *  2 *  2 *  2 *  2 *  2
30000	29,297	29  19/64 	1875	64	29,297	 3 *  5 *  5 *  5 *  5	                       2 *  2 *  2 *  2 *  2 *  2
35000	34,180	34  23/128	4375	128	34,180	 5 *  5 *  5 *  5 *  7	               2 *  2 *  2 *  2 *  2 *  2 *  2
40000	39,063	39   1/16 	625	16	39,063	 5 *  5 *  5 *  5	                 2 *  2 *  2 *  2
45000	43,945	43 121/128	5625	128	43,945	 3 *  3 *  5 *  5 *  5 *  5	       2 *  2 *  2 *  2 *  2 *  2 *  2
50000	48,828	48  53/64 	3125	64	48,828	 5 *  5 *  5 *  5 *  5	               2 *  2 *  2 *  2 *  2 *  2
55000	53,711	53  91/128	6875	128	53,711	 5 *  5 *  5 *  5 *  11	               2 *  2 *  2 *  2 *  2 *  2 *  2
60000	58,594	58  19/32 	1875	32	58,594	 3 *  5 *  5 *  5 *  5	               2 *  2 *  2 *  2 *  2
65000	63,477	63  61/128	8125	128	63,477	 5 *  5 *  5 *  5 *  13	               2 *  2 *  2 *  2 *  2 *  2 *  2
 
Last edited:

hippy

Technical Support
Staff member
My initial try would be to halve the division: output = input * 64 / 228 + 1
That doesn't quite work the way I was thinking it should.
That is because half of 455 is not 288. There is no integer value which is half of 455 but you can double the 64 multiplier to 128 as BESQUEUT has done and achieve the same result ...

output = input * multiplier / (divisor/2)

is the same as

output = input * (multiplier*2) / divisor
 

techElder

Well-known member
Thanks, and that makes more sense.

In the actual code connected to hardware, I doubled the ADC value for the sensor that has a 0 to 2.5 volt range and limited the result with MAX. Somewhere in the future I might add some 2x amplification, but I'm working on reducing a high noise level at the base for now.

All these numbers are fine and appreciated, but in the end the hardware always balks at being manipulated! :D
 

AllyCat

Senior Member
Hi,

there are exactly 1024 steps numbered from 0 to 1023.
In my terminology there are 1024 "steps" (sometimes called "risers") but 1025 levels. The 1025 level is the "Reference voltage" but cannot be reported by the ADC (within 10 bits). Note the PIC{axe} DAC can use the "extra" level, i.e. all levels from 0 to 32 (but it probably needs a POKESFR command).

So, if you were designing a precision voltmeter, then the reference voltage should be divided by 1024 to determine the step size. However, for the application in this thread, it appears that the desire is to report 1023 as "full scale", so 1023 should be the number of "steps". Or maybe 1022 if you want one LED lit when there is a zero level (as the "+1" appears to suggest).

But I'm surprised that nobody has mentioned the ** operator. I would just push the ADC value up to "full scale" by multiplying by 64 (or as required) and then ** 455 (or up to ** 458 if one LED is always to be illuminated). Basically just find the fractional step you want by using a pocket calculator and then multiply its value by 65536.

Cheers, Alan.
 

hippy

Technical Support
Staff member
Note the PIC{axe} DAC can use the "extra" level, i.e. all levels from 0 to 32 (but it probably needs a POKESFR command).
The DACCON1 register uses only 5 bits to set the level, so 32 levels, 0 to 31, and the datasheet (08M2) describes it as a "32-to-1 mux". It may however be possible to generate additional levels by disabling the DAC and setting the pin as output high or low - Have never tried nor tested that.
 

AllyCat

Senior Member
Hi,

It's possible to put the DAC into "Low Power" mode by disconnecting either end of the resistive divider chain (at least with M2s, figure 17-3). Disconnect the lower end and the output voltage must float up to the Reference voltage (level 32/32), which might be Vdd, or one of the FVRs, or externally applied, as desired. IIRC the setting of the flags is not entirely obvious from the data sheet, but it does work, I think with DACLPS = 1 and DACEN = 0. ;)

Cheers, Alan.
 

techElder

Well-known member
... But I'm surprised that nobody has mentioned the ** operator. I would just push the ADC value up to "full scale" by multiplying by 64 (or as required) and then ** 455 (or up to ** 458 if one LED is always to be illuminated). Basically just find the fractional step you want by using a pocket calculator and then multiply its value by 65536.
Hippy's first solution, above, did use the ** operator. That solution did work in this application, but later solutions worked better.

Code:
FIRST SOLUTION: LEDs = pot ** 9160 + 1
Hmmmmm, got to put what you said into code and see how that works.
 

techElder

Well-known member
... But I'm surprised that nobody has mentioned the ** operator. I would just push the ADC value up to "full scale" by multiplying by 64 (or as required) and then ** 455 (or up to ** 458 if one LED is always to be illuminated). Basically just find the fractional step you want by using a pocket calculator and then multiply its value by 65536.
So, I pulled out the technician bag-o-tricks and created some DO/LOOP FOR/NEXT code to run some of the numbers in the ranges and got this optimized result.

Code:
   ' optimizing an ADC output of 0 - 1023 to display on a string of 144 LEDs

   output = input * 20 ** 460 + 1 ' PICAXE math
The "455" derives from "65536 / 144".

The "20" derives from "1023 ** 455" being equal to 7 LEDs. So, what number times 1023 will make 1023 * some number ** 455 = 144? Some number turns out to be "20".

I adjusted "455" to "460" to get a more linear range, but lost a little bit on the low end. Compromise.

As it turns out, the steps at LED intervals are as follows (based on the simulator in PE6):
Code:
input = 29 to 31       output = 5
input = 57 to 64       output = 9
input = 122 to 128     output = 18
input = 506 to 512     output = 72
input = 1019 to 1025   output = 144
PS. Of course, credit goes to the great additions of those posters above (except booboo) that allows this implementation for my application. Thanks! :D
 

AllyCat

Senior Member
Hi,

Another refinement might be to replace the "+1" at the end with a "+ ZERO_SITUP" constant before the **. That should give the ability to adjust the range for the first LED being on.

My gut feeling is that to give the "smoothest" result, the multiplier before the ** should be made (almost) as large as possible (without causing an overflow), e.g. *64. But I've not tested any figures and sometimes intuition doesn't give the "expected" results, particularly with PICaxe maths. ;)

Cheers, Alan.
 

techElder

Well-known member
... with a "+ ZERO_SITUP" constant before the **.

... the multiplier before the ** should be made (almost) as large as possible (without causing an overflow), e.g. *64.
Sorry, Alan, you'll have to be more succinct for these two items.

I've considered the "* 64", but never could relate that to a ratio of 144 LEDs.
 

marks

Senior Member
Hi Texasclodhopper,
if having trouble with noise you could also try adding in some averaging
Code:
#picaxe 20M2 
 #no_data
 #terminal 38400
 SETFREQ M32
	
   Main: W1=0
      FOR B5 = 1 TO 5
         ReadADC10 b.0, W0
	   W1=W1+W0
	NEXT B5
	   W1=W1**1845+1
	Sertxd("ValueADC = ",#W1,cr,lf) ;steps 1 to 144
      
   pause 1000
    GOTO Main
 

AllyCat

Senior Member
Hi,

The 64 relates to the maximum value received from the ADC (e.g. 1023) to just fit the intermediate result in below 65536. Then the value after the ** would be approximately 65535 / 144 (or 143 or 142 depending on the desired "size" of the first and last segments) which I calculate is about 455.

Adding a ZERO_SITUP constant of between 1 and about 450 before the ** should make the second LED come on at a lower level than would otherwise happen. Perhaps balance that against any excess or deficiency for the last LED.

Cheers, Alan.
 

techElder

Well-known member
... The 64 relates to the maximum value received from the ADC (e.g. 1023) to just fit the intermediate result in below 65536. Then the value after the ** would be approximately 65535 / 144 (or 143 or 142 depending on the desired "size" of the first and last segments) which I calculate is about 455.
The way I read your text is as follows for the maximum from the ADC (1023):
Code:
output = 1023 * 64 ** 455 + 1 = [B]455[/B] ; because [B]1023 * 64 is just below 65,536[/B].
So, I didn't understand the results of your comment in the equation, but tell me where I've misread it, Alan. :D
 

AllyCat

Senior Member
Hi,

...sometimes intuition doesn't give the "expected" results, particularly with PICaxe maths. ;)
Sorry, yes you're looking for a maximum value of 143 so it would need around ** 143 . That might be getting rather low (for good resolution from integer maths) so maybe *32 and **285 (or perhaps your original *20 and **460) would give a better result. :eek:

Cheers, Alan.
 

BESQUEUT

Senior Member
Here's a challenge. Haven't seen a PICAXE routine that will do what the 'C' Map() function will do. That would be very handy converting ADC values 0-1023 to LED string values 1-144. I'm trying to understand what the constraints would be.
This certainly can be made simpler, but that works at least for tests values...
Code:
[color=Green]' Enter your values here :[/color]
[color=Blue]symbol in_max[/color][color=DarkCyan]=[/color][color=Navy]1023[/color]
[color=Green]'symbol out_max=144
'symbol out_min=1[/color]

[color=Blue]symbol out_max[/color][color=DarkCyan]=[/color][color=Navy]5000[/color]
[color=Blue]symbol out_min[/color][color=DarkCyan]=[/color][color=Navy]0[/color]

[color=Green]'symbol out_max=7000
'symbol out_min=1


' Do not change this : (note that precompiler calculations use zero octet program memory...)[/color]

[color=Blue]symbol out_mx1[/color][color=DarkCyan]=[/color][color=Blue]out_max[/color][color=DarkCyan]/[/color][color=Blue]in_max
symbol out_mx2[/color][color=DarkCyan]=[/color][color=Blue]out_mx1[/color][color=DarkCyan]+[/color][color=Navy]1[/color]
[color=Blue]symbol out_mx3[/color][color=DarkCyan]=[/color][color=Blue]out_mx2[/color][color=DarkCyan]-[/color][color=Blue]out_min
symbol out_mx[/color][color=DarkCyan]=[/color][color=Blue]out_max[/color][color=DarkCyan]+[/color][color=Blue]out_mx3
symbol K[/color][color=DarkCyan]=[/color][color=Navy]65536[/color][color=DarkCyan]/[/color][color=Blue]in_max[/color]
[color=Navy]#macro [/color][color=Black]Map[/color][color=Blue]([/color][color=Black]in,out[/color][color=Blue])
   [/color][color=Black]out[/color][color=DarkCyan]=[/color][color=Black]in[/color][color=DarkCyan]*[/color][color=Blue]K [/color][color=DarkCyan]** [/color][color=Blue]out_mx [/color][color=DarkCyan]+ [/color][color=Blue]out_min[/color]
[color=Navy]#endmacro[/color]


[color=Green]' Your program :[/color]
[color=Blue]symbol [/color][color=Purple]i[/color][color=DarkCyan]=[/color][color=Purple]w1[/color]

[color=Blue]for [/color][color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy]0 [/color][color=Blue]to [/color][color=Navy]10
      [/color][color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
      sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy]13[/color][color=Black],[/color][color=Navy]10[/color][color=Blue])
next [/color][color=Purple]i[/color]

[color=Blue]for [/color][color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy]1000 [/color][color=Blue]to [/color][color=Navy]1023
      [/color][color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
      sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy]13[/color][color=Black],[/color][color=Navy]10[/color][color=Blue])
next [/color][color=Purple]i[/color]
 
Last edited:

techElder

Well-known member
Map Macro Definition

Well... lot of work to be done... :(
Works when in_Max=1023, but lots of problems with others values...
In the special case (my app) of in_Max=1023, the following code (modified) from BESQUEUT is technically more accurate at the "bit boundaries" and otherwise has similar output. Looks better as a macro, too! :D

29 => 5
31 => 5
57 => 9
63 => 9
64 => 10
122 => 18
127 => 18
128 => 19
506 => 72
511 => 72
512 => 73
1019 => 144
1023 => 144
1024 => 1
1025 => 1
Code:
[color=Black]testing1:[/color]
[color=Green]' Enter your values here :[/color]
[color=Blue]symbol in_max[/color][color=DarkCyan]=[/color][color=Navy][b]1023[/b][/color]
[color=Blue]symbol out_max[/color][color=DarkCyan]=[/color][color=Navy][b]144[/b][/color]
[color=Blue]symbol out_min[/color][color=DarkCyan]=[/color][color=Navy][b]1[/b][/color]

[color=Green]' Do not change this : (note that precompiler calculations use zero octet program memory...)[/color]

[color=Blue]symbol out_mx1[/color][color=DarkCyan]=[/color][color=Blue]out_max[/color][color=DarkCyan]/[/color][color=Blue]in_max
symbol out_mx2[/color][color=DarkCyan]=[/color][color=Blue]out_mx1[/color][color=DarkCyan]+[/color][color=Navy][b]1[/b][/color]
[color=Blue]symbol out_mx3[/color][color=DarkCyan]=[/color][color=Blue]out_mx2[/color][color=DarkCyan]-[/color][color=Blue]out_min
symbol out_mx[/color][color=DarkCyan]=[/color][color=Blue]out_max[/color][color=DarkCyan]+[/color][color=Blue]out_mx3
symbol K[/color][color=DarkCyan]=[/color][color=Navy][b]65536[/b][/color][color=DarkCyan]/[/color][color=Blue]in_max[/color]

[color=Navy]#macro [/color][color=Black]Map[/color][color=Blue]([/color][color=Black]in,out[/color][color=Blue])
   [/color][color=Black]out[/color][color=DarkCyan]=[/color][color=Black]in[/color][color=DarkCyan]*[/color][color=Blue]K [/color][color=DarkCyan]** [/color][color=Blue]out_mx [/color][color=DarkCyan]+ [/color][color=Blue]out_min[/color]
[color=Navy]#endmacro[/color]


[color=Green]' Your program :[/color]
[color=Blue]symbol [/color][color=Purple]i[/color][color=DarkCyan]=[/color][color=Purple]w1

i[/color][color=DarkCyan]=[/color][color=Navy][b]29[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]31 [/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]57[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]63[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]64[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]122[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]127[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]128[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]506[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]511[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]512[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]1019[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]1023[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]1024[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])[/color]
[color=Purple]i[/color][color=DarkCyan]=[/color][color=Navy][b]1025[/b][/color]
[color=Black]Map[/color][color=Blue]([/color][color=Purple]i[/color][color=Black],[/color][color=Purple]w2[/color][color=Blue])
sertxd([/color][color=Black]#[/color][color=Purple]i[/color][color=Black],[/color][color=Red]" => "[/color][color=Black],#[/color][color=Purple]w2[/color][color=Black],[/color][color=Navy][b]13[/b][/color][color=Black],[/color][color=Navy][b]10[/b][/color][color=Blue])

end[/color]
 

techElder

Well-known member
marks, sorry to take so long to test this out in my application code. However, I did finally get to it, and it works great. (Of course, you already knew that! :D)

I did have to double my ADC reading, because the sensor I'm testing only goes to 2.5 volts. I doubled the average reading, so that works better, too. Thanks.


Hi Texasclodhopper,
if having trouble with noise you could also try adding in some averaging
Code:
#picaxe 20M2 
 #no_data
 #terminal 38400
 SETFREQ M32
	
   Main: W1=0
      FOR B5 = 1 TO 5
         ReadADC10 b.0, W0
	   W1=W1+W0
	NEXT B5
	   W1=W1**1845+1
	Sertxd("ValueADC = ",#W1,cr,lf) ;steps 1 to 144
      
   pause 1000
    GOTO Main
 
Top