generate PWM in pic 16F876

Thread Starter


Joined Nov 30, 2009
i'm trying to generate PWM sginal in pic16F876 using CCP1 module.
i read a variable resistor via AN0 and based on this value i configure my PWM duty cycle (high level). everything works just fine in Mplab and proteus VSM,but the CCP1/RC2 pin stay in 0 level...
here is the full code,all the comments are in french, sorry

can you please give a quick look to my code and help me.
Rich (BB code):
    LIST     p=16F876
    #include <>

OPTIONVAL     EQU    B'10000000'    ;B'10000111'
INTCONVAL    EQU    B'01000000'
DIRPORTA    EQU    B'00000001'    ; AN0 =entree, le rest sont des sorties
DIRPORTC    EQU    B'00000000'
PIE1VAL        EQU    B'01000010'
T2CONVAL    EQU B'00000011'
CCP1CONVAL    EQU    B'00001100'
ADCON0VAL    EQU B'10000000'
ADCON1VAL    EQU    B'00001110'
tempoval    EQU    D'35'
PR2VAL        EQU H'FF'

BANK0    macro        ; passer en banque 0
        bcf STATUS,RP0
        bcf    STATUS,RP1
BANK1    macro        ;passer en banque 1
        bsf STATUS,RP0
        bcf STATUS,RP1
BANK2    macro        ;passer en banque 2
        bcf STATUS,RP0
        bsf STATUS,RP1
BANK3    macro        ;passer en banque 3
        bsf STATUS,RP0
        bsf STATUS,RP1
;---------zone de BANK0
    CBLOCK    0x20
;--------zone commune----------------------------
    CBLOCK 0x70
    tempo : 1
;-----------------------DEMARRAGE DU RESET------------
    org 0x000
    goto init
    org 0x0004
    bsf        STATUS,RP0
    btfss    PIE1,ADIE    ;sauter si l'int AD est autorise
    goto    int_test1    ;no! aller au teste suivant
    bcf        STATUS,RP0
    btfsc    PIR1,ADIF    ;sauter si le flage est 0
    call    int_AD        ;flag=0! traiter cette interruption
    goto    int_test1
;-------------interruption timer2-----------
    bsf        STATUS,RP0
    btfss    PIE1,TMR2IE    ;sauter si l'int TMR2 est autorisee
    goto    restoreg    ;no fin d'int
    bcf        STATUS,RP0    ;banque 0    
    btfsc    PIR1,TMR2IF    ;flag positione ! traiter l'int
    call    int_TMR2
    goto    restoreg

    retfie                      ; return from interrupt

;---------interruption timer2------------
    bcf        PIR1,TMR2IF        ;effacer le flage de timer2
    bsf        ADCON0,ADON        ;lancer l'aquisition AD
    bsf        PORTC,5
wait20us                        ;routine de 20 us
    ;movf    tempo,f
    decfsz    tempo,f
    goto     wait20us
    movlw    tempoval
    movwf    tempo
    bsf        ADCON0,GO        ;lancer la conversion AD

;----------interruption convAD-----------
    bsf        PORTC,5
    bcf     ADCON0,ADON
    bcf        PIR1,ADIF
    movf    ADRESH,w
    movwf    CCPR1L
    bsf        STATUS,RP0    ;banque 1
    btfss    ADRESL,7
    goto     next_test
    bcf        STATUS,RP0
    bsf        CCP1CON,CCP1X
    bsf        STATUS,RP0
    btfss    ADRESL,6
    bcf        STATUS,RP0
    bsf        ADRESL,CCP1Y
    clrf    PORTA        ;effacer porta
    clrf    PORTC        ;effacer portc
    movlw    INTCONVAL    ;autorisation de l'int periphirique
    movwf    INTCON    
    movlw    T2CONVAL    ;prediviseur=16,
    movwf    T2CON        
    movlw    CCP1CONVAL    ; en mode PWM
    movwf    CCP1CON        
    movlw    ADCON0VAL    ;frequence de osc =32
    movwf    ADCON0
    clrf    ADRESH
    bsf        STATUS,RP0        ; sélectionner banque1
    clrf    ADRESL
    movlw    OPTIONVAL        
    movwf    OPTION_REG
    movlw   DIRPORTA        ;AN0 entree
    movwf    TRISA            
    movlw   DIRPORTC        ;CCP1/RC2 sortie
    movwf    TRISC
    movlw   ADCON1VAL        ;justification a gauche
    movwf    ADCON1            ;1 entree analogique 
    movlw    PR2VAL            ;charger PR2 avec H'FF' 
    movwf    PR2
    movlw    PIE1VAL            ;masque int AD=1,masque int TMR2=1
    movwf    PIE1
    bcf        STATUS,RP0        ;banque 0
    clrf     TMR2            ;effacer timer 2
    clrf    PIR1            ;effacer flags 
    bsf        INTCON,GIE        ;valider interruptions
    movlw    tempoval        ;pour la routine de 20 us
    movwf    tempo
    bsf        T2CON,TMR2ON    ;demarer timer2
    goto    start            
;-----------------------program principale----------------------------
    goto start


Joined Sep 7, 2009
I haven't looked at the code but could you describe (or post schematic) of how the analog input variable resistor is connected?


Joined Sep 7, 2009
Not sure if this helps at all, but it is fully working and tested code for the pic16F628a.
It is from when I was testing PWM. All it does is polls 10 pins with switches. All are pulled high by either internal pullups or resistors and the switches pull the pins low.
Maybe you could compare with your code and see what the differences are.
Rich (BB code):
    list      p=16f628a            ; list directive to define processor
    #include <>        ; processor specific variable definitions

w_temp        EQU     0x70        ; variable used for context saving 
status_temp   EQU     0x71        ; variable used for context saving

    cblock 0x20

        ORG     0x000             ; processor reset vector
        goto    init              ; go to beginning of program

        ORG     0x004             ; interrupt vector location
        movwf   w_temp            ; save off current W register contents
        movf    STATUS,w          ; move status register into W register
        movwf    status_temp       ; save off contents of STATUS register

; isr code can go here or be located as a call subroutine elsewhere

        movf    status_temp,w     ; retrieve copy of STATUS register
        movwf    STATUS            ; restore pre-isr STATUS register contents
        swapf   w_temp,f
        swapf   w_temp,w          ; restore pre-isr W register contents
        retfie                    ; return from interrupt

    movlw B'00000111'
    movwf CMCON                ;comparitors off    
    movlw B'00000100'
    movwf T1CON                ;enable timer1 internal no prescaler 
    BSF STATUS, RP0 ; Bank 1
;    bsf PIE1, 0                ;timer1 int enabled
;    BSF STATUS, RP0 ; Bank 1    
    clrf   OPTION_REG      ; weak pull ups
    bcf     STATUS, RP0    ; bank 0    
    movlw   B'01001000'     ; enable timer 1 interrupt and gpio change (not GIE yet)
    movwf   INTCON          ;  
    CLRF TMR1L                 ; Clear Low byte, Ensures no rollover into TMR1H
    clrf TMR1H
;    CLRF GPIO                 ; Initialize GPIO by
                            ; clearing output
                            ; data latches
    BSF STATUS, RP0         ; Select Bank 1
    movlw 0xFF
    movwf PR2                ;PWM setting
    MOVLW B'11000011'         
    MOVWF TRISA             ; Set RA<1:0 and 7:6> as input all others out
    MOVLW B'11110111'         
    MOVWF TRISB             ; Set all input except RB3 PWM out

    BCF STATUS, RP0         ;bank 0
    movlw B'00000100'        
    movwf T2CON                ;timer 2 on, no prescaler or postscaler
    movlw B'00001111'
    movwf CCP1CON
    movlw 0x04
    movwf CCPR1L
;    bsf INTCON, GIE            ;enable interrupts, then sleep

    bcf CCPR1Ltemp, 7
    btfss PORTA, 1
    bsf CCPR1Ltemp, 7
    bcf CCPR1Ltemp, 6
    btfss PORTA, 0
    bsf CCPR1Ltemp, 6
    bcf CCPR1Ltemp, 5
    btfss PORTB, 7
    bsf CCPR1Ltemp, 5
    bcf CCPR1Ltemp, 4
    btfss PORTB, 6
    bsf CCPR1Ltemp, 4
    bcf CCPR1Ltemp, 3
    btfss PORTB, 5
    bsf CCPR1Ltemp, 3
    bcf CCPR1Ltemp, 2
    btfss PORTB, 2
    bsf CCPR1Ltemp, 2
    bcf CCPR1Ltemp, 1
    btfss PORTB, 1
    bsf CCPR1Ltemp, 1
    bcf CCPR1Ltemp, 0
    btfss PORTB, 0
    bsf CCPR1Ltemp, 0
    movf CCP1CON, W            ;just in case
    movwf CCP1CONtemp
    bcf CCP1CONtemp, 5
    btfss PORTA, 7
    bsf CCP1CONtemp, 5
    bcf CCP1CONtemp, 4
    btfss PORTA, 6
    bsf CCP1CONtemp, 4
    movf CCP1CONtemp, W            
    movwf CCP1CON
    movf CCPR1Ltemp, W            
    movwf CCPR1L

    goto main

        END                       ; directive 'end of program'