It is always appropriate to respond to the list instead of the individual. That keeps the information on the list. The point of the PICList is less to provide a forum for YOU to get help with YOUR problem, and more to provide a way for people to observe problems and solutions of others, so we can all learn from these experiences. It's a way to disseminate experience and information as widely as possible- moving discussion off-list when it has technical content does not serve that interest. Mike H. On 1/23/07, Balthasar Indermuehle wrote: > 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 > -- http://www.piclist.com PIC/SX FAQ & list archive View/change your membership options at http://mailman.mit.edu/mailman/listinfo/piclist