Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

MAP functions... and some variation of the FreqDuty gen.

 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> Share your working BASCOM-AVR code here
View previous topic :: View next topic  
Author Message
EDC

Bascom Expert



Joined: 26 Mar 2014
Posts: 971

poland.gif
PostPosted: Tue Sep 01, 2020 11:12 am    Post subject: MAP functions... and some variation of the FreqDuty gen. Reply with quote

Hello.
I want to show one Function that can be handy in many cases.
It can scale Input_value that have determined range of the Minimum_in and Maximum_in into Output_Value that should be in the range of the Minimum_out and Maximum_out.

For example I can scale 0-1023 ADC readed from potentiometer into 1-100 that represent procent (%). In that way you have full swing of potentiometer (from very left into very right) scaled smoothly into new range.

Function showed below can be modified if you have different needs. So if Inputs are only Bytes (for example "Byval Min_in As Byte") then you can short internal Local Long variables into the Integers. Same if you expect results below zero then Function should return Integer, not Word.


Code:
Function Map(byval Value As Word , Byval Min_in As Word , Byval Max_in As Word , Byval Min_out As Word , Byval Max_out As Word)as Word
 Local I1 As Long
 Local I2 As Long
   I1 = Value - Min_in
   I2 = Max_out - Min_out
   I1 = I1 * I2
   I2 = Max_in - Min_in
   I1 = I1 / I2
   I1 = I1 + Min_out
   'Map = Abs(i1)     'casting Abs() directly into result may give wrong values
   I1 = Abs(i1)
   Map = I1
   If Map >= Max_out Then Map = Max_out - 1
End Function
 



For example of use I attach some variation of code previously published HERE
It is also a square wave generator but operated by two potentiometers. First potentiometer set the frequency from 20Hz to 2kHz and this is done by MAP function controlled by two constans in the line 12 Min_freq = 20 (Hz) and Max_freq = 2000 (Hz)
For Duty controll MAP function is reused, but with another boundares 1-100 Very Happy
Actual generator settings are displayed on the LCD.
Code example is for Mega2560 but it will work on the Mega328P Uno and other uC`s that have simillar registers structure..

Code:
$regfile = "m2560def.dat"                                   '8K SRAM
$crystal = 16000000
$hwstack = 64
$swstack = 16
$framesize = 200
$baud = 115200

' FREQ DUTY GENERATOR OPERATED BY TWO POTENTIOMETERS

Debug Off

Const Min_freq = 20                                         'Hz
Const Max_freq = 2000                                       'Hz
Const Min_duty = 1                                          ' 1%-100%
Const Max_duty = 100                                        ' 1%-100%

Config Submode = New                                        'Subs first then you can use them

'***********************************************
'*           ALPHANUMERIC LCD                  *
'***********************************************

   Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.5 , Db6 = Portc.7 , Db7 = Porta.6 , E = Portl.5 , Rs = Portl.1       ' , Wr = Porta.1
   Config Lcd = 16x2
   Cursor Off , Noblink
   Cls

'***********************************************
'*                  I/O                        *
'***********************************************

   Config Portb.7 = Output : Led Alias Portb.7              'Arduino Mega LED
   Config Portb.5 = Output : Freq_out Alias Portb.5         'Freq/Duty output pin

'***********************************************
'*                   ADC                       *
'***********************************************

'freq potentiometer on A0
'duty potentiometer on A1

Config Adc = Single , Prescaler = Auto , Reference = Avcc

Dim New_adc As Word , Freq_adc As Word , Duty_adc As Word

'***********************************************
'*                 VARIABLES                   *
'***********************************************
'multipurpose
 Dim Helpb As Byte , N As Byte
'program
 Dim New_freq As Word , New_duty As Word , Change As Byte
 'timer
 Dim Value As Dword , Ustaw As Word , Prescaler As Word , Help_d As Dword
 Dim Wartosc_dla_tccr1b As Byte , Wypelnienie As Word , Proc As Word

'***********************************************
'*                    TIMER1                   *
'***********************************************

'----------------------------------------------------------------
'TCCR1A  -> |COM1A1  COM1A0 COM1B1 COM1B0   --    --  WGM11 WGM10
'TCCR1B  -> | ICNC1   ICES1  --    WGM13  WGM12  CS12  CS11  CS10   FOR MEGA328P
'TCCR1C  -> | FOC1A  FOC1B   --     --     --     --    --    --
'----------------------------------------------------------------
  Const Freq = _xtal
'                    WGM13-|
   Const Pwm_presc1 = &B00010001                            'for TCCR1B
   Const Pwm_presc8 = &B00010010
  Const Pwm_presc64 = &B00010011
 Const Pwm_presc256 = &B00010100
Const Pwm_presc1024 = &B00010101

Const Set_output_mode = &B10100000                          'for TCCR1A


Function Map(byval Value As Word , Byval Min_in As Word , Byval Max_in As Word , Byval Min_out As Word , Byval Max_out As Word)as Word
 Local I1 As Long
 Local I2 As Long
   I1 = Value - Min_in
   I2 = Max_out - Min_out
   I1 = I1 * I2
   I2 = Max_in - Min_in
   I1 = I1 / I2
   I1 = I1 + Min_out
   I1 = Abs(i1)
   Map = I1
   'Map = Abs(i1)
   If Map >= Max_out Then Map = Max_out - 1
End Function

Sub Calc_duty()
  Help_d = Value * New_duty
  Help_d = Help_d / 100
  Wypelnienie = Help_d
   Ocr1a = Wypelnienie
End Sub

Locate 1 , 1 : Lcd "Freq="
Locate 2 , 1 : Lcd "Duty="

Freq_adc = 1024 : Duty_adc = 1024                           'refresh even if zero

Do

 New_adc = 0
 For N = 1 To 64
  New_adc = New_adc + Getadc(0)
 Next
 Shift New_adc , Right , 6

 If Freq_adc <> New_adc Then
  Freq_adc = New_adc

  New_freq = Map(freq_adc , 0 , 1023 , Min_freq , Max_freq) ' <<< 0-1023 scaled here into 20 to 2000

  Locate 1 , 6 : Lcd New_freq ; "Hz  "

  Change = 1
 End If

 New_adc = 0
 For N = 1 To 64
  New_adc = New_adc + Getadc(1)
 Next
 Shift New_adc , Right , 6

 If Duty_adc <> New_adc Then
  Duty_adc = New_adc

  New_duty = Map(duty_adc , 0 , 1023 , Min_duty , Max_duty) ' <<< 0-1023 scaled here into 1 to 100

  Locate 2 , 6 : Lcd New_duty ; "%   "

  Change = 1
 End If

 If Change = 1 Then
  Change = 0

   Help_d = New_freq


    If Help_d > 0 Then

     Value = Freq                                           'uC clock speed

      Select Case Help_d

       Case 1

        '256
         Wartosc_dla_tccr1b = Pwm_presc256
          Shift Value , Right , 8

       Case 2 To 15
       '64
         Wartosc_dla_tccr1b = Pwm_presc64
          Shift Value , Right , 6

       Case 16 To 122                                       '16000000Hz/131072 = 15Hz  '
       '8
         Wartosc_dla_tccr1b = Pwm_presc8
          Shift Value , Right , 3

       Case Else                                            '16000000Hz/131072 = 122Hz
       '1
         Wartosc_dla_tccr1b = Pwm_presc1

      End Select

      Value = Value \ Help_d
       Shift Value , Right , 1                              'divide /2

       Decr Value : Ustaw = Value                           'substract one

       Call Calc_duty()

        Icr1 = Ustaw

         Tccr1a = Set_output_mode                           'set count up, reset count down
         Tccr1b = Wartosc_dla_tccr1b                        'set prescaler and WGM13

    End If

 End If
Loop
End
Back to top
View user's profile Visit poster's website
albertsm

Administrator



Joined: 09 Apr 2004
Posts: 5921
Location: Holland

blank.gif
PostPosted: Wed Sep 02, 2020 7:09 pm    Post subject: Reply with quote

thanks for posting this. This is a very usable function. And easy adjustable Very Happy
_________________
Mark
Back to top
View user's profile Visit poster's website
Dave

Bascom Member



Joined: 05 Feb 2005
Posts: 314
Location: OR

usa.gif
PostPosted: Thu Sep 03, 2020 4:10 am    Post subject: Reply with quote

Thanks for sharing. Mapping functions are great.
Here are a few other mapping functions to consider. https://www.mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&t=12401
Back to top
View user's profile
albertsm

Administrator



Joined: 09 Apr 2004
Posts: 5921
Location: Holland

blank.gif
PostPosted: Thu Sep 03, 2020 9:08 am    Post subject: Reply with quote

i already thought i had seen it before. but was not sure if it was here.
Anyway, good to have these variations.

_________________
Mark
Back to top
View user's profile Visit poster's website
EDC

Bascom Expert



Joined: 26 Mar 2014
Posts: 971

poland.gif
PostPosted: Thu Sep 03, 2020 10:58 am    Post subject: Reply with quote

I dont use "Search" option of the Forum (my bad) so I also translate this from C source some time ago. No plagiarism here Very Happy
If I had seen before linked topic maybe Meister example, where compiler precalculate some values, will be used.
Anyway MAP topic is refreshed and new handy example is attached Very Happy
Back to top
View user's profile Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> Share your working BASCOM-AVR code here All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum