News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Math not working

Started by Fanie, Today at 02:51 PM

Previous topic - Next topic

Fanie

I have a pot 0 - 5V on an A/D input which display correctly 0 to 1023.

What I want to do is make 50% or 512 the zero and adjust up must display 1 to 512, and from the zero adjust down must also indicate 1 to 512.

What am I missing ?

        Vin = ADIn 7
        Vin = 1023 - Vin    ' swap pot direction
                            ' A goto Start2 here indicates correctly 0 to 1023 on the display.
       
        If Vin > 512 Then
           Vin = Vin - 512             ' This works, display 0 to 512
        EndIf
        GoTo Start2        'display the value


        If Vin <= 512 Then
            Vin = 512 - Vin           ' This works faulty, display 512 to 0 and not 0 to 512
        EndIf                         

Start2: display the value


Wimax

How did you define the variables ?

top204

#2
You can scale the ADC value range, into another value range using a scaling procedure.

For example:
'
'  /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\    \/\\\                                                /\\\          /\\\
'  \/\\\\\\\\\\\/        /\\\\\    /\\\\\\\\\\    /\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'    \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\    \/\\\        \/\\\        /\\\\\\\\\\
'      \/\\\    \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\    \/\\\ /\\  /\\\/////\\\
'      \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\  \//\\\\\\\\/\\
'        \///        \///    \/////    \//////////    \//////////      \/////        \/////    \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Use a Scaling procedure to scale an ADC value rangle, into a required value range.
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F25K20                                                  ' Tell the compiler what device to compile for
    Declare Xtal = 16                                                  ' Tell the compiler what frequency the device will be operating at (in MHz)
    Declare Auto_Heap_Arrays = On                                      ' Tell the compiler to create arrays above standard variables, so assembler code is more efficient
    Declare Auto_Variable_Bank_Cross = On                              ' Tell the compiler to create any multi-byte variables in the same RAM bank. For more efficiency
'
' Setup USART1
'
    Declare Hserial_Baud = 9600                                        ' Set the Baud rate to 9600
    Declare HRSOut1_Pin  = PORTC.6                                      ' Set the TX pin
'
' Create Global variables here
'
    Dim wADC_Value    As Word                                          ' Holds the 10-bit ADC value
    Dim wFinal_Value As SWord                                          ' Holds the scaled value
   
'-------------------------------------------------------------------------------------------------------------
' The main program starts here
' A demonstration loop, to simulate a 10-bit ADC value being scaled
'
Main:
    For wADC_Value = 0 To 1024 Step 32                                  ' Create a loop to simulate values from a 10-bit ADC (plus one for the simulation)
        wFinal_Value = wScale(wADC_Value, 0, 1023, -512, 512)          ' Scale the 0 to 1023, to -512 to 512
        wFinal_Value = Abs(wFinal_Value)                                ' Make a negative value, positive
        HRSOut1Ln "ADC = ", Dec4 wADC_Value,                            ' \
                  " : Scaled = ", Dec3 wFinal_Value                    ' / Transmit the original and scaled ADC value to a serial terminal
    Next                                                                ' Close the loop

'-------------------------------------------------------------------------------------------------------------
' Scale a 16-bit signed integer value range to another 16-bit signed integer value range
' Input    : pValueIn holds the value to scale
'          : pInMin is the lower bound of the value's input range
'          : pInMax is the upper bound of the value's input range
'          : pOutMin is the lower bound of the value's target range
'          : pOutMax is the upper bound of the value's target range
' Output    : Returns the scaled result
' Notes    : None
'
Proc wScale(pValueIn As SDword, pInMin As SWord, pInMax As SWord, pOutMin As SWord, pOutMax As SWord), SWord
    If pValueIn > pInMax Then pValueIn = pInMax                        ' Make sure the value in does not exceed the maximum allowed
    Result = (((pValueIn - pInMin) * (pOutMax - pOutMin)) / (pInMax - pInMin)) + pOutMin
EndProc

On the serial terminal, it will show:

ADC = 0000 : Scaled = 512
ADC = 0032 : Scaled = 480
ADC = 0064 : Scaled = 448
ADC = 0096 : Scaled = 416
ADC = 0128 : Scaled = 384
ADC = 0160 : Scaled = 352
ADC = 0192 : Scaled = 320
ADC = 0224 : Scaled = 288
ADC = 0256 : Scaled = 256
ADC = 0288 : Scaled = 224
ADC = 0320 : Scaled = 192
ADC = 0352 : Scaled = 160
ADC = 0384 : Scaled = 128
ADC = 0416 : Scaled = 096
ADC = 0448 : Scaled = 064
ADC = 0480 : Scaled = 032
ADC = 0512 : Scaled = 000
ADC = 0544 : Scaled = 032
ADC = 0576 : Scaled = 064
ADC = 0608 : Scaled = 096
ADC = 0640 : Scaled = 128
ADC = 0672 : Scaled = 160
ADC = 0704 : Scaled = 192
ADC = 0736 : Scaled = 224
ADC = 0768 : Scaled = 256
ADC = 0800 : Scaled = 288
ADC = 0832 : Scaled = 320
ADC = 0864 : Scaled = 352
ADC = 0896 : Scaled = 384
ADC = 0928 : Scaled = 416
ADC = 0960 : Scaled = 448
ADC = 0992 : Scaled = 480
ADC = 1024 : Scaled = 512

Scaling procedures are also in the "Scale.inc" library file, located at: "C:\Users\User Name\PDS\Includes\". But I re-created one of them within the code listing itself, so it could be clearly seen.

If the values in and out are known, and will not change. The generic scaling procedure can be changed to a much more efficient expression. Such as:

Proc ADC_Scale(pValueIn As SDword), SWord
    If pValueIn > 1023 Then pValueIn = 1023                        ' Make sure the value in does not exceed the maximum allowed
    Result = ((pValueIn * 1024) / 1023) + -512
EndProc


Which expects 0 to 1023 in, and gives -512 to 512 out.

Regards
Les

Fanie

Quote from: Wimax on Today at 03:11 PMHow did you define the variables ?

Vin is a DWORD.

Quote from: top204 on Today at 03:19 PMYou can scale the ADC value range, into another value range using a scaling procedure.


Thank you Les, but what is wrong with my simple code ?  I'm trying to figure out if in my thinking is there an oversight or is it worm infested already  :o  ?

RGV250

Hi,
I think you need to multiply by 0.01 to show 5v

Bob

Fanie

#5
If I do this and change Vin's value keeping it below 512

        Vin = 40
        Vin = 512 - Vin

Then it display the output correctly

Pepe

Vin = ADIn 7
        Vin = 1023 - Vin    ' swap pot direction
                            ' A goto Start2 here indicates correctly 0 to 1023 on the display.
       
        If Vin > 512 Then
           Vin = Vin - 512   
       Else
            Vin = 512 - Vin         
        EndIf                         

Start2: display the value

Wimax

Quote from: Fanie on Today at 02:51 PM        Vin = ADIn 7
        Vin = 1023 - Vin    ' swap pot direction
                            ' A goto Start2 here indicates correctly 0 to 1023 on the display.
       
        If Vin > 512 Then
           Vin = Vin - 512             ' This works, display 0 to 512
        EndIf
        GoTo Start2        'display the value


        If Vin <= 512 Then
            Vin = 512 - Vin           ' This works faulty, display 512 to 0 and not 0 to 512
        EndIf                        

Start2: display the value


I think that this line
GoTo Start2        'display the value is temporary as the subsequent code will never be executed, but if it were deleted then the ambiguity would remain if Vin > 512 after the acquisition and swap without an "Else"
 


Fanie

#8
Got it working !  Thank you.
The goto must be inside the If routine before the Endif.

Vin = ADIn 7
        Vin = 1023 - Vin    ' swap pot direction
     
        If Vin > 512 Then
          Vin = Vin - 512            ' This works, display 0 to 512
          GoTo Start2        'display the value
        EndIf
       


        If Vin <= 512 Then
            Vin = 512 - Vin          ' This works faulty, display 512 to 0 and not 0 to 512
            GoTo Start2        'display the value
        EndIf                       

Start2: display the value

RGV250

Ah,
I thought you wanted to show the voltage, not the value.

Bob

top204

#10
A more efficient method of your mechanism would be:

If Vin > 512 Then
  Vin = Vin - 512           
Else
  Vin = 512 - Vin         
EndIf

Because if Vin is not greater that 512, it must be equal to it or lower that it. So no extra comparisons or jumps required.

Also, make sure that Vin is a signed variable. Incase the subtractions cause a negative value. With unsigned integers, even a small negative value is actually greater than 512 in an unsigned comparison. i.e. Two's complement.

Pepe

This is what I wrote in post #7

Fanie

Thank you Les AND Pepe, I will use it because it is a lot neater than mine.