Justin Lipton wrote: > > Hi, > > I am new to the PIC device family and am looking to program a PIC16C74. > > My application requires 3 PWM outputs (all with adjustable duty cycles). > Obviously I will use CCP1 for one PWM output leaving me bothered about > the remaining two. > > The other two outputs have frequencies of 30Hz and 70Hz respectively and > need duty cycles (which will not change very often) of 50% or 10%. > > Can anyone suggest a neat method for implementing these outputs? Neat? That's too subjective. But here are a couple of Cool ways of generating multiple PWM outputs. First, last week when we were talking about PWM's I alluded to a vertical counter version. Here it is: ;------------------------------------------------------------ ;vert_pwm ; ; The purpose of this routine is to generate 4 pulse width ;modulated waveforms using vertical counters. This version ;implements 5-bit counters, but other sized counters can ;easily be created. ; The algorithm consists of 8 vertical roll over counters: ;4 for the rising edge and 4 for the falling edge. Whenever ;a rising edge counter rolls over the corresponding PWM bit ;is driven high and when a falling edge counter rolls over it's ;driven low. ; The four rising edge counters are grouped together in the ;lower nibble while the falling edge counters are in the upper. ; ; The counters work on this little trick (complements to ;John Payson): ; the following two instructions propogate the carry bit in ;the W register to the next counter bit and if there is an ;underflow (the counters are down counters), generates a carry ;out. ; ; XORWF bn,F ;toggle next bit if there's a carry in ; ANDWF bn,W ;Set carry if bit went from 0 to 1 ; ;RAM ; b0-b4 counters ; pwm_state - current state of the pwm outputs ; temp - temporary register. ;ROM ; 17 instructions ; vert_pwm: COMF b0,W ;unconditionally toggle and get the MOVWF b0 ;'carry out' if going from 0 -> 1 ; XORWF b1,F ; ANDWF b1,W ; ; XORWF b2,F ; ANDWF b2,W ; ; XORWF b3,F ; ANDWF b3,W ; ; XORWF b4,F ; ANDWF b4,W ; ; MOVWF temp ;save the carry out results (only ;those counters that rolled over ;will generate a carry out). ; ANDLW 00001111b ;get the rising edge counters. ; IORWF pwm_state,F ;If a rising edge counter rolled over ;then turn that output on. ; SWAPF temp,W ;Get the falling edge counters XORLW 0x0f ;and toggle them. A roll over is now ;a 'zero' ; ANDWF pwm_state,F ;If a falling edge counter rolled ;then turn that output off MOVWF PWM_PORT The down side with the vertical counter pwm is its initialization. Try it. Here's another method for 8 8-bit pwms (but uses old-fashioned horizontal counters) ;------------------------------------------------------------ ;pwm_multiple ; ; The purpose of this routine is to generate 8 pulse width ;modulated waveforms. The algorithm consists of 9 counters ;that change the state of the pwm bits whenever they roll over. ;One of the counters, rising_edge, will drive the pwm bits ;high when it rolls over. The other 8 counters pwm0-pwm7 will ;drive their corresponding bits low when they roll over. ; ; ;RAM: ; pwm0-pwm7 - pwm counters ; rising_edge - rising edge counter ; pwm_state - current state of the pwm outputs. ;ROM ; 23 instructions ;Execution time ; 23 cycles pwm_multiple CLRW ;Build the bit mask for turning ;off the PWM outputs. Assume that ;all of the outputs will be turned ;off. ; DECFSZ pwm0,F ;If the first counter has not reached 0 IORLW 00000001b ;then we don't want to turn it off. ; DECFSZ pwm1,F ;Same for the second one IORLW 00000010b ; ; DECFSZ pwm2,F ;and so on... IORLW 00000100b ; ; DECFSZ pwm3,F ; IORLW 00001000b ; ; DECFSZ pwm4,F ; IORLW 00010000b ; ; DECFSZ pwm5,F ; IORLW 00100000b ; ; DECFSZ pwm6,F ; IORLW 01000000b ; ; DECFSZ pwm7,F ; IORLW 10000000b ; ; ; ANDWF pwm_state,W ; Clear all of those pwm outputs ;that have reached zero. ; XORLW 11111111b ;Toggle the current state. INCFSZ rising_edge,F ;If the rising edge counter has not XORLW 11111111b ;rolled over then toggle them again. ;Double toggle == no effect. However, ;if the rising edge counter does roll ;over then a single toggle will turn ;the pwm bits on, unless of course the ;pwm counter has just rolled over too. ; MOVWF pwm_state ;Save the state MOVWF PWM_PORT ;update the outputs There's also a "Scenix virtual peripheral" similar to this bit-banging code. However, the pwm frequencies are not constant (which in most cases is not a big deal) and the code is slower (which in many cases is). Now I realize that neither of these directly satisfy your 30Hz and 70Hz frequency requirements (why do you need those frequencies anyways?). However, you could set up a timer interrupt routine that interrupts at 210 Hz (or 420, 630, 210*n Hz) and every third time through run the 70Hz PWM code and every 7th time through run the 30hz code. There was a single pwm output version of code posted last week. Scott