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.

PIC PWM outputs?

Status
Not open for further replies.

Andy1845c

Active Member
I have been googling for a while now, and I haven't been able to find what I am looking for.

What is a PWM output on a PIC? I assume any pic can do PWM, but one with a PWM output makes it easier?

I am looking for a a program to simply fade one I/O port on and off gently. I want to use it to control christmas lights and as a starting point in learning to use PWM.

I don't need it to be adjustible after programming (would be fun to add in the future though)

Is somthing like this somwhat simple, or does it take a fair amount of programming know how to make work? Maybe over my head at the moment?:eek:

All I have been able to find for the most part are motor contollers and color wash codes. And some are in C or Basic, and I only have a basic beginner knowledge of ASM.

Anyone have any advice or know where I could find a very basic PWM program to play with?
 
Andy1845c said:
Is somthing like this somwhat simple, or does it take a fair amount of programming know how to make work? Maybe over my head at the moment?:eek:
It's not too tough to do. Read the datasheet very carefully, as always, when setting something like this up.

Anyone have any advice or know where I could find a very basic PWM program to play with?
Here's my simple newbie PWM program for a 16F628:
Code:
	processor 16f628
	include "P16F628.inc"
	__config _HS_OSC & _WDT_OFF & _LVP_OFF

	cblock	0x20		;start of general purpose registers
	d1,d2,d3,count
	endc

	org		0x0000

init	clrf	count
	movlw	0x07			;turn comparators off
	movwf	CMCON
	bsf 	STATUS,RP0		;bank 1
	movlw	0x00			;all pins outputs
	movwf	TRISA
	movwf	TRISB
	movlw	0xff			;set period
	movwf	PR2
	bcf 	STATUS,RP0		;bank 0

main	movlw	0x80			;set duty cycle
	movwf	CCPR1L
	movlw	0x04			;set timer2 prescale and enable it
	movwf	T2CON
	movlw	0x0c			;set bottom 2 pwm bits and enable pwm
	movwf	CCP1CON
	call	delay

mloop	movf	count,w			;cycles msb 8 bits of pwm from 0 to 255
	movwf	CCPR1L			;over and over
	call	delay
	incfsz	count
	goto	mloop
reset	clrf	count
	goto	mloop	

delay	movlw	0x2d			;around 0.1 second or a bit less
	movwf	d1
	movlw	0xe7
	movwf	d2
	movlw	0x01
	movwf	d3
delay_0	decfsz	d1, f
	goto	dd2
	decfsz	d2, f
dd2	goto	dd3
	decfsz	d3, f
dd3	goto	delay_0
	return

	end
 
Last edited:
futz's example uses the pic's internal CCP module aka hardware pwm. If you have the budget, check out the 16F737 (or 767), they have three independent CCP modules, making it nice for rgb color mixing applications. hardware pwm also offers the benefit of freeing up the CPU and not using any interrupts, so your pic can do other stuff, not having to waste cycles on generating the pulse-train.

On the other hand, there are many asm examples out there for soft-pwm, where interrupts are used to generate a pulse-train. the advantage to soft-pwm is cheaper chips can be used, and you can get more pwm outputs. an inexpensive 12f683 has only one hard-pwm output, but can do five soft-pwm outputs.
 
Thanks for the replys. Right now I don't care how I accomplish the PWM, but its interesting to know there are two ways to go about it.

Will futz's code fade in and out, or just hold at a fixed duty cycle? I really need to spend some time learning ASM better.
 
Andy1845c said:
Will futz's code fade in and out, or just hold at a fixed duty cycle? I really need to spend some time learning ASM better.
It's just an example. You'd have to modify it to suit your purpose. It constantly varies the PWM duty cycle from 0 (off) to 255 (full on), over and over. Tis just a demo, not supposed to be useful.
 
Andy1845c said:
I am looking for a a program to simply fade one I/O port on and off gently. I want to use it to control christmas lights and as a starting point in learning to use PWM.

I don't need it to be adjustible after programming (would be fun to add in the future though)

Is somthing like this somwhat simple, or does it take a fair amount of programming know how to make work? Maybe over my head at the moment?:eek:

All I have been able to find for the most part are motor contollers and color wash codes. And some are in C or Basic, and I only have a basic beginner knowledge of ASM.


If all you want is just to fade one I/O port, you don't need to use PWM. You can simply just use a delay routine. Send the port pin high, delay for certain time and send the port pin low. Just refer to Nigel's tutorial, you'll find the answer you need. But whatever you do don't use Timer0, or you'll upset him badly. :D
 
Should futz's code actually output on a pin? RB3? I can't get it to work and can't get my head around how to PWM with a pic. I have been googling for over 2 hours and have seen all kinds of PWM programs, but most have more to them then just PWM and that confuses me.

Maybe i'm just jumping too far ahead. Nothing is making any sense:mad:
 
Andy1845c said:
.... I have been googling for over 2 hours and have seen all kinds of PWM programs, but most have more to them then just PWM and that confuses me.

I was teaching this in school today :)
PWM in its most simple (not confusing) form. This is C but the concept is the same in any language.

Untested off the top of the head sort of code follows....
Code:
int i;
int percent;
 
percent = 52;  //  % time on
while(1)   // loop forever
{
    for (i=0; i>100; i++)
    {
        if (i < percent)
        {
              ra0 = 1; // turn bit on
        }
        else
        {
             ra0 = 0; // turn bit off
        }
        delay_ms(1); //some sort of delay here, determines freq
}
 
-------------------- OR --------------------------
 
while(1) // loop forever
{
    ra0 = 1; // turn bit on
 
    for (i=0; i>100; i++)
    {
        if (i == percent)
        {
              ra0 = 0; // turn bit off
        }
        delay_ms(1); // some sort of delay here, determines freq
    }
}

You can use timers and other hardware to unload the processor but the above works.
 
Last edited:
Gayan Soyza said:
Here is another one done in 628

**broken link removed**

I tried this one, and couldn't get the led to do anything:confused: I think i need to back up and learn some basics before I attemp PWM.
 
I'm using the 16F628A. So futz's and Gayan's code should work. I'm not sure what I am doing wrong. I haven't tried Bill's code yet. I don't know if I have a 16F88 around or not.

I think i'm just trying to run before I can walk.
 
Ok. Are you using the 4 MHz internal oscillator? Do you have the LED connected to the RB3/CCP1 pin? If not, what pin(s)?
 
I am using _HS_OSC. Would that be correct?

I have the LED on RB3. I have tried both ways, but RB3 should be sourcing power, right?
 
bananasiong said:
Can you post up your program? futz's program should work. Or you can first try the fixed duty cycle.

Well, its pretty much exactly whats in the link Gayan posted

Code:
;=======pwm.ASM=================================15/11/06==
;     standard crystal 4.0MHz XT
;------------------------------------------------------------
;     configure programmer
 LIST P=16F628;f=inhx8m
 #include "P16F628.INC"  ; Include header file
 __CONFIG _PWRTE_ON  & _WDT_OFF & _HS_OSC & _BODEN_ON & _LVP_OFF & _CP_OFF & _MCLRE_OFF

; [URL="https://sandiding.tripod.com/Bertys.html"]https://sandiding.tripod.com/Bertys.html[/URL]
;------------------------------------------------------------
 cblock 0x20 ; Beginn General Purpose-Register
;-------------------------- counters 
 count1
 count2
 count3
;--------------------------
 endc
;--------------------------
#DEFINE pwmu PORTB,3
;--- Reset --------------------------------------------------
 org h'00'
 goto init  ; reset -> init
;--- Interrupt ----------------------------------------------
 org h'04'
;--------------------------
init clrf PORTA
 clrf PORTB
 movlw 0x07  ; Turn comparators off and enable pins for I/O 
 movwf CMCON 
 bcf STATUS,RP1
 call usi ; setari porturi
 call pause
 movlw 0xFF
 movwf PORTB
 call pause
 call set_timer
;-------------------------- asteapta puls de 1ms
uu 
 call pause
 movlw 0x02
 movwf CCPR1L
 call pause
 movlw 0x10
 movwf CCPR1L
 call pause
 movlw 0x40
 movwf CCPR1L
 call pause
 movlw 0x80
 movwf CCPR1L
 call pause
 movlw 0xFF
 movwf CCPR1L
 call pause
 movlw 0x80
 movwf CCPR1L
 call pause
 movlw 0x40
 movwf CCPR1L
 call pause
 movlw 0x10
 movwf CCPR1L
 goto uu
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
set_timer
 clrf T2CON
 clrf TMR2
 clrf INTCON
 bsf STATUS,RP0
 clrf PIE1
 bcf STATUS,RP0
 clrf PIR1
 bsf STATUS,RP0
 movlw 0xFF
 movwf PR2 ; compare with 255
 bcf STATUS,RP0
 movlw 0x02
 movwf CCPR1L
 movlw 0x03
 movwf T2CON ; prescaler 1:16 and postscaler 1:1
 movlw 0x3C
 movwf CCP1CON
 bsf T2CON,TMR2ON
 return
;************************************************************************
;       Subrutine de intarziere                                         *
;************************************************************************
pause movlw 0x02 ; 
 movwf count3
d3 movlw 0x3F
 movwf count1
d1 movlw 0xFA   
 movwf count2
d2 decfsz count2,F 
 goto d2  
 decfsz count1,F 
 goto d1  
 decfsz count3,F    
 goto d3          
 retlw 0x00
;============================================================
usi bsf STATUS,RP0 ; Bank 1
 movlw 0xFF ; all input
 movwf TRISA
 movlw 0x00
 movwf TRISB ; all output
 bcf STATUS,RP0 ; Bank 0
 return
;============================================================
 end

I just copied and pasted futz's as well. I assume both should output in RB3 and only RB3, correct?
 
I'm not sure how much of a difference this makes but your header says 16f628 and you said that you are using a 16f628a. I'll post an alternative code in a little while.
 
Andy1845c said:
I just copied and pasted futz's as well. I assume both should output in RB3 and only RB3, correct?
Correct.

If you're using a PIC16F628A you have to make little changes: the list directive and the include file. I've played with futz's code and it's ok. I've chosen the internal oscillator. The original program requires a high speed crystal.
 
Andy1845c said:
I have the LED on RB3. I have tried both ways, but RB3 should be sourcing power, right?

with pwm, it will alternately sink and source, so it doesn't matter on polarity, aside from your duty cycle will going one way or the other
 
Status
Not open for further replies.

Latest threads

Back
Top