PWM with PIC16F84A?

Thread Starter

detroit

Joined Mar 13, 2014
5
I'm new to this forum so hello to everyone.

How I got here:
I am working on PIC16F84A to generate a PWM signal where gradually increases and decreases the brightens of an LED in assembly ( maybe C if too hard) depending on 3 DIP switch input

1. I am having a hard time grasping the idea around timer, prescaler and interrupt. Reading I think I have to implement this in the code to get the desired result. Not sure how...

2. Do I have to use an outside oscillator or use the RC method only?

3. I have created where I can use the switch to turn on and of.. ( that is as far I have gotten)

I would like some help in pointing me in the right direction.

Thank you for your help in advance
 

mcgyvr

Joined Oct 15, 2009
5,394
There are NUMEROUS tutorials on the internet to generate a PWM signal with a PIC..
google "PIC16F84A PWM" and have fun :)
 

Thread Starter

detroit

Joined Mar 13, 2014
5
Thanks for the quick reply mcgyvr,

I have probably read 99 % of them, and yet did not come across any that clarify how the prescaler is implemented with timer to control the duty cycle ( 0%, 50% ...)

If you can suggest a good site or maybe take some of your time to explain it it would be greatly appreciated.

thanks
 

BobTPH

Joined Jun 5, 2013
11,643
The timer on the PIC16F84A does not have a controllable duty cycle. Use a PIC with a PWM module, such as the 16F628.

If you must use that PIC, you will have to control the on and off time separately by software, using either the timer or a program delay loop.


Bob
 

Thread Starter

detroit

Joined Mar 13, 2014
5
Thanks Bob for your time,

I have to use PIC16F84A, and from the reading that I have done i have concluded that I need both the timer and delay implemented in the code.
Can you please break each of them down.
I have done normal delay where its on and off.
Timer part I am straight lost....

Thanks
 

BobTPH

Joined Jun 5, 2013
11,643
Example for PWM with 1ms period.

1. Calculate the on time base on period and duty cycle:

on_time = 1ms * duty;

2. Set a pin to high.
3. Wait for the on time
4. Set the pin to low
5. Wait for the off_time = period - on_time
6. goto 2;

Bob
 

Thread Starter

detroit

Joined Mar 13, 2014
5
Thanks again, but I still am confused (do apologize just trying to grasp the logic)

So I would like to read 3 switches each one has a duty cycle.
So how do I implement the PWM method in the below code that I have done so far.
PLEASE Keep in mind I am at work therefore the code is close to what I have done at home.

Rich (BB code):
    ;include the header file

    __CONFIG  0X3FF2       ; i think I am missing something here ????     

    ORG        0X0000
    GOTO    START        

    ORG        0X0004
    RETFIE

START

    BSF        STATUS,RP0    ;Shift to bank 1 
    MOVLW    0XF0
    MOVWF    TRISB        ;Set RB0,RB1,RB2,RB3 as outputs
    BCF        STATUS,RP0    ;Shift to bank 0


LOOP

    CLRF    TEMPB

    BTFSC    PORTB,7        ;Check Switch 1
    CALL    S1        ;Call switch1 subroutine if switch is on
    BTFSC    PORTB,6        ;Check Switch 2
    CALL    S2        ;Call switch1 subroutine if switch is on
    BTFSC    PORTB,5        ;Check Switch 3
    CALL    S3        ;Call switch1 subroutine if switch is on

    MOVF    TEMPB,W        ; to the PORTA and PORTB registers to display
    MOVWF    PORTB        ; on the LEDs

    GOTO    LOOP    ;Return to top of loop

S1
; Turns on LED 1-4 at(would like @ 25% duty cycle)
; Not sure how to implement the logic in here
    MOVLW    0X0F        ;0000 1111 on PORTA
    IORWF    TEMPB,F
    RETURN

S2
; Turns on LED 1-4 (would like @ 50% duty cycle)
; Not sure how to implement the logic in here
    MOVLW    0X0F        ;0000 1111 on PORTA
    IORWF    TEMPB,F
    RETURN


S3
; Turns on LED 1-4 (would like @ 100% duty cycle)
; Not sure how to implement the logic in here
    MOVLW    0X0F        ;0000 1111 on PORTA
    IORWF    TEMPB,F
    RETURN

; And havent gone further for the reverse process, 
;as I would like to solve the above first

    END
Again thanks for your help is greatly appreciated...
 

Thread Starter

detroit

Joined Mar 13, 2014
5
So I would like to use the delay method, however I do not know how to use the timer as a counter.

I need to clear timer, for me to use it as a counter.
clear watch time dog.
and select a prescaler.

can someone provide a sample code in assembly how this would be done, no it is not making me lazy.
Just that I know I will understand it better.

Thanks
 

Ian Rogers

Joined Dec 12, 2012
1,136
Do you not want to use an interrupt on the timer? It makes PWM generation so much easier..

If you require two PWM outputs.

Set up two compare variables pwm1 and pwm2.
Set the timer on... and switch both outputs on.
Compare pwm1 against timer, if timer is bigger switch off the output pin.
Compare pwm2 against timer, if timer is bigger switch off the output pin.
If the timer spills over set both outputs high again...

If you put all the above in an interrupt all you need to do is adjust the two variables pwm1 and pwm2...
 

Ian Rogers

Joined Dec 12, 2012
1,136
Look at this code... Its yours with a 4 pwm outputs at 5 bits precision... Only 200hz, but enough for LED's..

Rich (BB code):
;include the header file

pwm1	equ	20h	; pwm1 variable
pwm2	equ	21h	; pwm2 variable
pwm3	equ	22h	; pwm3 variable
pwm4	equ	23h	; pwm4 variable
Period	equ	24h	; pwm period
Pcount	equ	25h	; period counter
Wsav	equ	26h	; save w reg
Ssav	equ	27h	; save status reg
TEMPB	equ	28h

	list	 p=16f84a
	#include p16f84a.inc

	__CONFIG  0X3FF2       ; i think I am missing something here ????     
	

	ORG	0X0000
	GOTO    START        

	ORG	0X0004
	goto	ISR		; goto ISR routine

START
	BSF	STATUS,RP0	;Shift to bank 1 
	movlw 	b'00001000'	; fast as possible
	movwf	OPTION_REG
	MOVLW	0XF0
	MOVWF	TRISA		;Set RA0,RA1,RA2,RA3 as outputs
	BCF	STATUS,RP0	;Shift to bank 0
	movlw	b'10100000'	; timer on
	movwf	INTCON
	movlw	032h		; set period
	movwf	Period		; pwm cannot go past this
	movlw	0BfH       ; This defines the speed of the interrupt...
	movwf	TMR0
	movlw	16h
	movwf	pwm1
	movwf	pwm2
	movwf	pwm3	
	movwf	pwm4

LOOP

	BTFSC	PORTB,7		;Check Switch 1
	CALL	S1		;Call switch1 subroutine if switch is on
	BTFSC	PORTB,6		;Check Switch 2
	CALL    S2		;Call switch1 subroutine if switch is on
	BTFSC	PORTB,5		;Check Switch 3
	CALL    S3		;Call switch1 subroutine if switch is on

	GOTO	LOOP		;Return to top of loop

S1
; Turns on LED 1-4 at(would like @ 25% duty cycle)
; Not sure how to implement the logic in here
	movlw	8h
	movwf	pwm1
	movwf	pwm2
	movwf	pwm3	
	movwf	pwm4
	RETURN

S2
; Turns on LED 1-4 (would like @ 50% duty cycle)
; Not sure how to implement the logic in here
	movlw	16h
	movwf	pwm1
	movwf	pwm2
	movwf	pwm3	
	movwf	pwm4
	RETURN


S3
; Turns on LED 1-4 (would like @ 100% duty cycle)
; Not sure how to implement the logic in here
	movlw	32h
	movwf	pwm1
	movwf	pwm2
	movwf	pwm3	
	movwf	pwm4
	RETURN

; And havent gone further for the reverse process, 
;as I would like to solve the above first

ISR
	movwf	Wsav
	movf	STATUS,w
	movwf	Ssav		; save registers
	incf	Pcount,f	; preriod timer
	
	movf	pwm1,w		; Check pwm 1
	subwf	Pcount,w	
	btfsc	STATUS,C
	bcf	PORTA,0

	movf	pwm2,w		; check pwm 2
	subwf	Pcount,w
	btfsc	STATUS,C
	bcf	PORTA,1

	movf	pwm3,w		; check pwm 3
	subwf	Pcount,w	
	btfsc	STATUS,C
	bcf	PORTA,2

	movf	pwm4,w		; check pwm 4
	subwf	Pcount,w	
	btfsc	STATUS,C
	bcf	PORTA,3

	movf	Period,w	; check period
	subwf	Pcount,w
	btfss	STATUS,C
	goto	noclear
	movlw	0fh
	movwf	PORTA
	clrf	Pcount

noclear:
	bcf	INTCON,T0IF
	movlw	0BfH
	movwf	TMR0
	
	movf	Ssav,w
	movwf	STATUS
	swapf	Wsav,w
	retfie

    END
It uses interrupts so I hope you get the idea...
 
Top