Puede que lo que te envio no te resulte interesante inmediatamente. Pero de todas formas puede resultarte entretenido, te lo aseguro. Se trata de otra aplicacion mas de los llamados "contadores verticales". Te aseguro que es extremadamente inteligente, y tiene muchas ventajas (no he pensado en los inconvenientes, pero estoy seguro que tambien tendra). Es como lo de los algoritmos de ordenamiento, son curiosidades interesantes. Es un poco dificil de seguir, asi que si necesitas que te ponga en antecedentes, dimelo; (no es que me considere mas listo que tu, sino que ya he visto otras veces el tema de los contadores verticales). Chao. -----Mensaje original----- De: Scott Dattalo [SMTP:sdattalo@UNIX.SRI.COM] Enviado el: miercoles 20 de mayo de 1998 3:17 Para: PICLIST@MITVMA.MIT.EDU Asunto: Re: 3 PWMs 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