News:

;) This forum is the property of Proton software developers

Main Menu

10 Bit Resolution PIC16F684

Started by Abdullah, Apr 07, 2026, 09:11 AM

Previous topic - Next topic

Abdullah

HI everyone
I have a question.
Can the PWM resolution of the PIC16F684 be used at a higher bit resolution when using a 20MHz crystal?
Normally the duty cycle operates in 8-bit resolution (0 to 255).
I it possible to convert or extend this to a range of 0 to 1024 (i.e.,10-bit resolution)?
Abdullah

Pepe

#1
demo proteus 10 bits pwm


Device = 16F684
Config FOSC_HS, WDTE_OFF, PWRTE_OFF, PWRTE_OFF, MCLRE_OFF, CP_OFF, CPD_OFF, BOREN_OFF
Declare Xtal = 20
Declare Create_Coff On
Declare Optimiser_Level 3
Declare Watchdog Off
Declare Adin_Res 10
Declare Adin_Tad FRC
Declare Adin_Stime 50
TRISA = %00000001        ' RA0 = ADC input
TRISC = %11011111        ' RC5 = PWM output
ANSEL  = %00000001       ' AN0 enabled only
ADCON0.7 = 1            '
PR2 = 255                 '
T2CON = %00000100        ' Timer2 ON, prescaler 1
CCP1CON = %00001100      ' CCP1 PWM mode

Dim adc_val As Word
Dim duty    As Word
Dim dutya    As Word

Do
    duty = ADIn 0
   
    If dutya<>duty Then
                       dutya=duty
                       CCP1CON.4 = duty.0 
                       CCP1CON.5 = duty.1
                       CCPR1L = duty >> 2
                       DelayUS 100
     EndIf
Loop

top204

#2
The HPWM command, uses an 8-bit duty cycle value as a set scale, because the resolution of a PWM depends on its frequency. So the HPWM command allows different frequencies, and a set duty to match them. It calculates what value is required for the duty, with the frequency chosen.

However, if 10-bit resolution is always required, the frequency of the PWM waveform cannot be changed, but it does make things a little simpler.

Below is a code template to operate the PWM waveform with a 10-bit resolution:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Setup a PIC16F684 device to operate at 20MHz using an external crystal or resonator,
' and write a 10-bit duty cycle value to the CCP peripheral operating as PWM.
'
' Written for the Positron8 BASIC Compiler by Les Johnson.
'
    Device = 16F684                                 ' Tell the compiler what device is being compiled for
    Declare Xtal = 20                               ' Tell the compiler what speed the device will be operating at (in MHz)
    Declare Optimiser_Level = 2                     ' Set the optimiser to level 2
    Declare Dead_Code_Remove = 1                    ' Remove Dead Code for extra optimising
'
' Setup RSout
'
    Declare Serial_Baud = 9600                      ' Baud rate of 9600
    Declare RSOut_Pin = PORTC.0                     ' Transmit from PORTC pin 0
    Declare RSOut_Mode = 0                          ' Inverted mode
'
' Create any global variables here
'
    Dim wDutyValue As Word                          ' Holds the 10-bit duty cycle value

'-----------------------------------------------------------------------
' The main program starts here
' Alter the 10-bit duty cycle of the PWM module, and Transmit the duty cycle value to a serial terminal.
'
Main:
    Setup()                                         ' Setup the program and any peripherals

    Do                                              ' Create a loop
        For wDutyValue = 0 to 1023 Step 10          ' Create a loop for the 10-bit duty cycle
            Analog1_Write10(wDutyValue)             ' Write the 10-bit duty cycle to the PWM
            RSoutLn Dec wDutyValue                  ' Transmit wDutyValue to a serial terminal, as an ASCII decimal value
            DelayMs 100                             ' Delay so the duty cycle can be seen changing
        Next                                        ' Close the duty cycle loop
    Loop                                            ' Do it forever

'-----------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
     Analog1_Open10()                               ' Configure the CCP1 peripheral as PWM with a resolution of 10-bits (0 - 1023)
EndProc

'-----------------------------------------------------------------------
' Write a 10-bit duty cycle value to the CCP peripheral operating as PWM
' Input     : pDuty holds the 10-bit duty cycle (0 to 1023)
' Output    : None
' Notes     : None
'
Proc Analog1_Write10(pDuty As Word)
    Dim bTemp As Byte

    CCP1CON = CCP1CON & %11001111
    bTemp = pDuty << 4
    bTemp = bTemp & %00110000
    CCP1CON = CCP1CON | bTemp
    CCPR1L = pDuty >> 2
EndProc

'-----------------------------------------------------------------------
' Configure the CCP1 peripheral as PWM with a resolution of 10-bits (0 - 1023)
' Input     : None
' Output    : None
' Notes     : When the PIC device is operating at 20MHz, the PWM waveform will be at 19.53KHz
'
Proc Analog1_Open10()
    T2CON = %00000100               ' Turn on Timer2 with a Prescaler value of 1:1
    PR2 = 255                       ' Set PWM resolution to 10-bits
    CCPR1L = 0                      ' \
    CCP1CON = %00001100             ' / Turn on PWM by setting bits 2 and 3 of CCP1CON    
    PinOutput PORTC.5               ' Enable the PWM output pin
EndProc

'---------------------------------------------------------
' Turn off the PWM peripheral by clearing CCP1CON
' Input     : None
' Output    : None
' Notes     : Also disable the PWM output pin
'
Proc Analog1_Close()
    CCP1CON = 0
    PinInput PORTC.5
EndProc

'-------------------------------------------------------------------
' Setup the config fuses for an external crystal on a PIC16F684 device
'
    Config HS_OSC,_
           WDTE_OFF,_
           PWRTE_OFF,_
           MCLRE_OFF,_
           CP_OFF,_
           CPD_OFF,_
           BOREN_OFF,_
           IESO_OFF,_
           FCMEN_OFF

When the PIC device is operating at 20MHz, the PWM waveform will be at 19.53KHz for a 10-bit resolution.

Regards
Les

Abdullah

Quote from: top204 on Today at 08:35 AMThe HPWM command, uses an 8-bit duty cycle value as a set scale, because the resolution of a PWM, depends on its frequency, so the HPWM command allows different frequencies, and a set duty to match them. It calculates what value is required for the duty, with the frequency chosen.

However, if 10-bit resolution is always required, the frequency of the PWM waveform cannot be changed, but it does make things a little simpler.

Below is a code template to operate the PWM waveform with a 10-bit resolution:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Setup a PIC16F684 device to operate at 20MHz using an external crystal or resonator,
' and write a 10-bit duty cycle value to the CCP peripheral operating as PWM.
'
' Written for the Positron8 BASIC Compiler by Les Johnson.
'
    Device = 16F684                                 ' Tell the compiler what device is being compiled for
    Declare Xtal = 20                               ' Tell the compiler what speed the device will be operating at (in MHz)
    Declare Optimiser_Level = 2                     ' Set the optimiser to level 2
    Declare Dead_Code_Remove = 1                    ' Remove Dead Code for extra optimising
'
' Setup RSout
'
    Declare Serial_Baud = 9600                      ' Baud rate of 9600
    Declare RSOut_Pin = PORTC.0                     ' Transmit from PORTC pin 0
    Declare RSOut_Mode = 0                          ' Inverted mode
'
' Create any global variables here
'
    Dim wDutyValue As Word                          ' Holds the 10-bit duty cycle value

'-----------------------------------------------------------------------
' The main program starts here
' Alter the 10-bit duty cycle of the PWM module, and Transmit the duty cycle value to a serial terminal.
'
Main:
    Setup()                                         ' Setup the program and any peripherals

    Do                                              ' Create a loop
        For wDutyValue = 0 to 1023 Step 10          ' Create a loop for the 10-bit duty cycle
            Analog1_Write10(wDutyValue)             ' Write the 10-bit duty cycle to the PWM
            RSoutLn Dec wDutyValue                  ' Transmit the wDutyValue value to a serial terminal
            DelayMs 100                             ' Delay so the duty cycle can be seen changing
        Next                                        ' Close the duty cycle loop
    Loop                                            ' Do it forever

'-----------------------------------------------------------------------
' Setup the program and any peripherals
' Input     : None
' Output    : None
' Notes     : None
'
Proc Setup()
     Analog1_Open10()                               ' Configure the CCP1 peripheral as PWM with a resolution of 10-bits (0 - 1023)
EndProc

'-----------------------------------------------------------------------
' Write a 10-bit duty cycle value to the CCP peripheral operating at PWM
' Input     : pDuty holds the 10-bit duty cycle
' Output    : None
' Notes     : None
'
Proc Analog1_Write10(pDuty As Word)
    Dim bTemp As Byte

    CCP1CON = CCP1CON & %11001111
    bTemp = pDuty << 4
    bTemp = bTemp & %00110000
    CCP1CON = CCP1CON | bTemp
    CCPR1L = pDuty >> 2
EndProc

'-----------------------------------------------------------------------
' Configure the CCP1 peripheral as PWM with a resolution of 10-bits (0 - 1023)
' Input     : None
' Output    : None
' Notes     : When the PIC device is operating at 20MHz, the PWM waveform will be at 19.53KHz
'
Proc Analog1_Open10()
    T2CON = %00000100               ' Turn on Timer2 with a Prescaler value of 1:1
    PR2 = 255                       ' Set PWM resolution to 10-bits
    CCPR1L = 0                      ' \
    CCP1CON = %00001100             ' / Turn on PWM Module 1 by setting bits 2 and 3 of CCP1CON     
    PinOutput PORTC.5               ' Enable the PWM1 output pin
EndProc

'---------------------------------------------------------
' Turn off the PWM1 peripheral by clearing CCP1CON
' Input     : None
' Output    : None
' Notes     : Also disable the PWM1 output pin
'
Proc Analog1_Close()
    CCP1CON = 0
    PinInput PORTC.5
EndProc

'-------------------------------------------------------------------
' Setup the config fuses for an external crystal on a PIC16F684 device
'
    Config HS_OSC,_
           WDTE_OFF,_
           PWRTE_OFF,_
           MCLRE_OFF,_
           CP_OFF,_
           CPD_OFF,_
           BOREN_OFF,_
           IESO_OFF,_
           FCMEN_OFF

When the PIC device is operating at 20MHz, the PWM waveform will be at 19.53KHz for a 10-bit resolution.

Regards
Les

Many thanks Sir Les and sir Pepe
Abdullah

Abdullah

hello
what is the deference this
CCPR1L = duty >> 2
    CCP1CON.5 = duty.1
    CCP1CON.4 = duty.0
and this
Dim bTemp As Byte

    CCP1CON = CCP1CON & %11001111
    bTemp = pDuty << 4
    bTemp = bTemp & %00110000
    CCP1CON = CCP1CON | bTemp
    CCPR1L = pDuty >> 2
Abdullah

Pepe

The difference is that in the second case the bits are assigned to the register at the same time, whereas in the first case less code is used but the bits are assigned in two cycle times.