Menu

Simple PWM generation for low frequencies.

mkstevo
2020-05-06
2020-08-14
  • mkstevo

    mkstevo - 2020-05-06

    I had the need to generate some very low frequency PWM recently. As the inbuilt PWM does not go that low, I looked at writing my own. I know there is the software PWM but as that can only generate PWM whilst it is 'active' (as, I should say mine does) and given I wanted the capability of ramping the PWM up and down to provide a soft start, and soft stop, I thought I'd see if I could make my own.

    These routines are capable of generating PWM from 10Hz to 999Hz, with a minimum duty of 1% and a maximum of 99%.

    The ramp routines can ramp up from any value (1% minimum) to any value (99% max) and if required the ramp down will do the same in reverse.

    I've tried to comment the code as much as possible, they form a working demonstration for the 12F1840 and should be easily portable to any processor.

    I don't for a second assume that they are better than the software PWM library, but they gave me the flexibility I required.

    They are rather memory hungry, needing about 1700 words of program space. This could be reduced by a few words by omitting the adjustable (potentiometer and ADC) routines if not needed. If you don't need the flexibility of being able to invert the PWM generation, these parts could also be omitted giving further savings.

    '12F1840 demo for PWM generation
    
    'The Frequency can be from 10 Hz to 750 Hz
    'The Duty can be from 1% to 99%
    
    'First, set the frequency:
    'Set_Frequency(Frequency_In_Hz)
    'Set_Frequency(500) 'Sets a frequency of 500Hz
    
    'Then, set the duty:
    'Set_Duty(Duty_Required_In_Percent)
    'Set_Duty(25) 'Sets an on duty of 25% and an off duty of 75%
    
    'GenerateFixed_PWM will generate set number of PWM cycles, at
    'the current frequency and duty
    'GenerateFixed_PWM(Number_Of_Cycles, Invert_PWM)
    'Invert_PWM determines whether the duty of the PWM should be
    'inverted or not.
    'When inverted, a duty of 25% on and 75% off becomes 75% on and 25% off.
    'GenerateFixed_PWM(100,0) generates 100 cycles of non-inverted PWM at
    'the current frequency and duty
    
    'RampUp_PWM ramps the PWM at the current frequency from the start duty
    'to the end duty.
    'The start duty must be less than end duty. If not, no PWM will be generated.
    'The start can not be less than 1%, the end can not be more than 99%.
    'If these are exceeded, they will default to 1%, or 99%.
    'RampUp_PWM(Start_DUTY, End_Duty, Invert_PWM)
    'RampUp_PWM(0,99,0) generates a PWM that ramps from 1% to 99% which is not inverted
    
    'RampDn_PWM ramps the PWM at the current frequency from the start duty
    'to the end duty.
    'The start duty must be more than end duty. If not, no PWM will be generated.
    'The start can not be more than 99%, the end can not be more than 1%.
    'If these are exceeded, they will default to 1%, or 99%.
    'RampDn_PWM(Start_DUTY, End_Duty, Invert_PWM)
    'RampDn_PWM(99,0,0) generates a PWM that ramps from 99% to 1% which is not inverted
    
    'Set_Variable_PWM allows the duty to be set by a potentiometer connected to an ADC input
    'in this example, it is ADC0 = Pin 7 on the 12F1840
    '====
    'NOTE
    '====
    'After Set_Variable_PWM has been used, all PWM will be generated at the most recent 
    'duty set by the potentiometer. To return to another duty, Set_Duty must be used.
    
    'GenerateVariable_PWM generates a PWM where the duty is set by the potentiometer
    'as in Set_Variable_PWM.
    'To generate a fully variable PWM, call GenerateVariable_PWM from within a loop
    'GenerateVariable_PWM(Number_Of_Cycles, Invert_PWM)
    'Invert_PWM determines whether the duty of the PWM should be
    'inverted or not.
    
    'Repeat 100
    '    GenerateVariable_PWM(10,0)
    'End Repeat
    
    'Generates 100 patterns of 10 cycles of PWM. The PWM duty is updated after each
    'pattern of 10 cycles of PWM have been generated.
    '====
    'NOTE
    '====
    'After GenerateVariable_PWM has been used, all PWM will be generated at the most recent 
    'duty set by the potentiometer. To return to another duty, Set_Duty must be used.
    
    
    'The final two routines are not implemented, they are from a program for the 16F1825
    'The idea is (or was) to provide a number of steps of positive and negative adjustment
    'depending on the position of the potentiometer. When the potentiometer is set to the
    'middle position, no adjustment is made. As the potentiometer is rotated left and right,
    'further steps of adjustment are made.
    
    'Set_PWMValues
    '
    'and
    '
    'Get_AdjustedPWM
    
    'Set_PWMValues
    'This increases the value of some fixed PWM duties by up to +/- 22%
    'The fixed values can then be used to call one of the other PWM generation routines
    '
    'Example 1:
    'RampUp_PWM(0,SpMed,0)
    '
    'would ramp up to the fixed PWM duty set by SpMed
    '
    'Example 2:
    'Set_PWM_Values
    'RampUp_PWM(0,SpMed,0)
    '
    'Would first adjust the value of SpMed depending on the position of a potentiometer
    'and then ramp the PWM up from zero to that adjusted value.
    '
    '
    'To use these routines, these variables used in them would require dimensioning:
    '
    'Dim SpHigh As Byte
    'Dim SpHmed As Byte
    'Dim SpMed  As Byte
    'Dim SpLmed As Byte
    'Dim SpLow  As Byte
    'Dim SpDead As Byte
    '
    'Let SpHigh = 90
    'Let SpHmed = 75
    'Let SpMed  = 50
    'Let SpLmed = 30
    'Let SpLow  = 25
    'Let SpDead = 10
    
    
    '(c) Mark Stevenson 2020
    
    '  'Optimise A-d.h
    '  'Standard family chips
        #define USE_AD0 True
        #define USE_AD1 False
        #define USE_AD2 False
        #define USE_AD2 False
        #define USE_AD3 False
        #define USE_AD4 False
        #define USE_AD5 False
        #define USE_AD6 False
        #define USE_AD7 False
        #define USE_AD8 False
        #define USE_AD9 False
        #define USE_AD10 False
        #define USE_AD11 False
        #define USE_AD12 False
        #define USE_AD13 False
        #define USE_AD14 False
        #define USE_AD15 False
        #define USE_AD16 False
        #define USE_AD17 False
        #define USE_AD18 False
        #define USE_AD19 False
        #define USE_AD20 False
        #define USE_AD21 False
        #define USE_AD22 False
        #define USE_AD23 False
        #define USE_AD24 False
        #define USE_AD25 False
        #define USE_AD26 False
        #define USE_AD27 False
        #define USE_AD28 False
        #define USE_AD29 False
        #define USE_AD30 False
        #define USE_AD31 False
        #define USE_AD32 False
        #define USE_AD33 False
        #define USE_AD34 False
    
    
    #Option Explicit
    #Chip 12F1840, 32
    
    #Config CP=On
    'Read protected
    
    '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    '                                 +5V    1
    #Define                 Pin2    PortA.5 '2
    #Define                 Pin3    PortA.4 '3
    #Define                 Pin4    PortA.3 '4 - In only
    #Define                 PWM_Out PortA.2 '5
    #Define                 Pin6    PortA.1 '6
    #Define                 ADC_In  PortA.0 '7
    '                                 Gnd    8
    '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
    Dir                 Pin2    Out
    Dir                 Pin3    In
    Dir                 Pin4    In
    Dir                 PWM_Out Out
    Dir                 Pin6    Out
    Dir                 ADC_In  In
    
    '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    'Initialise PWM
    Dim    Freq_Time       As Long 'Holds the time of a complete cycle in uS
    Dim    PWM_OnTime      As Long 'Holds the 'On'  part of the PWM time
    Dim    PWM_OffTime     As Long 'Holds the 'Off' part of the PWM time
    Dim    ADC_Value       As Word 'Holds the value of the pot
    Dim    Last_ADC        As Word 'Check to see if pot position changed
    Dim    Current_Duty    As Word 'Holds the most recent duty
    Let    Freq_Time       = 0
    Let    PWM_OnTime      = 0
    Let    PWM_OffTime     = 0
    Let    ADC_Value       = 0
    Let    Last_ADC        = 0
    Let    Current_Duty    = 0
    'Initialise Frequency and Duty
    Set_Frequency(125)
    Set_Duty(10)
    '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    Do
    
    'With a frequency of 125Hz, each complete cycle should take 8 mS to be generated
    '1000 cycles should equate to eight seconds of PWM (1000 x 0.008 = 8 Seconds)
    
    'The timings below are approximate, but should give an idea of their usage
    
        GenerateFixed_PWM(1000,0) 'This generates around 10 seconds of fixed value PWM      at 125Hz
    
        'PWM Inverted
        GenerateFixed_PWM(1000,1) 'This generates around 10 seconds of fixed value PWM      at 125Hz
    
        'The ramp time can be reduced by lowing the repeat count in ramp up and ramp down routines
    
        RampUp_PWM(0,98,0)        'This takes approximately 5 seconds to ramp from 0  - 98% at 125Hz
        RampDn_PWM(98,0,0)        'This takes approximately 5 seconds to ramp from 98 -  0% at 125Hz
    
        'PWM Inverted
        RampUp_PWM(0,98,1)        'This takes approximately 5 seconds to ramp from 0  - 98% at 125Hz
        RampDn_PWM(98,0,1)        'This takes approximately 5 seconds to ramp from 98 -  0% at 125Hz
    
        Repeat 100                '100 repeats of 10 cycles gives around 10 seconds of PWM  at 125Hz
            GenerateVariable_PWM(10,0)
        End Repeat
    
        'Set duty after variable PWM has been used
        Set_Duty(10)
    
    Loop
    
    Sub Set_Frequency(In Frequency As Long)
    
        If Frequency > 750 Then
            Let Frequency = 500
        End If
        If Frequency < 10 Then
            Let Frequency = 10
        End If
    
        Let Freq_Time = 7250 / Frequency
        'This should give us the uS delay required to generate the PWM time
        If PWM_OnTime = 0 Then
            Set_Duty(50)
        End If
    End Sub
    
    Sub Set_Duty(In DutyRatio As Byte)
    
        If Freq_Time = 0 Then
            Set_Frequency(125)
        End If
    
        If DutyRatio > 99 Then
            Let DutyRatio = 99
        End If
        If DutyRatio < 1 Then
            Let DutyRatio = 1
        End If
    
        Let Current_Duty= DutyRatio
    
        Let PWM_OnTime  = DutyRatio
        Let PWM_OffTime = 100 - PWM_OnTime
    
        Let PWM_OnTime  = Freq_Time * PWM_OnTime
        Let PWM_OffTime = Freq_Time * PWM_OffTime
    
    End Sub
    
    Sub GenerateFixed_PWM(In Cycles As Word, In Invert_PWM As Byte)
    
        If Invert_PWM = 0 Then
            Repeat Cycles 'Generate a few cycles of PWM
                Let PWM_Out     = 1
                Repeat PWM_OnTime
                    Wait 1 uS
                End Repeat
    
                Let PWM_Out     = 0
                Repeat PWM_OffTime
                    Wait 1 uS
                End Repeat
            End Repeat
        Else
            Repeat Cycles 'Generate a few cycles of Inverted PWM
                Let PWM_Out     = 0
                Repeat PWM_OnTime
                    Wait 1 uS
                End Repeat
    
                Let PWM_Out     = 1
                Repeat PWM_OffTime
                    Wait 1 uS
                End Repeat
            End Repeat
        End If
    
    End Sub
    
    Sub GenerateVariable_PWM(In Cycles As Word, In Invert_PWM As Byte)
        Set_Variable_PWM
        GenerateFixed_PWM(Cycles, Invert_PWM)
    End Sub
    
    Sub RampUp_PWM(In StartDuty As Byte, In EndDuty As Byte, In Invert_PWM As Byte)
    'The ramp time can be reduced by lowing the repeat count in ramp up and ramp down routines
    Dim St_PWMOn   As Long
    Dim St_PWMOff  As Long
    Dim RampLoop   As Byte
    
        If StartDuty > 99 Then
            Let StartDuty = 99
        End If
        If StartDuty < 1 Then
            Let StartDuty = 1
        End If
    
        If EndDuty > 99 Then
            Let EndDuty = 99
        End If
        If EndDuty < 1 Then
            Let EndDuty = 1
        End If
    
        If Freq_Time = 0 Then
            Set_Frequency(125)
        End If
    
        If StartDuty => EndDuty Then
            Exit Sub
        End If
    
        Let RampLoop = EndDuty - StartDuty
    
        Let St_PWMOn  = StartDuty
        Let St_PWMOff = 100 - St_PWMOn
    
        Let St_PWMOn  = Freq_Time * St_PWMOn
        Let St_PWMOff = Freq_Time * St_PWMOff
    
        If Invert_PWM = 0 Then
            Repeat RampLoop 'Std PWM
    'The ramp time can be reduced by lowing the repeat count in ramp up and ramp down routines
                Repeat 5 ' 5 cycles of each "step"
                    Let PWM_Out = 1
                    Repeat St_PWMOn
                        Wait 1 uS
                    End Repeat
    
                    Let PWM_Out     = 0
                    Repeat St_PWMOff
                        Wait 1 uS
                    End Repeat
                End Repeat
                Let St_PWMOn  = St_PWMOn  + Freq_Time
                Let St_PWMOff = St_PWMOff - Freq_Time
            End Repeat
        Else
            Repeat RampLoop 'Inverted PWM
    'The ramp time can be reduced by lowing the repeat count in ramp up and ramp down routines
                Repeat 5 ' 5 cycles of each "step"
                    Let PWM_Out     = 0
                    Repeat St_PWMOn
                        Wait 1 uS
                    End Repeat
    
                    Let PWM_Out     = 1
                    Repeat St_PWMOff
                        Wait 1 uS
                    End Repeat
                End Repeat
                Let St_PWMOn  = St_PWMOn  + Freq_Time
                Let St_PWMOff = St_PWMOff - Freq_Time
            End Repeat
        End If
    
        Let Current_Duty = EndDuty
    
    End Sub
    
    Sub RampDn_PWM(In StartDuty As Byte, In EndDuty As Byte, In Invert_PWM As Byte)
    'The ramp time can be reduced by lowing the repeat count in ramp up and ramp down routines
    Dim St_PWMOn   As Long
    Dim St_PWMOff  As Long
    Dim RampLoop   As Byte
    
        If StartDuty > 99 Then
            Let StartDuty = 99
        End If
        If StartDuty < 1 Then
            Let StartDuty = 1
        End If
    
        If EndDuty > 99 Then
            Let EndDuty = 99
        End If
        If EndDuty < 1 Then
            Let EndDuty = 1
        End If
    
        If Freq_Time = 0 Then
            Set_Frequency(125)
        End If
    
        If StartDuty <= EndDuty Then
            Exit Sub
        End If
    
        Let RampLoop = StartDuty - EndDuty
    
        Let St_PWMOn  = StartDuty
        Let St_PWMOff = 100 - St_PWMOn
    
        Let St_PWMOn  = Freq_Time * St_PWMOn
        Let St_PWMOff = Freq_Time * St_PWMOff
    
        If Invert_PWM = 0 Then
            Repeat RampLoop 'Std PWM
    'The ramp time can be reduced by lowing the repeat count in ramp up and ramp down routines
                Repeat 5 ' 5 cycles of each "step"
                    Let PWM_Out     = 1
                    Repeat St_PWMOn
                        Wait 1 uS
                    End Repeat
    
                    Let PWM_Out     = 0
                    Repeat St_PWMOff
                        Wait 1 uS
                    End Repeat
                End Repeat
                Let St_PWMOn  = St_PWMOn  - Freq_Time
                Let St_PWMOff = St_PWMOff + Freq_Time
            End Repeat
        Else
            Repeat RampLoop 'Inverted PWM
    'The ramp time can be reduced by lowing the repeat count in ramp up and ramp down routines
                Repeat 5 ' 5 cycles of each "step"
                    Let PWM_Out     = 0
                    Repeat St_PWMOn
                        Wait 1 uS
                    End Repeat
    
                    Let PWM_Out     = 1
                    Repeat St_PWMOff
                        Wait 1 uS
                    End Repeat
                End Repeat
                Let St_PWMOn  = St_PWMOn  - Freq_Time
                Let St_PWMOff = St_PWMOff + Freq_Time
            End Repeat
        End If
    
        Let Current_Duty = EndDuty
    
    End Sub
    
    Sub Set_Variable_PWM
    
        Let ADC_Value = ReadAD10(AN0, True) 'Read the ADC. AN0 on the 12F1840 is pin 7
        If ADC_Value > 990 Then
            Let ADC_Value = 990
        End If
        If ADC_Value < 1 Then
            Let ADC_Value = 1
        End If
    
        Let ADC_Value = ADC_Value / 10 'Give a value of 1 - 99
    
        If ADC_Value <> Last_ADC Then
            Let Last_ADC = ADC_Value
            Set_Duty(ADC_Value)
        End If
    
    End Sub
    
    'These last two routines are not implemented, they are from a program for the 16F1825
    'The idea is (or was) to provide a number of steps of positive and negative adjustment
    'depending on the position of the potentiometer. When the potentiometer is set to the
    'middle position, no adjustment is made. As the potentiometer is rotated left and right,
    'further steps of adjustment are made.
    
    'This increases the value of some fixed PWM duties by up to +/- 22%
    'The fixed values are then used to call one of the other PWM generation routines
    '
    'Example 1:
    'RampUp_PWM(0,SpMed,0)
    '
    'would ramp up to the fixed PWM duty set by SpMed
    '
    'Example 2:
    'Set_PWM_Values
    'RampUp_PWM(0,SpMed,0)
    '
    'Would first adjust the value of SpMed depending on the position of a potentiometer
    'and then ramp the PWM up from zero to that adjusted value.
    '
    '
    'To use these routines, the variables used in them would require dimensioning:
    '
    'Dim SpHigh As Byte
    'Dim SpHmed As Byte
    'Dim SpMed  As Byte
    'Dim SpLmed As Byte
    'Dim SpLow  As Byte
    'Dim SpDead As Byte
    '
    'Let SpHigh = 90
    'Let SpHmed = 75
    'Let SpMed  = 50
    'Let SpLmed = 30
    'Let SpLow  = 25
    'Let SpDead = 10
    
    
    Sub Set_PWMValues
        Get_AdjustedPWM
        If Adjustment > 0 Then
        'The maximum number of steps are 22
        'Be aware that where this can result
        'in values going over 99 or under 1
        'this should be checked for.
            If Adjustment > 100 Then 'A positive adjustment required
                Let Adjustment  = Adjustment - 100
                Let SpHigh = 90 + Adjustment
                Let SpHmed = 75 + Adjustment
                Let SpMed  = 50 + Adjustment
                Let SpLmed = 30 + Adjustment
                Let SpLow  = 25 + Adjustment
                Let SpDead = 10 + Adjustment
                If SpHigh > 99 Then
                    Let SpHigh = 99
                End If
            Else                     'A negative adjustment required
                Let SpHigh = 90 - Adjustment
                Let SpHmed = 75 - Adjustment
                Let SpMed  = 50 - Adjustment
                Let SpLmed = 30 - Adjustment
                Let SpLow  = 25 - Adjustment
                Let SpDead = 10 - Adjustment
                If SpDead > 99 Then
                    Let SpDead = 1
                End If
            End If
        Else
            Let SpHigh = 90
            Let SpHmed = 75
            Let SpMed  = 50
            Let SpLmed = 30
            Let SpLow  = 25
            Let SpDead = 10
        End If
    End Sub
    
    'A method of using these adjusted steps is shown in Set_PWMValues
    
    Sub Get_AdjustedPWM
    
        Let ADC_Value = ReadAD10(AN0, True) 'Read the ADC. AN0 on the 12F1840 is pin 7
    
        If ADC_Value > 990 Then
            Let ADC_Value = 990
        End If
        If ADC_Value < 1 Then
            Let ADC_Value = 1
        End If
    
        Let ADC_Value = ADC_Value / 10 'Give a value of 1 - 99
    
        Let Adjustment = 0
    
        'Note: In the original prototype
        'The potentiometer is wired in "Reverse" so positive values
        'indicate that a negative adjustment has been requested.
        If ADC_Value > 55 Then
            Let Adjustment = ADC_Value - 55
            Let Adjustment = Adjustment / 2   'This should give a total of 22 steps in the negative direction
        End If
        If ADC_Value < 45 Then
            Let Adjustment = 45 - ADC_Value
            Let Adjustment = Adjustment / 2   'This should give a total of 22 steps in the positive direction
            Let Adjustment = Adjustment + 100 'Indicate it is a positive value
        End If
    
    End Sub
    
     

    Last edit: mkstevo 2020-05-07
  • Anobium

    Anobium - 2020-05-06

    Very, very nice.

    May I make a demo from this? Essentially, means I put in GitHub (demos in the distro).

    Code comments.

    1. ReadAD10 ( AN7 ) as there is no AN7 the code does what? Should this be AN0?
    2. You could add the Code Optimiser with just AN0 set to TRUE and this would save a lot of PROGMEM.

    Very cool.

     
  • mkstevo

    mkstevo - 2020-05-07

    Sorry, I guess I didn't make that section as clear as it ought to be.

    The bottom two routines are not used in the demonstration program, they are there to provide inspiration on how this could be achieved. There is a comment that says that they were taken from a program for the 16F1825 and that for the 12F1840 "ReadAD10(AN7)" would need changing to "ReadAD10(AN0)". I should perhaps update that so that for the 12F1840 they work correctly, it might be more obvious.

    Code updated to remove references to AN7.
    Code updated to include Optimisation for ADC.

     

    Last edit: mkstevo 2020-05-07
  • stan cartwright

    stan cartwright - 2020-08-09

    Your code attracted my interest as I needed a fixed every 20ms pwm with 1 to 19ms pulse width.
    I used an every 1ms interrupt but with a faster interrupt could work to 1000Hz...and variable duty cycle.
    I'll get back on this when (if) I sort it.

     
  • stan cartwright

    stan cartwright - 2020-08-09

    Your code says 0 to 1000 Hz pwm.
    That would be every 1ms but then the 0 to 100% duty cycle would be 10us.
    I don't think much could be done in 10us interrupt but gonna scope it...if my usb can cope.
    like cheap dc motors in reclaimed toys to make a robot may not like high pwm frequencies...
    not so low that it humms though.

     
  • stan cartwright

    stan cartwright - 2020-08-09

    Your code says 0 to 1000 Hz pwm.
    That would be every 1ms but then the 0 to 100% duty cycle would be 10us.
    I don't think much could be done in 10us interrupt but gonna scope it...if my usb can cope.
    like cheap dc motors in reclaimed toys to make a robot may not like high pwm frequencies...
    not so low that it humms though.
    so..every 1ms if pwm=1% then on 10us off 990us
    if pwm=99% then on 990us off 10us.

    that's just for 1KHz...doh

     

    Last edit: stan cartwright 2020-08-09
  • stan cartwright

    stan cartwright - 2020-08-09

    I just sorted this demo based on the 50Hz pwm code I had.
    https://www.youtube.com/watch?v=kJ03zHD_g5I&feature=youtu.be

    #chip mega328p,16
    #option explicit
    
    dir portd.7 out
    dim us_counter , pwm_val as byte
    ;-------------------------------
    ;start 1ms interrupt isr
        On Interrupt Timer0Match1 Call isr
        Dim OCR0  AS byte alias OCR0A
        Dim TCCR0 AS  byte alias TCCR0B
        WGM01 = 1
        OCR0 = 159 ;10us
        TCCR0 = 0x28
        TCCR0 = TCCR0 or 0x01
    '--------------
    do
    pwm_val=50
    loop
    ;
    Sub isr ;called every 10uS
      us_counter ++
      if us_counter = 100 then
        us_counter = 0
        set portd.7 on
      else if us_counter = pwm_val then
        set portd.7 off
      end if
    End Sub
    

    How to vary the pwm frequency ??

     

    Last edit: stan cartwright 2020-08-09
  • stan cartwright

    stan cartwright - 2020-08-09

    I'm making progress Mike. You got to get into interrups mate. I am just learning like timer0 match and the 328 has 3 timers to play with. The timercalculator is worth installing.
    I will start a new thread and say inspired by your idea of slower pwm.
    my version will allow a program to run in the foreground I guess but it wil be interrupted every 10us so will still work?? I am still a gcb beginner

     
  • stan cartwright

    stan cartwright - 2020-08-11

    Although i was pleased I got a 1KHz pwm to work in a short time and felt smug,
    getting it to change frequency to 1Hz accuracy would it seems need a faster than 10uS interrupt...more like 1uS.
    999Hz=1001.001001001 uS
    998Hz=1002.004008016 uS
    997Hz=1003.0090270812 uS

    It looks like just add 1uS but doing my head in :)
    adding 1uS changes frequency but not pwm % and I seem to be looking at this wrong ...or may be not possible...but still trying.

     
  • stan cartwright

    stan cartwright - 2020-08-12

    Added a pot
    do
    pwm_percent=scale(readad (AN0),0,255,1,99)
    loop
    but can't figure frequency change
    https://www.youtube.com/watch?v=sXdhdx3Qgas

     
  • mkstevo

    mkstevo - 2020-08-13

    For the use I needed this for, interrupts might not have worked too well. I'm not good with interrupts either and trying to do what I needed looked like very hard work using them.

    I particularly required that the PWM could be "ramped" up and down, moving the motors (which vary from 12V types to 48V types) progressively when starting and stopping. I also needed to ramp up and down a solenoid, which again can vary in voltage.

    A "linear" approach where:
    some PWM is ramped up,
    some switches tested,
    more PWM generated,
    switches tested,
    if switches reach certain positions,
    ramp PWM down,
    reverse motors,
    ramp PWM up,
    test switches,
    generate more PWM,
    test switches,
    if switches reach certain positions,
    ramp PWM down,
    change motors,
    Ramp PWM up...

    Is more suited to my application, and to my mind, easier for me to program and understand.

    The motors are more suted to low frequency PWM, as are the solenoids. I only use PWM up to 250Hz, in order to give me some leeway in case I needed higher frequencies later, I limited my calculations to 1kHz.

    Above a few 100Hz, the PWM modules in the (PIC) device peripherals would almost certainly be more suited. By running the device at a slow oscillator frequency, it is possible to generate lower frequencies than might be considered normally. Again, had it not been for the requirement I set myself of ramping up and down the PWM, this might have been the approach I would have taken. My original PicAxe program and design that these routines were intended to replace, did not have the ramp facilities, but I wanted to improve on that to make it worth my while in redesigning the circuit.

    When it is working, it really is a joy to watch! We manufacture, sell and repair machines that are sold into amusement arcades. This test unit forms part of an automated test unit for the "mechanics" for the "Grabbing" machines that you would see in a seaside arcade where you might try to win a soft toy. This tests not only almost all of the mechanics we sell or have sold previously, it also tests most (very nearly all) of the competing products that we service. I simply connect up using an appropriate adapter cable and switch on - having selected a power supply of an appropriate voltage. The unit detects the type of mechanics fitted by testing the the operation of the switches in a particular sequence. By building a table of how the switches move under certain movements it then determines how to move the various types of mechanics in the "correct" sequence. After that, an automatic burn in test can be performed, testing the entire system repeatedly for as long as required to either prove the unit working following a repair, or to try to induce any intermittent faults that may be present. It does all of this with no intervention, allowing me to get on with something else. This means I can be doing two things at once, doubling my work rate!

     

    Last edit: mkstevo 2020-08-13
  • stan cartwright

    stan cartwright - 2020-08-14

    Hi Sir. I worked in the arcade games industry in the late 70's but trade died off in the 80's due to home "computers" so the company switched to making gambling machines.
    These poker game machines were sent to southern Ireland and because of gambling laws,
    did not pay out winnings in cash. It displayed on the screen "For Amusement Only".
    Apparently if you won you told the bar staff who had a key to reset the machine and they paid you in cash...that's what the factory owner told me.

    As for interrupts.. like many gcb things, they can seem deep and mysterious..and still are to me
    but I think worth trying to grasp.

    As for solenoids, I bought a 12V solenoid water/air valve but trouble driving it with pwm.
    Maybe it is just to slow to respond.

     

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.