Menu

Map Command

Anobium
2018-02-17
2018-02-28
1 2 > >> (Page 1 of 2)
  • Anobium

    Anobium - 2018-02-17

    There was request a long time ago for a MAP command. Well I needed one - so, here is it.

    See this for the latest!! https://sourceforge.net/p/gcbasic/discussion/629990/thread/d40aceb3/#82d6

    MAP is a function. 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.

    So, example. Read the ADC with a 8bit value (a 0 to 255 range) and you need a to MAP to a 0-270 range, use myNewValue = map ( myADCValue, 0, 255,0,270)

    Include in the release? Let me know.

    ~~~
    '''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.
    '''@param l_map: the number to map
    '''@param l_fromLow: the lower bound of the value’s current range
    '''@param l_fromHigh: the upper bound of the value’s current range
    '''@param l_toLow: the lower bound of the value’s target range
    '''@param l_toHigh: the upper bound of the value’s target range
    function map ( in l_map as word, in l_fromLow as word, in l_fromHigh as word, in l_toLow as word, in l_toHigh as word) as word

    dim l_syscalc as long
    #define _mapFactor 10000
    l_syscalc = ( l_toHigh - l_toLow ) +1
    l_syscalc = [long]l_syscalc * _mapFactor
    l_syscalc = [long]l_syscalc / ( l_fromHigh - l_fromLow )
    l_syscalc = [long]l_syscalc * l_map
    map = (l_syscalc / _mapFactor)

    end function
    ~~~

     

    Last edit: Anobium 2018-02-18
  • Chris Roper

    Chris Roper - 2018-02-17

    I like it.

    Here is an example for the Xpress Evaluation board using the Map Function:

    ''' MAP_Test.xpress.gcb
    '''
    ''' Testing the MAP Function on an Xpress Board
    ''' Use R15 (potentiometer) as a 5 possition Rotary switch and display
    ''' the current state on a VT100 Terminal (TeraTerm) and LED's
    
    #Chip 16F18855, 32
    
    'Generated by PIC PPS Tool for Great Cow Basic
    'PPS Tool version: 0.0.5.11
    'PinManager data: v1.55
    '
    #startup InitPPS, 85
    
    Sub InitPPS
      'Module: EUSART
        RC0PPS = 0x0010    'TX  > RC0
        TXPPS  = 0x0010    'RC0 > TX (bi-directional)
    End Sub
    
    #option explicit
    
    #include  <LCD2SerialRedirect.h>
    #define LCD_IO 0
    #define USART_BAUD_RATE 19200
    
    Dim NewPos, CurPos as Byte
    
    dir PortA out
    
    HSerPrint "Ready"
    
    Do
      NewPos = Map(ReadAD10(AN4), 0, 1024, 0, 4)
      if NewPos <> CurPos  then
        CurPos = NewPos
        PortA  = CurPos + 1
        cls : locate 0,0
        HSerPrint(CurPos)
      end if
      wait 100 ms
    Loop
    
    End
    
    function map ( in l_map as word, in l_fromLow as word, in l_fromHigh as word, in l_toLow as word, in l_toHigh  as word) as word
    
      dim l_syscalc as long
      #define _mapFactor 10000
      l_syscalc = ( l_toHigh - l_toLow ) +1
      l_syscalc = [long]l_syscalc * _mapFactor
      l_syscalc = [long]l_syscalc / ( l_fromHigh - l_fromLow )
      l_syscalc = [long]l_syscalc * l_map
      map = (l_syscalc / _mapFactor)
    
    end function
    

    I vote that it be included in the next release, it will be a valuable function in may different cases.

    Cheers
    Chris

    edit: Updated to display value on LED's as well as the terminal to enhance flexibility and assist in testing possible comms errors.

     

    Last edit: Chris Roper 2018-02-17
  • Chris Roper

    Chris Roper - 2018-02-17

    This example, also for the Xpress Evaluation Board, uses the Map Function twice.
    First to convert the reading from Potentiometer R15 into a mV value and the a second time to convert the mV value into a BAR Graph scale for display on the VT100 Terminal.

    ''' VT100-VoltMeter.xpress.gcb
    '''
    ''' Use R15 (potentiometer) as a 5 potential divider and display
    ''' the current Voltage on a VT100 Terminal (TeraTerm) as a BAR Graph
    
    #Chip 16F18855, 32
    
    'Generated by PIC PPS Tool for Great Cow Basic
    'PPS Tool version: 0.0.5.11
    'PinManager data: v1.55
    
    #startup InitPPS, 85
    
    Sub InitPPS
      'Module: EUSART
        RC0PPS = 0x0010    'TX  > RC0
        TXPPS  = 0x0010    'RC0 > TX (bi-directional)
    End Sub
    
    #option explicit
    
    #include  <LCD2SerialRedirect.h>
    #define LCD_IO 0
    #define USART_BAUD_RATE 19200
    
    Dim NewPos, CurPos as word
    Dim GraphVal as Byte
    
    HSerPrint "Ready"
    
    Do
      NewPos = Map(ReadAD10(AN4), 0, 1023, 0, 3300) ' Convert Position to mV
      GraphVal = Map(NewPos, 0, 3300, 0, 10) ' Convert mV to bar graph value
    
      if NewPos <> CurPos  then
        CurPos = NewPos
        cls : locate 1,1
        HSerPrint "["
        repeat GraphVal
          HSerPrint Chr(219)
        end Repeat
        repeat 10 - GraphVal
          HSerPrint Chr(32)
        end Repeat
        HSerPrint "] "
        HSerPrint(CurPos)
        HSerPrint " mV"
       end if
      wait 100 ms
    Loop
    
    End
    
    function map ( in l_map as word, in l_fromLow as word, in l_fromHigh as word, in l_toLow as word, in l_toHigh  as word) as word
    
      dim l_syscalc as long
      #define _mapFactor 10000
      l_syscalc = ( l_toHigh - l_toLow ) +1
      l_syscalc = [long]l_syscalc * _mapFactor
      l_syscalc = [long]l_syscalc / ( l_fromHigh - l_fromLow )
      l_syscalc = [long]l_syscalc * l_map
      map = (l_syscalc / _mapFactor)
    
    end function
    

    Cheers
    Chris

    edit; Updated to correctly show mV

     

    Last edit: Chris Roper 2018-02-17
  • Chris Roper

    Chris Roper - 2018-02-17

    Thinking further about the Map Function would it not be better to call it Scale?

    Whilst I realise that it is intended to be the equivalent to the Arduino Map Function I would argue that the Arduino team got the name wrong and we would be perpetuating that error.

    My reasoning is that the Function takes one value in a linear range and equates it to another linear range.

    If you were reading a linear temperature sensor such as an (NTC) thermistor you would be converting a linear voltage via an ADC into a 10 digit linier value which in turn would be scaled into degrees of temperature, be it Centigrade or Fahrenheit. Mapping on the other hand is where a non linear value, such as is the case with a thermocouple temperature sensor, is compared to a lookup table to find a value from a map of nonlinear equivalents.

    Ardino is the result of Computer scientists and software engineers but Microcontrollers are from the world of process control and are still predominantly used in that role.

    In light of that, Scale would make far more sence to a Control Engineer than a programmer in the context of convering analoge, or even digital, sensor readings into practical units of mesurment.

    Cheers
    Chris

     
  • Chris Roper

    Chris Roper - 2018-02-17

    One more example.

    This code will allow a simple potentiometer, attached to the shaft, to give numerical feedback of the actual position of a servo motor.

    ''' Angular.Position.xpress.gcb
    '''
    ''' Testing the MAP Function on an Xpress Board
    ''' Display the rotation of the potentiometer (R15) as an Angular
    ''' Position on a VT100 Terminal (TeraTerm).
    
    #Chip 16F18855, 32
    
    'Generated by PIC PPS Tool for Great Cow Basic
    'PPS Tool version: 0.0.5.11
    'PinManager data: v1.55
    '
    #startup InitPPS, 85
    
    Sub InitPPS
      'Module: EUSART
        RC0PPS = 0x0010    'TX  > RC0
        TXPPS  = 0x0010    'RC0 > TX (bi-directional)
    End Sub
    
    #option explicit
    
    #include  <LCD2SerialRedirect.h>
    #define LCD_IO 0
    #define USART_BAUD_RATE 19200
    
    Dim NewPos, CurPos as Integer
    
    HSerPrint "Ready"
    
    Do
      NewPos = Map(ReadAD10(AN4), 0, 1023, 0, 270) - 135 ' Scale Position of Potentiometer to Angular degrees
      if NewPos <> CurPos  then
        CurPos = NewPos
        cls : locate 1,1
        HSerPrint(CurPos)
      end if
      wait 100 ms
    Loop
    
    End
    
    function map ( in l_map as word, in l_fromLow as word, in l_fromHigh as word, in l_toLow as word, in l_toHigh  as word) as word
    
      dim l_syscalc as long
      #define _mapFactor 10000
      l_syscalc = ( l_toHigh - l_toLow ) +1
      l_syscalc = [long]l_syscalc * _mapFactor
      l_syscalc = [long]l_syscalc / ( l_fromHigh - l_fromLow )
      l_syscalc = [long]l_syscalc * l_map
      map = (l_syscalc / _mapFactor)
    
    end function
    

    All of the examples in this thread were created during testing and are posted here to stimulate ideas.

    Even is making a few changes and these examples may be adapted to work as examples for the function in its final form. Feel free to use any of this code as you see fit.

    Cheers
    Chris

     
  • Anobium

    Anobium - 2018-02-18

    A revised method called Scale().


    myvalue = Scale( InValue , fromLow, fromHigh, inHigh, inLow)

    Re-Scales a number from one range to another. That is, a value of fromLow would get Scaled 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.

    Note that the "lower bounds" of either range may be larger or smaller than the "upper bounds" so the Scale() function may be used to reverse a range of numbers, for example
    myvalue = Scale( InValue , 1, 50, 50, 1)

    The function also handles negative numbers well, so that this example
    myvalue = Scale( inValue, 1, 1023, 50, -100) is also valid and works well.

    The Scale() function uses integer maths.

    Anobium

    Totally ripped off from Arduino code. All rights reserved by the original developer.

     
  • stan cartwright

    stan cartwright - 2018-02-18

    I didn't know what map did. I was surprised it re-scaled a range of values.

     
    • Anobium

      Anobium - 2018-02-18

      Learning all time. The initial Great Cow BASIC version I posted supported Bytes and Words.   The version called Scale supports Integers.

      Very interesting use cases posted by Chris. Ineeded to Scale 0 -255 to 225-135 (a range of 270 in a 360 full range) .

       

      Last edit: Anobium 2018-02-18
      • Chris Roper

        Chris Roper - 2018-02-18

        Using the new Scale Function the Angular Position example becomes easier to visualise as the line:

        ' Scale Position of Potentiometer to Angular degrees
        NewPos = Map(ReadAD10(AN4), 0, 1023, 0, 270) - 135
        

        Becomes:

        ' Scale Position of Potentiometer to Angular degrees
        NewPos = Scale(ReadAD10(AN4), 0, 1023, -135, 135)
        

        Making it easy to see that Zero is when the Shaft is centered and that there are 135 Degrees of rotation either side of center for a total arc of 270 Degrees.

         

        Last edit: Chris Roper 2018-02-18
        • Anobium

          Anobium - 2018-02-18

          Using the new Scale Function the Gauge Position on a Nextion Screen is simplified:

          ' Scale Position of Potentiometer to Angular degrees
          ' Read ADC as 8 bit value
          
              adcval = ReadAD( AN4 )
          
           ' Scale to 270 range which is the range of 270 degrees of movement of the gauge
          
              ScaledValue = scale( adcval, 0, 255, -135 , 135 )
          
           ' Adapt the ScaledValue to start at 225degress swing thru 0degree to 135degree.  225..360..0..135 =  (360-225)+(135-0)=270. So, the 0 degree of the gauge it a 0900 hours on an analog clock face.
          
                    AdaptedScaledValue1  = ( 360 + ScaledValue ) mod 360
          
           ' Adapt the ScaledValue to start at 315degress swing thru 180degree to 45degree.  315..180..45 =   (315 - 45 )=270.  So, the 180 degree of the gauge it a 0300 hours on an analog clock face.
          
                    AdaptedScaledValue1  = (180-ScaledValue)
          

          Works great. I have two gauges scaled from a pot. Range of 0 to 255 to -135 to 135.

           

          Last edit: Anobium 2018-02-18
  • stan cartwright

    stan cartwright - 2018-02-18

    A user "kieth sent an email asking for analogue meter display convert to show mark/space in ms for servo actuator. bit vague but now thought this would be handy. depends how fast it is with multiply and divide rather than rescaling/rewriting the program for new scale.
    It's something I'd thought about not realising it's been done.
    private 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;
    }
    Is this function in any basic? naming for consistency and familiarity. I was unfamiliar with map..thought it was to do with a key board

     
    • Anobium

      Anobium - 2018-02-18

      @Stan. What???! You have just posted the Arduino MAP function. We know this exists and we acknowledged this in the documentation. What is your point in the post?

       
  • stan cartwright

    stan cartwright - 2018-02-18

    As a basic user I'm unfamiliar with map. I searched other basic for map. I saw it wanted converting. I'm assuming it's not a standard basic thing so give it a meaningful name as mentioned maybe. Re-scale would mean something more than map for basic users unfamiliar with c map perhaps. maybe scaleto . If it goes in solutions map vs rescale(range) ?

     
    • Anobium

      Anobium - 2018-02-18

      @Stan. OK

       
      • mmotte

        mmotte - 2018-02-28

        @Anobium - hold steadfast! Map is good.

         
  • stan cartwright

    stan cartwright - 2018-02-18

    Anobium - re nextion. I sent you a nextion display. The ide was carp. I thought you'd used it as just a display. I thought of mentioning using gcb to make a nextion display ie send serial commands to use graphics to a programmed pic and screen.
    it was for picaxe but got nowhwere with the program sd card except for demos.
    It wouldn't take much to "make a nextion" with supported glcd. with gcb as far as graphics,the touch screen dunno.
    Thinking, the nextion win ide was no fun but the idea fine. images on sd nice. cost £20
    a simpler/cheaper version as most colour displays have sd slot?

     

    Last edit: stan cartwright 2018-02-18
    • Anobium

      Anobium - 2018-02-18

      I am writing a GLCD library for the Nextion Displays. Next week I may have something ready.

      State of current development. Most Great Cow BASIC GLCD commands are operational. GLCDPrint, Circle, PSET etc etc. I have sorted access to the internal fontset and the Nextion objects. Looking pretty easy to use. But, it has been a lot of work.

      The SD Card is used to load the Nextion screens, but, you can do the same via the serial port.

       

      Last edit: Anobium 2018-02-18
  • stan cartwright

    stan cartwright - 2018-02-18

    ps by the time i type something the forum has been updated but doesn't show in real time so I look daft

     
  • stan cartwright

    stan cartwright - 2018-02-18

    More info please about Anobium using nextion. The display you showed is called a what? it's in the ide.Guages? Did you get the thing working for you? I never did. gcb glcd does fine but not nextion equiv. any thoughts. glcd sd card image is in the forum somewhere. make new thread?

     
  • stan cartwright

    stan cartwright - 2018-02-19

    I tried scale to convert 0-255 to 45-314 degree analoge gauge. It worked.
    Neat function. very fast in this visual use.
    basis of a gauge for glcd. works nice with scale as shows any range.
    a pretty facia would be easy with a few commands

    ;scale to 45 to 314 degrees for "rev counter" type display glcd on uno
    #chip mega328p, 16
    #include <UNO_mega328p.h >
    #option explicit
    #include <glcd.h>
    #INCLUDE <TRIG2PLACES.H>
    ;
    #define GLCD_TYPE GLCD_TYPE_ILI9341
    'Pin mappings for SPI - this GLCD driver supports Hardware SPI and Software SPI
    #define GLCD_DC       DIGITAL_8         ' Data command line
    #define GLCD_CS       DIGITAL_10        ' Chip select line
    #define GLCD_RESET    DIGITAL_9         ' Reset line, you could just tie high
    #define GLCD_DI       DIGITAL_12        ' Data in | MISO    - Not used therefore not really required
    #define GLCD_DO       DIGITAL_11        ' Data out | MOSI
    #define GLCD_SCK      DIGITAL_13        ' Clock Line
    ;
    #define ILI9341_HardwareSPI    ' remove/comment out if you want to use software SPI.
    #define GLCD_EXTENDEDFONTSET1
    GLCDfntDefaultsize = 2
    GLCDRotate (3)
    GLCDCLS ILI9341_BLACK
    ;
    dim radius,xcentre,ycentre,xend,yend as byte
    dim temp,angle,needlecolour,newval,oldval as word
    dir portc.0 in
    ;
    radius=200
    xcentre=160
    ycentre=120
    oldval=45
    newval=45
    ;
    draw_needle
    ;
    Do
    GLCDPrint 0,0,str(readad(portc.0))+"  ",ili9341_white
      newval = Scale(ReadAD(portc.0), 0, 255, 45, 314)
      if newval <> oldval  then
        erase_needle
        draw_needle
        oldval=newval
      end if
    Loop
    
    End
    ;
    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
    ;
    sub erase_needle
      angle=oldval
      needlecolour=ILI9341_black
      radius=200
      needle ;erase needle
    end sub
    ;
    sub draw_needle
      angle=newval
      needlecolour=ILI9341_white
      radius=200
      needle ;draw needle
    end sub
    ;
    sub needle
      xend = xcentre - radius  * sin (angle)/255
      yend = ycentre + radius  * cos (angle)/255
      line (xcentre,ycentre,xend,yend,needlecolour)
    end sub
    
     

    Last edit: stan cartwright 2018-02-19
  • stan cartwright

    stan cartwright - 2018-02-20

    I noticed the a2d doesn't get to 255 (or 1023 with readad10) on uno or nano 328p in the code just posted for scale to ili glcd. https://youtu.be/ywBkivRINl0

     
    • Anobium

      Anobium - 2018-02-20

      What are the returned results? The range Please post your ASM. What is VREF set to ( see help for VREF).

       
  • stan cartwright

    stan cartwright - 2018-02-20

    I added

     #define AD_REF_SOURCE AD_REF_256 
    

    This sorted it, readad goes 0-255 but connecting ad.0 to 5V and it's not steady at 255 but jumping around between 248 and 252. Connecting to 0V gives steady 0.
    I've never changed the vref and readad has always been 0-255.
    Add attatchments not working.

     

    Last edit: stan cartwright 2018-02-20
    • Anobium

      Anobium - 2018-02-20

      Did you check the 0v common ground?

       
1 2 > >> (Page 1 of 2)

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.