News:

Let's find out together what makes a PIC Tick!

Main Menu

Low PWM Frequency

Started by hobbyelectronics, Jan 24, 2023, 11:01 AM

Previous topic - Next topic

hobbyelectronics

Hello everyone.

I need to generate PWM signal with a frequency of 90 Hz and a duty cycle between 1 and 100% in 1% steps.
Looking at the proton manual, using the PIC hardware PWM module would not go down to 90 Hz, and depending on the PIC clock frequency the lowest would be 145 Hz with a 4 MHz clock.

Is that right? I am surprised these cannot go lower. Looking at the various PIC data sheets it would seem this is the case, with setting the various PWM / timer related registers.
For example using a RPi Pico the PWM frequency range is between 7 Hz and 125 MHz, so I am missing something here.
Maybe scaling down the PWM module clock or some other method would change the frequency range?

I need to run the PIC at 16 MHz or higher if possible.
I have searched around for possible solutions but came up blank.....

Any ideas?

Thank you

Paul

See_Mos

Hi Paul, welcome to the forum.

There is a program in the samples folder for slow PWM.  Also if you search this forum for slow PWM then about hit #12 is some other code that I posted that goes much lower than you need.

What device are you using?

top204

Take a look in the compiler's "C:\Users\User Name\PDS\Samples\New Samples" folder for: "PWM RGB LEDs.bas" or "Software_Multi_PWM.bas" or "Slow_PWM_Interrupt_Driven.bas".

These all use an interrupt to create software PWM signals that can go very slow indeed.

See_Mos

Les always comes up with better coding than I do but if you want to play with my code here it is modifies for 90Hz 100 steps when XTAL = 16

' Simple slow PWM using timer interrupts

' multiply the output frequency by the number of steps (ticks) required.
' 10Hz * 1000 = interrupt frequency of 10KHz
' 15Hz * 255 = interrupt frequency of 3825 Hz
' need to calculate prescaler and preload values instead of using PIC Multi_Calc
' or Microelektronika calculator

' -----------------------------------------------------------------------------
' INC files now include 100mS start delay, CLS and display XTAL speed on LCD
' -----------------------------------------------------------------------------
$define _LCD_PORT_ 1                    ' LCD PortA = 0, PortB = 1, PortC = 2
                                        ' 3 = custom or no LCD

'Include "25K22_8.inc"
Include "18F25K22 Intosc 16.inc"

Dim T1 As Word                          ' maximum number of ticks
Dim T2 As Word                          ' high time in ticks
Dim T3 As Word                          ' ticks counter
Dim Timer1_Reg As TMR1L.Word             ' Alias to TMR1H and TMR1L
Dim Timer1_Val As Word

'Symbol TMR1IF = PIR1.0                  ' TMR1 Overflow Interrupt Flag bit

On_Hardware_Interrupt GoTo Hardware_Int
GoTo Start

Hardware_Int:
    Context Save
      If TMR1IF  = True Then
        Timer1_Reg = Timer1_Reg + Timer1_Val    ' Reload timer 1
        TMR1IF = 0
        Inc T3                                  ' ticks counter
        If T3 >= T1 Then T3 = 0                 ' zero if count > 1000

        If T3 < T2 Then                         ' high time
            LATB.1 = 1                          ' PWM Output pin
        Else                                    ' low time
            LATB.1 = 0
        End If
      EndIf

   PIR1.0 = 0                                   ' Clear the interrupt flag
   Context Restore
'--------------------------------- End of interrupt code  ----------------------

Start:
    T1 = 100                                    ' maximum number of steps
    T2 = 25                                     ' high time test values
    T3 = 0                                      ' zero the ticks counter
'--------------------------------- interrupt setup ----------------------------
' -------------------------------Values for 8MHz clock ------------------------
'    Timer1_Val = $FCF3                        ' value for 256 steps at 10Hz
'    Timer1_Val = $FCF0                        ' value for 255 steps at 10Hz
'    Timer1_Val = $FDF5                       ' value for 255 steps at 15Hz
'    Timer1_Val = $FF38                       ' value for 10KHz, output = 10Hz
'    Timer1_Val = $FF7B                       ' value for 15KHz, output = 15Hz
'    Timer1_Val = $FF9C                       ' value for 20KHz, output = 20Hz
'    Timer1_Val = $FFA9                       ' value for  90Hz 256 steps
'    Timer1_Val = $FFEA                       ' value for  90Hz 1000 steps
' -------------------------------Values for 16MHz clock ------------------------
    Timer1_Val = $FE44                       ' value for  90Hz 100 steps


    Timer1_Reg = Timer1_Val

    IPR1  = 128                             ' set interrupt priorities
    IPR2  = 0                               ' low
    PIR1.0 = 0                              ' Clear Timer 1 interrupt flag
    PIE1.0 = 1                              ' Enable timer 1 interrupt
    T1CON = 1                               ' Turn on Timer 1
    INTCON =  $C0                           ' Enable interrupts
'--------------------------------- End of interrupt setup ----------------------

    TRISB = 0
    While 1 = 1 : Wend