Hi Chris and all others who responded so diligently to my question! Thanks for all your excellent help so far. I'm reading, learning and experimenting at this point (not successful yet, but it's starting to look good). I might have some more questions in regards to an individual response. Is it customary to respond privately in that case or to the list? Cheers - Balt > -----Original Message----- > From: piclist-bounces@mit.edu > [mailto:piclist-bounces@mit.edu] On Behalf Of Chris Piclist > Sent: Mittwoch, 24. Januar 2007 01:12 > To: piclist@mit.edu > Subject: RE: [PIC] fading a LED with 16F917 > > Hi Balt, > > Welcome to the world of pics! They are great devices and a > lot of fun to experiment with. > > One of my favorite things to do is make led and robot > projects for my daughter. She really enjoys helping me make > things and likes it when I make her little circuits. I do a > lot of led projects using RGB leds and pwm. > > I've experimented and created many types of pwm code using > bit banging and the pwm modules that some pics have. My > favorite piece of code and the one I now use as the > foundation for most of my led work was written by Scott > Datalo. I've pasted a few code snippets here for you to look > at. None of them are 100% complete so you will need to add > code of your own. If you are interested, I would be happy to > zip up a simple nightlight project I created and post it on > my website or here on Piclist. > > Hope this helps. > > -Chris > > ; ---------------------------------------------------- > ; Here is a piece of sample code from Scott. > ; be sure to visit his web site for more info. The ; link is below. > ; ---------------------------------------------------- > list P=pic16f84 > > #include p16f84.inc > > > ; ---------------------------------------------------- > ;Variables - Adjust for your pic and for absolute ; or relative mode. > ; ---------------------------------------------------- > cblock 0x0020 > > ; > ; The duty cycle for each PWM is stored here: > ; > > pwm0,pwm1,pwm2,pwm3 > pwm4,pwm5,pwm6,pwm7 > > ; > ; The counters are compared to the duty cycles > ; to determine when the pulse should be turned off > ; > > pwm0_cntr,pwm1_cntr,pwm2_cntr,pwm3_cntr > pwm4_cntr,pwm5_cntr,pwm6_cntr,pwm7_cntr > > ; > ; When rhe "rising_edge" counter rolls over, all > ; pwms are driven high > ; > rising_edge > > pwm_state > endc > > #define PWM_PORT PORTB > > > org 0 > > goto Start > > org 4 > > ;------------------------------------------------------------ > ;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. > ; > ; The technique can be understood with an example for one ; > counter. (This was taken from my web page: > ; http://www.dattalo.com/technical/theory/pwm.html ) ; ; In > Psuedo-code: > ; > ;// Initialize > ; > ;PWM_output = 1; > ;rising_edge = 0; // Rising edge counter > ;falling_edge = MAX_COUNT - duty_cycle; // Falling edge counter > ; > ;// Loop forever: > ; > ;while(1) { > ; > ; // If the rising_edge counter rolls over, make the output > high ; ; if(rising_edge++ > MAX_COUNT) { > ; rising_edge = 0; > ; PWM_output = 1; > ; } > ; > ; > ; // If the falling_edge counter rolls over, make the output > low ; ; if(falling_edge++ > MAX_COUNT) { > ; falling_edge = 0; > ; PWM_output = 0; > ; } > ; > ;} > ; > ; > ;In this un-optimized example, we start the PWM output in the > high ;state and initialize the falling edge counter with the > desired ;duty cycle (or actually MAX_COUNT - duty_cycle, > since the ;algorithm increments the counters). When the > counters reach their ;maximum count, they're cleared back to > zero and the PWM output is ;updated. Perhaps a simple picture > illustrates it better: > ; > ; > ;RE |---------|---------|---------|---------|--------- > ; 01234567890123456789012345678901234567890123456789 > ; > ;FE ----|---------|---------|---------|---------|----- > ; 67890123456789012345678901234567890123456789012345 > ; > ;PWM ----______----______----______----______----______ > ; > ; > ; > ;RE = Rising Edge counter > ; > ;FE = Falling Edge counter > ; > ;PWM = PWM output > ; > ;In this example, the counters roll over after 10 counts. In > the ;beginning, the rising edge counter is cleared and the > output is ;driven high. Also, the duty cycle is 4 so the > falling edge ;counter is initialized to (10 - 4) = 6. When > the rising edge ;counter counts from 9 to 10, it is "rolled > over" back to zero and ;the output is driven high. Similarly, > the falling edge counter ;drives the output low when it rolls over. > ; > ;Perhaps one thing to notice is that the difference (modulo > 10) ;between the two counters is always equal to the duty > cycle. That's ;no coincidence. In fact that's why this > technique is called the ; "Phase Shifted Counters". > ; > ;The modulo arithmetic gets *much* simpler when MAX_COUNT = 2^N. > ; > ; > ;RAM: > ; pwm0-pwm7 - pwm counters > ; rising_edge - rising edge counter > ; pwm_state - current state of the pwm outputs. > ;ROM > ; 38 instructions > ;Execution time > ; 23 cycles > > pwm_multiple > > ; > DECFSZ rising_edge,F ;If the rising edge counter has not > rolled > GOTO pwm_update ;over, then go update the PWM counters > ; > pwm_rising_edge: ; > ; > MOVF pwm0,W ;Update each counter with the latest > MOVWF pwm0_cntr ;pwm value > ; > MOVF pwm1,W ; > MOVWF pwm1_cntr ; > ; > MOVF pwm2,W ; > MOVWF pwm2_cntr ; > ; > MOVF pwm3,W ; > MOVWF pwm3_cntr ; > ; > MOVF pwm4,W ; > MOVWF pwm4_cntr ; > ; > MOVF pwm5,W ; > MOVWF pwm5_cntr ; > ; > MOVF pwm6,W ; > MOVWF pwm6_cntr ; > ; > MOVF pwm7,W ; > MOVWF pwm7_cntr ; > ; > MOVLW 0xff ;Turn on all of the PWM's. > GOTO pwm_exit ; > > pwm_update: > CLRW ;Build the bit mask for turning > ;off the PWM outputs. Assume that > ;all of the outputs will be turned > ;off. > ; > DECFSZ pwm0_cntr,F ;If the first counter has not > reached 0 > IORLW b'00000001' ;then we don't want to turn it off. > ; > DECFSZ pwm1_cntr,F ;Same for the second one > IORLW b'00000010' ; > ; > DECFSZ pwm2_cntr,F ;and so on... > IORLW b'00000100' ; > ; > DECFSZ pwm3_cntr,F ; > IORLW b'00001000' ; > ; > DECFSZ pwm4_cntr,F ; > IORLW b'00010000' ; > ; > DECFSZ pwm5_cntr,F ; > IORLW b'00100000' ; > ; > DECFSZ pwm6_cntr,F ; > IORLW b'01000000' ; > ; > DECFSZ pwm7_cntr,F ; > IORLW b'10000000' ; > ; > ; > ; > ; > ANDWF pwm_state,W ; Clear all of those pwm outputs > ;that have reached zero. > pwm_exit: ; > MOVWF PWM_PORT ;Update the outputs > MOVWF pwm_state ;Save the state > > RETURN > > > Start > BSF STATUS,RP0 > CLRF PWM_PORT > BCF STATUS,RP0 > > MOVLW 0 > MOVWF pwm0 > > MOVLW 0x10 > MOVWF pwm1 > > MOVLW 0x20 > MOVWF pwm2 > > MOVLW 0x30 > MOVWF pwm3 > > MOVLW 0x40 > MOVWF pwm4 > > MOVLW 0x50 > MOVWF pwm5 > > MOVLW 0x60 > MOVWF pwm6 > > MOVLW 0x70 > MOVWF pwm7 > > loop > CALL pwm_multiple > goto loop > end > > > > ; ---------------------------------------------------- > ; Below are some routines from one of my nightlight ; > projects. You can see how I am using Scott's code ; to PWM > modulate the RGB led. I control brightness ; which lets me > change colors and overall intensity. > ; > ; *** NOTE *** This code is not complete. I left out ; a lot > of setup and other irrelivent stuff to try ; and keep it simple. > ; > ; ---------------------------------------------------- > ;MAIN CODE > ; > ; The PWMLevelTable contains entries > ; for bright, medium and dim led levels. > ; It is used when the user changes the > ; maximum brightness level of the > ; nightlight. > ; > ; The table has 4 entries for each > ; brightness level. The entries are: > ; MaxDutyCycle - The new maximum duty cycle > ; RedStart - Starting red duty cycle > ; GreenStart - Starting green duty cycle > ; BlueStart - Starting blue duty cycle > ; > ; USAGE: Call the table subroutine with the ; offset you want > in W ; ; *** NOTE *** I did not put any error checking or ; > 256 byte boundary management code in here. Make ; sure table > is in first 256 bytes or write better code. > ; > PWMLevelTable > addwf PCL,f > ; Bright > dt 0xf0, 0x09, 0xa5, 0xe0 ; Start offset 0x0 > ; Medium > dt 0x20, 0x15, 0x05, 0x1e ; Start offset 0x4 > ; Dim > dt 0x09, 0x05, 0x03, 0x02 ; Start offset 0x8 > > ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= > ; *** Main program loop > ; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= > ; PWM the RGB leds > Main > PWM > ; check for light adjust button press > btfsc LTBtnPressed > goto LTAdjBtnHandler > > ; Check for time adjust button press > btfsc TMBtnPressed > goto TMAdjBtnHandler > > ; Check for TimeToSleep > btfsc TimeToSleep > goto Shutdown > > ; Time to change colors by adjusting duty cycles? > btfsc ChangeColor > goto ColorCycle > > ; ---------------------------------------------------- > ; This is Scott's code - modified for my project ; > ---------------------------------------------------- > > decfsz risingEdge,f ; Rising edge == 0? > (time to start over) > goto PWMUpdate ; NO - Update each > pwm count down > > PWMRisingEdge > movfw redPwm ; Set each color's duty > cycle > movwf redPwmCtr > > movfw greenPwm > movwf greenPwmCtr > > movfw bluePwm > movwf bluePwmCtr > > movlw RLED|GLED|BLED ; turn on all pwm ports > goto PWMExit > > PWMUpdate > ; build bit mask for turning off pwm's > ; who's counters are zero > clrw ; Clear WREG. > It's the mask register. > > decfsz redPwmCtr,f ; Is it time to turn off > this led? > iorlw RLED ; NO - set > mask to keep this led on. > > decfsz greenPwmCtr,f > iorlw GLED > > decfsz bluePwmCtr,f > iorlw BLED > > andwf pwmState,w ; clear all outpus that > reached zero > PWMExit > movwf PORTC ; Update pwm > outputs > movwf pwmState ; Save state for next > pass through > goto PWM ; repeat > ;------------------------------------------------------------- > ---------- > ------ > > ; ---------------------------------------------------- > ; This routine is a cut and paste from my nightlight. > ; > ; It shows one way to change duty cycle and cycle ; led > colors/brightness. > ; ---------------------------------------------------- > ; > ; > ; ColorCycle is responsible for incrementing the ; duty cycle > for each of the colors in the RGB led. > ; > ; It does this by adding 0x01 or 0xFF to each ; color's duty > cycle. Adding 0xFF is the same ; as subtracting 0x01. > ; > ; When a duty cycle reaches the maximum > ; or minimum value, it's increment register ; is changed from > 0x01 to 0xFF or from 0xFF to 0x01. > ; This causes the duty cycle to count in the ; opposite direction. > ; > ; Each led cycles back and forth between its ; minimum and > maximum brightness level. > ; > ; When the three led's are mixed, all kinds ; of cool colors > come out. > ; > ; NOTE - ColorCycle is called by the main line ; code > whenever ChangeColor is high. ChangeColor ; is set every 32 > mS in the TMR0 interrupt. > ; Adjust the TMR0 interrupt interval to change ; the cycle > speed AND/OR add a counter here ; to only change values every X calls. > ; ---------------------------------------------------- > ColorCycle > ; *** Automatic color cycle the pwms - test version 1 > movfw redInc ; Increment/decrement duty > cycles > addwf redPwm,f > movfw greenInc > addwf greenPwm,f > movfw blueInc > addwf bluePwm,f > > ; Check each duty cycle for min value. If it's at > ; the minimun, invert the incrementer. > CheckRed > ; min check > movf redPwm,w ; Check for minimum value > subwf pwmMin,w > btfss STATUS,Z ; Need to invert? > goto CheckRedMax ; NO, Check for max invert > goto RedInvert ; YES, Invert > > CheckRedMax > ; max check > movf redPwm,w ; Check for maximum value > subwf pwmMax,w > btfss STATUS,Z ; Need to invert? > goto CheckGreen ; NO, Check next color > > RedInvert > movlw 0xff ; Toggle incrementer > between > btfsc redInc,7 ; 0xFF and 0x01. This causes it > movlw 0x01 ; to increment or > decrement duty > movwf redInc ; cycle when added to a > register. > > CheckGreen > ; min check > movf greenPwm,w > subwf pwmMin,w > btfss STATUS,Z > goto CheckGreenMax > goto GreenInvert > > CheckGreenMax > ; max check > movf greenPwm,w > subwf pwmMax,w > btfss STATUS,Z > goto CheckBlue > > GreenInvert > movlw 0xff > btfsc greenInc,7 > movlw 0x01 > movwf greenInc > > CheckBlue > ; min check > movf bluePwm,w > subwf pwmMin,w > btfss STATUS,Z > goto CheckBlueMax > goto BlueInvert > > CheckBlueMax > ; max check > movf bluePwm,w > subwf pwmMax,w > btfss STATUS,Z > goto ColorCycleDone > > BlueInvert > movlw 0xff > btfsc blueInc,7 > movlw 0x01 > movwf blueInc > > ColorCycleDone > bcf ChangeColor ; Clear the color change flag. > goto PWM > ;------------------------------------------------------------- > ---------- > ------ > > -- > http://www.piclist.com PIC/SX FAQ & list archive View/change > your membership options at > http://mailman.mit.edu/mailman/listinfo/piclist > -- http://www.piclist.com PIC/SX FAQ & list archive View/change your membership options at http://mailman.mit.edu/mailman/listinfo/piclist