Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

16F88 PWM and A/D conversion

Status
Not open for further replies.
Thanks Motion ..
I shall try that , after i repair the damage i did to the programmer last night ..
Not sure if i burnt the chip or wether i burnt the 74LS241 or one of the flip flops or wether i just need to work on the programming of the programmer ..something happened because it isnt working like it was ..bummer..
 
motion said:
I have used the PIC on a motor driver application in which the PWM duty cycle is a function of the ADC output and here are few tips I can give.

In your application as in mine, the A/D result is used to calculate the PWM duty. On the PWM module, the duty cycle can only change at timer2 overflow. In your case, it's at a 5Khz rate. This is regardless of how many times you load CCPR1L. Therefore, the 5Khz rate should dictate the rate you make A/D conversions and not the other way around (i.e., the A/D conversion rate dictating how fast you update CCPR1L).

A 5Khz A/D conversion rate is well within the limits of the PIC ADC. Selecting 8Tosc for Tad, the A/D conversion time is 12Tad or about 20usec. Since at 5Khz there is 200usec between A/D conversion intervals, there is 180usec of sampling time allowed.

All these is easily done if A/D conversion is synchronized with timer2 overflow. That is, you don't need to check the GO/DONE bit but instead poll the TMR2IF bit.

1. Poll the TMR2IF bit until it is set.
2. Clear TMR2IF bit.
3. Read the result from the previous A/D conversion and save result.
4. Use the A/D result to set the PWM duty.
5. Start a new conversion. This step can be done ahead of step 4.
6. Repeat step 1. While waiting for TMR2IF to be set in 200usec, the A/D conversion is completed after 20usec and the rest of the time is spent sampling.

BTW, you can also use interrupts here, using TMR2IF to initiate interrupt.
I cant wait to try this out.. i fixed the hardware of the programmer , now i am rewriting some the software..
 
Mike this code works on a F628 ,but not on an F88 why ??
What could be wrong ??


Code:
;****************************************************************** 

        org   0x0000 

RESET   clrf    STATUS          ;                                 |B0 
        clrf    PORTA           ; clear Port A data latches       |B0 
        clrf    PORTB           ; clear Port B data latches       |B0 
        movlw   h'07'           ;                                 |B0 
        movwf   CMCON           ; turn comparator off             |B0 
        bsf     STATUS,RP0      ; select bank 1                   |B1 
        clrf    TRISA           ; port A all outputs              |B1 
        clrf    TRISB           ; port B all outputs              |B1 
        bcf     STATUS,RP0      ; select bank 0                   |B0 
; 
;  setup PWM (looks like CCPR1L uses Tosc while PR2 uses Tcyc) 
; 
        clrf    T2CON           ; TMR2 prescale:1                 |B0 
        movlw   d'100'          ; same as (100*4)>>2              |B0 
        movwf   CCPR1L          ; 100 usecs, 50% duty cycle?      |B0 
        bsf     STATUS,RP0      ; select bank 1                   |B1 
        movlw   d'200'-1        ; 200 1.0 usec 'ticks'            |B1 
        movwf   PR2             ; Period=200 usecs, Freq=5.0 KHz  |B1 
        bcf     STATUS,RP0      ; select bank 0                   |B0 
        movlw   b'00001100'     ;                                 |B0 
        movwf   CCP1CON         ; put CCP module in PWM mode      |B0 
        bsf     T2CON,TMR2ON    ; turn on TMR2                    |B0 
; 
;  now test to see if the LED on RB3 is glowing at 50% brightness 
; 
LOOP    goto    LOOP            ; loop indefinately               |B0 
; 
;***************************************************************
 
Willi,

Are you sure it's not workin'? Are you checkin' the right pin? The CCP1 pwm output pin can be configured as RB0 or RB3 with a configuration bit setting... Have you taken a look at the Data Sheets?

I can take a closer look in awhile after finishing up a Flight Plan I'm workin' on...

Regards, Mike
 
Willi,

It works on my 20-MHz 16F88 proto' board and I only modified the file slightly... I added a clrf ANSEL instruction (bank 1) to turn off the ADC module, which shouldn't have affected PWM, and I modified T2CON for prescale=16 for this particular 20-MHz board and I also set PR2=100 for a 320-usec period (frequency = 3125-Hz)...

Good luck... Regards, Mike

<added>

If you omit the _CCP1_RB0 or _CCP1_RB3 setting in your config' line, the configuration will default to CCP1 on RB0...

Code:
        __CONFIG  _CONFIG1, _CCP1_RB0&_LVP_OFF&_PWRTE_ON&_WDT_OFF&_HS_OSC
        __CONFIG  _CONFIG2, _IESO_OFF & _FCMEN_OFF
 
Thank you !! to everyone who offered suggestions ..
The ADC section WORKS PERFECTLY
The PWM works from compleatly off to full on !!...amazing ..
Mike your code is flawless
thank you all again ..
 
Code:
results of my PWM LED test..
 i adjusted  the PWM to keep the current at 2mA...

Elapsed time /-/ Voltage on 2.2 F capacitance..

20 min             3.56 V     2mA
30 min             2.97 V     2mA
40 min             2.30 V     2mA
45 min             2.05 V     2mA
47 min             1.94 V     2mA
48 min             1.88 V     2mA
48 min 30 sec      1.83 V  1.8 mA
after 48 min 30 sec the caps ran out of power and i no longer could control the amount of current used by the LED ...
i used a rechargable battery was to boost the usable voltage from the caps. its voltage was not enough to power the LED by itself ..
i connected the PWM output from the PIC16F88 to the gate of a FET which was used to drive the LED circuit which had only a 1.0 ohms resistor....
i used a varible resistor connected to the ADC input of the PIC to control the current..
 
motion said:
.

All these is easily done if A/D conversion is synchronized with timer2 overflow. That is, you don't need to check the GO/DONE bit but instead poll the TMR2IF bit.

1. Poll the TMR2IF bit until it is set.
2. Clear TMR2IF bit.
3. Read the result from the previous A/D conversion and save result.
4. Use the A/D result to set the PWM duty.
5. Start a new conversion. This step can be done ahead of step 4.
6. Repeat step 1. While waiting for TMR2IF to be set in 200usec, the A/D conversion is completed after 20usec and the rest of the time is spent sampling.

BTW, you can also use interrupts here, using TMR2IF to initiate interrupt.
Could this be why i am getting intermittant blips in the PWM signal??..because i still havnt tried this yet..
what i have done with the PWM is
controlled a motor speed..
controlled the rate of discharge of current from the super caps to a pair of NiMH batteries..
I have also been able controll the cranking force of my hand generator, by adjusting the dutycycle ..
and of course my LEDs
i tell ya this Varible PWM is the greatest thing since sliced bread..
 
Could this be why i am getting intermittant blips in the PWM signal??..

The PWM duty is double-buffered and essentially glitch-free. I would suspect the A/D conversion part more than the PWM. It's hard to tell without knowing more details like your current source code.

i tell ya this Varible PWM is the greatest thing since sliced bread

Not exactly. However put in a low cost PIC, it did open a lot possibilities.
 
ok this is my PWM code which reads the ADC of the 16F88..
Notice that The list directive is for a F84, and the .inc file is commented out..
its a long story , but the short of it is i am running MPASM under dos on a different machine , the one with my programmer on it ..
anyway with the appropriate equates it really doesnt matter what is up at the top of the program..
so i listed all the equates that i needed..not all of the F88 equates though ..
oh the comments can be found on the preceding pages of this thread..


Code:
        LIST    P=16F84
      ;  include "P16F628A.inc"

			               
TEMP    EQU     0x0c
ADON    EQU     0X00
ADIF    EQU     0X06
GO_DONE EQU     0X02
TMR2ON  EQU     0X02
RP0     EQU     0x05
RP1     EQU     0x06
W                            EQU     H'0000'
F                            EQU     H'0001'

;----- Register Files------------------------------------------------------

INDF                         EQU     H'0000'
TMR0                         EQU     H'0001'
PCL                          EQU     H'0002'
STATUS                       EQU     H'0003'
FSR                          EQU     H'0004'
PORTA                        EQU     H'0005'
PORTB                        EQU     H'0006'
PCLATH                       EQU     H'000A'
INTCON                       EQU     H'000B'
PIR1                         EQU     H'000C'
PIR2                         EQU     H'000D'
TMR1L                        EQU     H'000E'
TMR1H                        EQU     H'000F'
T1CON                        EQU     H'0010'
TMR2                         EQU     H'0011'
T2CON                        EQU     H'0012'
CCPR1L                       EQU     H'0015'
CCPR1H                       EQU     H'0016'
CCP1CON                      EQU     H'0017'
RCSTA                        EQU     H'0018'
TXREG                        EQU     H'0019'
RCREG                        EQU     H'001A'
ADRESH                       EQU     H'001E'
ADCON0                       EQU     H'001F'

OPTION_REG                   EQU     H'0081'
TRISA                        EQU     H'0085'
TRISB                        EQU     H'0086'
PIE1                         EQU     H'008C'
PCON                         EQU     H'008E'
PR2                          EQU     H'0092'
TXSTA                        EQU     H'0098'
SPBRG                        EQU     H'0099'
EEDATA                       EQU     H'009A'
ANSEL                        EQU     H'009B'
CMCON                        EQU     H'009C'
EECON2                       EQU     H'009D'
ADRESL                       EQU     H'009E'
ADCON1                       EQU     H'009F'



        org     0x00                    
                                        ;this is where the program starts
        clrf    PORTA       
        clrf    PORTB
        CLRF    STATUS
        movlw   0x07
        movwf   CMCON
        bsf     STATUS ,RP0          ;bank 1
        CLRF    TRISA
        CLRF    TRISB
        BCF     STATUS ,RP0

        CLRF    T2CON
        MOVLW   D'000'
        MOVWF   CCPR1L
        BSF     STATUS,RP0
        MOVLW   d'255'-1
        MOVWF   PR2
        BCF     STATUS,RP0
        MOVLW   b'00001100'
        MOVWF   CCP1CON
        BSF     T2CON,TMR2ON

        BSF     STATUS,RP0
        MOVLW   b'00000001'
        MOVWF   TRISA
        MOVLW   b'00000001'
        MOVWF   ANSEL
        MOVLW   b'01000000'
        MOVWF   ADCON1
        BCF     STATUS,RP0
        MOVLW   b'01000000'
        MOVWF   ADCON0

LOOP    CALL    ADC
        MOVWF   CCPR1L
        GOTO    LOOP

ADC     BSF     ADCON0,ADON
        BCF     PIR1,ADIF
        MOVLW   d'13'
        MOVWF   TEMP
ACQ     DECFSZ  TEMP,F
        GOTO    ACQ
        BSF     ADCON0,GO_DONE
ADX     BTFSC   ADCON0,GO_DONE
        GOTO    ADX
        MOVF    ADRESH,W
        BCF     ADCON0,ADON
        RETURN


        end
 
I don't see anything wrong with the code. What I find unusual is the fact that you turn OFF the A/D converter at the end of each conversion. You don't save much power because only after usec later, you turn it back ON. In the meantime, power is disconnected to the ADC module and the sampling capacitor must charge from scratch.

I don't know exactly your application but if the analog signal is coming from a potentiometer, the wiper in motion could momentarily disconnect and you could have a high value reading.

Anyway, you can try my suggestion. I have modified the code to do so. It is really simpler than your code.

Code:
        LIST    P=16F88
      ;  include "P16F628A.inc" 

                         
TEMP    EQU     0x0c 
ADON    EQU     0X00 
ADIF    EQU     0X06
GO_DONE EQU     0X02
TMR2ON  EQU     0X02
TMR2IF  EQU     0X01
RP0     EQU     0x05
RP1     EQU     0x06
W                            EQU     H'0000'
F                            EQU     H'0001'

;----- Register Files------------------------------------------------------ 

INDF                         EQU     H'0000' 
TMR0                         EQU     H'0001' 
PCL                          EQU     H'0002'
STATUS                       EQU     H'0003'
FSR                          EQU     H'0004' 
PORTA                        EQU     H'0005'
PORTB                        EQU     H'0006' 
PCLATH                       EQU     H'000A' 
INTCON                       EQU     H'000B' 
PIR1                         EQU     H'000C'
PIR2                         EQU     H'000D' 
TMR1L                        EQU     H'000E'
TMR1H                        EQU     H'000F' 
T1CON                        EQU     H'0010' 
TMR2                         EQU     H'0011' 
T2CON                        EQU     H'0012' 
CCPR1L                       EQU     H'0015' 
CCPR1H                       EQU     H'0016'
CCP1CON                      EQU     H'0017'
RCSTA                        EQU     H'0018' 
TXREG                        EQU     H'0019' 
RCREG                        EQU     H'001A' 
ADRESH                       EQU     H'001E' 
ADCON0                       EQU     H'001F'

OPTION_REG                   EQU     H'0081'
TRISA                        EQU     H'0085' 
TRISB                        EQU     H'0086' 
PIE1                         EQU     H'008C' 
PCON                         EQU     H'008E' 
PR2                          EQU     H'0092' 
TXSTA                        EQU     H'0098'
SPBRG                        EQU     H'0099' 
EEDATA                       EQU     H'009A' 
ANSEL                        EQU     H'009B' 
CMCON                        EQU     H'009C' 
EECON2                       EQU     H'009D' 
ADRESL                       EQU     H'009E'
ADCON1                       EQU     H'009F'



        org     0x00
                                        ;this is where the program starts
        clrf    PORTA
        clrf    PORTB
        CLRF    STATUS
        BSF     STATUS ,RP0          ;bank 1. It should be ahead of CMCON
  ifdef __16F628A
        movlw   0x07
        movwf   CMCON
  endif
        CLRF    TRISA
        CLRF    TRISB
        BCF     STATUS ,RP0

        CLRF    T2CON
        MOVLW   D'000'
        MOVWF   CCPR1L
        BSF     STATUS,RP0
        MOVLW   d'255'-1
        MOVWF   PR2
        BCF     STATUS,RP0
        MOVLW   b'00001100'
        MOVWF   CCP1CON
        BSF     T2CON,TMR2ON

        BSF     STATUS,RP0
        MOVLW   b'00000001'
        MOVWF   TRISA
        MOVLW   b'00000001'
        MOVWF   ANSEL
        MOVLW   b'01000000'
        MOVWF   ADCON1
        BCF     STATUS,RP0
        MOVLW   b'01000000'
        MOVWF   ADCON0
        BSF     ADCON0,ADON
        CLRF    PIR1

LOOP    CALL    ADC
        MOVWF   CCPR1L
        GOTO    LOOP

ADC     BTFSS   PIR1,TMR2IF
        GOTO    ADC
        BCF     PIR1,TMR2IF

        MOVF    ADRESH,W
        BSF     ADCON0,GO_DONE
        RETURN

        END
 
thanks i'll try it , btw the blips i was getting were about one every second , but intermitently , hard to explain..
they were happening when the potentiometer wasnt moving..
question::
in this code below couldnt you just use one MovLW command ?
since w contains b'00000001' from the first load there really isnt a need to load it again ?since it allready contains 1.. unless it is just for clarity..
Code:
         BSF     STATUS,RP0 
        MOVLW   b'00000001' 
        MOVWF   TRISA 
        MOVWF   ANSEL

Code:
         BSF     STATUS,RP0 
        MOVLW   b'00000001' 
        MOVWF   TRISA 
        MOVLW   b'00000001' 
        MOVWF   ANSEL
 
Yes the first sample code is the same as the second. The W register does not lose its value after a MOVWF instruction.
 
Bump!

Just thought I would bring this old thread to light as I have a problem in this area.

I have a few questions that are all related.

I am using a PIC16F873A with a 4MHz resonator.

I am currently trying to use PWM to control a servo motor that requires approximately a 0.5-2ms pulse every 20ms. This would also require a resolution of at least 0.01ms.

What my problem is, is that I cannot seem to get the PWM going slowly enough for my purposes. I have fiddled with the prescalers and postscalers all day to no real avail. And, to be honest, with no real accuracy as I am a little unsure as to how best to calculate the required delay using the appropriate forumulas to equal the exact period required... :?

So my question is, can a 4MHz resonator provide a pulse this size and at the correct interval? I beleive the frequency is 50Hz for a 20ms period.

Is using a slower resonator a viable solution?

Any suggestions, pointers or code would be appreciated.

Thanks! :D

p.s. im a noob here :oops:

I have attached my code, but beware! it is VERY patchy as it is bodged together for testing pusposes. the comments are most likely wrong as i have been changing values left, right and center.
 

Attachments

  • pwmcode.txt
    8.6 KB · Views: 296
Status
Not open for further replies.

Latest threads

Back
Top