-
Single PIC to Blink 5 LEDs Independently?
I'm in the final stages of a project I've been working off-and-on for the past 8 months. The final stage before submitting my board is to see if I can reduce the number of components by combining functionality into 1 chip.
Currently, I have 5 12F629's which each blink 1 LEDs with separate on/off timings, with some randomization in the on/off cycles. I use PWM to fade in/out the LEDs as they must simulate old incandescent Christmas tree lights. Can I do this all with 1 pic (say, 16F1825)? I've been looking at Darrel's SPWM_INT - Multiple Software PWM but not sure if I can code in the needed PAUSEs while the LEDs are fully on or off (to get the right blinky look).
Am I on the right path here, or does anyone have some suggestions for me? Going from 5 chips to 1 would be a big win for me.
-
Re: Single PIC to Blink 5 LEDs Independently?
I went on Microchip and looked for a PIC with at least 5 timers: PIC18F24J11.
http://www.microchip.com/ParamChartS...g=en&pageId=74
(That page might load properly, or not.)
I'd try to use that along with DT-INTs; best way to blink LEDs.
Robert
EDIT:
http://darreltaylor.com/DT_INTS-18/home.html
Quote:
TMR0_INT -- TMR0 Overflow
TMR1_INT -- TMR1 Overflow
TMR2_INT -- TMR2 to PR2 Match
TMR3_INT -- TMR3 Overflow
TMR4_INT -- TMR4 Overflow
EDIT SOME MORE:
There are 16F models if that makes things easier for you: PIC16F1782
http://www.microchip.com/ParamChartS...=en&pageId=74#
Use the Show/Hide Column feature to speed browsing.
-
1 Attachment(s)
Re: Single PIC to Blink 5 LEDs Independently?
Thanks Robert. 16Fs do make things easier for me. Looks like the 16F1782 has (4) 8bit timers and (1) 16bit timer so I'll pick up some of those.
I'm wondering, though, if I could use a 12F683 (2 x 8-bit, 1 x 16-bit) and the unused ports of a 16F1825 (I have RC4 and RA3-5 ports available) which has 4 x 8-bit and 1 x 16-bit timers. Some of the TMRs on the 16F1825 are already used, I'm sure, since I'm using CCP1 & CCP2.
How can I tell which TMRs are being used? Here's my code:
Code:
'****************************************************************
'* Name : Nacelle_Motors_16F1825_32Mhz_Int_SN754410.pbp *
'* Author : Ross A. Waddell *
'* Notice : Copyright (c) 2012 *
'* : All Rights Reserved *
'* Date : 10/20/2012 *
'* Version : 2.0 *
'* Notes : Motor control for TOS E engines using SN754110 *
'* : motor driver, plus steady-on amber lights *
'****************************************************************
' ***************************************************************
' TODOs
' ***************************************************************
' 1. Need to calibrate motor RPMs so they spin at the same rate
' -> Separate "MotorRPM" EEPROM variables?
' 2. Add power isolation as blinking running lights seem to increase electrical noise
DEFINE OSC 32 ' Set oscillator 32 Mhz
' ***************************************************************
' Device Fuses
' ***************************************************************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF
__config _CONFIG2, _PLLEN_ON & _STVREN_ON & _BORV_LO & _LVP_OFF
#ENDCONFIG
' ***************************************************************
' Initialization
' ***************************************************************
OSCCON = %11110000 ' 32 MHz internal osc (8 Mhz with 4x SPLLEN enabled)
pause 100 ' As advised by Darrel Taylor for EEPROM issue
DEFINE CCP2_REG PORTC ' Only need to define CCP2 pin as there are 2
DEFINE CCP2_BIT 3 ' possible choices: RA5 or RC3
PORTA = 0 ' Set initial value of PORTA to 0
PORTC = 0 ' Set initial value of PORTC to 0
;ADCON0 = 7
;ADCON1 = 7
ANSELA.0 = 0 ' Digital only on rotary encoder B pin
ANSELA.1 = 0 ' Digital only on rotary encoder A pin
ANSELA.2 = 0 ' Digital only on rotary encoder's button
ANSELC.0 = 0 ' Digital only on Stbd motor direction signal (Motor 1)
ANSELC.1 = 0 ' Digital only on Port motor direction signal (Motor 2)
ANSELC.2 = 0 ' Digital only on LED_0 pin (steady-on amber lights)
ANSELC.3 = 0 ' Digital only on CCP2 pin (Port engine)
ANSELC.5 = 0 ' Digital only on CCP1 pin (Stbd engine)
TRISA = %00000111 ' Make PORTA pins 0-2 input for rotary encoder
TRISC = %00000000 ' Make all PORTC pins output
' The INTEDG bit of the OPTION_REG register determines on which edge the
' interrupt will occur. When the INTEDG bit is set, the rising edge will
' cause the interrupt. When the INTEDG bit is clear, the falling edge will
' cause the interrupt.
OPTION_REG.6 = 1 ' 1=Rising edge (default) or button "PRESS";
' 0=Falling edge or button "RELEASE"
Old_Bits VAR BYTE
New_Bits VAR BYTE
RotEncDir VAR BIT ' 1=CW, 0=CCW
' Rot Enc pin A connected to PortA.1;
' Rot Enc pin B connected to PortA.0
Old_RPM VAR BYTE
I VAR BYTE
LED_0 VAR PORTC.2 ' Alias PORTC.2 as "LED_0"
MOTOR_1_DIR VAR PORTC.0 ' Alias PORTC.0 as "MOTOR_1_DIR"
MOTOR_1_PWM VAR PORTC.5 ' Alias PORTC.5 as "MOTOR_1_PWM"
MOTOR_2_DIR VAR PORTC.1 ' Alias PORTC.1 as "MOTOR_2_DIR"
MOTOR_2_PWM VAR PORTC.3 ' Alias PORTC.3 as "MOTOR_2_PWM"
ButtonPress VAR PORTA.2 ' Alias PORTA.2 as "ButtonPress"
TimeCnt VAR Word
LOW LED_0
LOW MOTOR_1_DIR
LOW MOTOR_1_PWM
LOW MOTOR_2_DIR
LOW MOTOR_2_PWM
' ***************************************************************
' Pin Connections
' ***************************************************************
' RA0 -> B pin of rotary encoder
' RA1 -> A pin of rotary encoder
' RA2 -> Button switch pin of rotary encoder
' RC0 -> Stbd motor direction signal (motor 1)
' RC1 -> Port motor direction signal (motor 2)
' RC2 -> Steady-on LED
' RC3/CCP2 -> Port motor PWM output (motor 2)
' RC5/CCP1 -> Stbd motor PWM output (motor 1)
' ***************************************************************
' Includes
' ***************************************************************
INCLUDE "DT_INTS-14.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts
' --> copy both files to PBP main folder
' (i.e. c:\pbp3)
INCLUDE "EE_Vars.PBP" ' copy file to PBP main folder (i.e. c:\pbp3)
' ***************************************************************
' EEPROM Variables
' ***************************************************************
MotorRPM VAR BYTE : @ EE_var _MotorRPM, BYTE, 150
PortEngDir VAR BYTE : @ EE_var _PortEngDir, BYTE, 0
' ***************************************************************
' ASM Interrupt Definitions
' ***************************************************************
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler IOC_INT, _RotEncAdjust, PBP, yes
; INT_Handler INT_INT, _RotEncBtnPress, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
' ***************************************************************
' Set default values
' ***************************************************************
Old_RPM = MotorRPM
Old_Bits = PORTA & (%00000011)
HIGH LED_0 ' Turn on steady-on LEDs
LOW MOTOR_1_DIR ' Set stbd motor (motor 1) to fwd (CW)
' (always spins in the same direction)
IF PortEngDir = 0 THEN
LOW MOTOR_2_DIR ' Set port motor (motor 2) to fwd (CCW)
ELSE
HIGH MOTOR_2_DIR ' Set port motor (motor 2) to rev (CW)
ENDIF
' Spin up motors to saved value of _MotorRPM
' (Below a cycle of 66, the motors don't move at all)
IF MotorRPM > 66 THEN
FOR I = 65 to MotorRPM
pause 30
HPWM 1, I, 20000 ' Stbd engine (CCP1)
IF PortEngDir = 0 THEN
HPWM 2, I, 20000 ' Port engine (CCP2), fwd (CCW)
ELSE
HPWM 2, (255-I), 20000 ' Port engine (CCP2), rev (CW)
ENDIF
NEXT I
EndIf
HPWM 1, MotorRPM, 20000 ' Stbd engine (CCP1)
IF PortEngDir = 0 THEN
HPWM 2, MotorRPM, 20000 ' Port engine (CCP2)
ELSE
HPWM 2, (255-MotorRPM), 20000 ' Port engine (CCP2)
ENDIF
' Enable interrupts on RPM control now that motors are fully spun up
;INTCON = %10011000 ' Global int enabled, INTE enabled, IOCI enabled,
' INTF flag bit 0 clr, IOCI flag bit 0 clr
INTCON = %10001000 ' Global int enabled, IOCI enabled,
' INTF flag bit 0 clr, IOCI flag bit 0 clr
IOCAP.0 = 1 ' Enable positive (rising edge) change
IOCAP.1 = 1 ' Enable positive (rising edge) change
IOCAN.0 = 1 ' Enable negative (falling edge) change
IOCAN.1 = 1 ' Enable negative (falling edge) change
IOCAF.0 = 0 ' Clear interupt-on-change flag
IOCAF.1 = 0 ' Clear interupt-on-change flag
;INTCON.1 = 0 ' Clear RA2/INT External Interrupt Flag
@ INT_ENABLE IOC_INT ; Interrupt-on-Change interrupt
;@ INT_ENABLE INT_INT ; INT/Ext Interrupt
Main:
' Check if motor RPM has changed
IF MotorRPM <> Old_RPM Then
Old_RPM = MotorRPM
GOSUB ChngMotorHPWM
EndIF
TimeCnt = 0
While ButtonPress = 0
TimeCnt = TimeCnt + 1
Pause 10
If TimeCnt > 500 Then BtnAction
Wend
BtnAction:
If TimeCnt > 0 and TimeCnt < 200 Then
PortEngDir = PortEngDir + 1
If PortEngDir > 1 Then PortEngDir = 0
@ EE_write_var _PortEngDir ; save the new number to EEPROM
GOSUB ReversePortEng
ElseIf TimeCnt >= 200 Then
@ EE_write_default _MotorRPM
EndIf
GOTO Main
ReversePortEng:
LOW MOTOR_2_DIR ' Electrically stop motor 2
LOW MOTOR_2_PWM
pause 100
IF PortEngDir = 0 THEN
LOW MOTOR_2_DIR ' Set port motor (motor 2) to fwd (CCW)
ELSE
HIGH MOTOR_2_DIR ' Set port motor (motor 2) to rev (CW)
ENDIF
IF PortEngDir = 0 THEN
HPWM 2, MotorRPM, 20000 ' Port engine (motor 2), fwd (CCW)
ELSE
HPWM 2, (255-MotorRPM), 20000 ' Port engine (motor 2), rev (CW)
ENDIF
RETURN
ChngMotorHPWM:
HPWM 1, MotorRPM, 20000 ' Stbd engine (motor 1)
; Tried 245 Hz but it made the motor too loud.
; Supposedly, anything above 20kHz is above
; human hearing
IF PortEngDir = 0 THEN
HPWM 2, MotorRPM, 20000 ' Port engine (motor 2), fwd (CCW)
ELSE
HPWM 2, (255-MotorRPM), 20000 ' Port engine (motor 2), rev (CW)
ENDIF
RETURN
end
' ***************************************************************
' [IOC - interrupt handler]
' ***************************************************************
RotEncAdjust:
New_Bits = PORTA & (%00000011)
IF (New_Bits & %00000011) = (Old_Bits & %00000011) Then DoneRotEnc
RotEncDir = New_Bits.1 ^ Old_Bits.0
IF RotEncDir = 1 Then
; CW rotation - increase speed but only to a max of 255
IF MotorRPM < 255 then MotorRPM = MotorRPM + 1
Else
' CCW rotation - decrease speed to a min of 0
IF MotorRPM > 0 Then MotorRPM = MotorRPM - 1
EndIF
@ EE_write_var _MotorRPM ; save the new number to EEPROM
DoneRotEnc:
Old_Bits = New_Bits
IOCAF.0 = 0 ' Clear interrupt flags
IOCAF.1 = 0
@ INT_RETURN
' ***************************************************************
' [INT - interrupt handler]
' ***************************************************************
;RotEncBtnPress:
' Restore MotorRPM to default value
;@ EE_write_default _MotorRPM
; INTCON.1 = 0 ' Clear RA2/INT External Interrupt Flag
;@ INT_RETURN
Attachment 6725
Also, would adding the blinkies to this project (which already uses Darrel's DT_INST-14.bas to handle a quadrature rotary encoder inputs) affect the existing functionality?
-
Re: Single PIC to Blink 5 LEDs Independently?
Do you see any (major) difference between the 16G1782 and the 16F1825? The latter has only 14 pins (compared to the former's 28) and that would help a lot; I only need 5 outputs. Plus, I have a bunch of those around.
Ok, so let's say I use 1 dedicated 16F1825 chip to do the 5 independent blinks - should I use the SPWM include from Darrel? How do I configure the 5 timers with different on/off frequencies?
-
Re: Single PIC to Blink 5 LEDs Independently?
-
Re: Single PIC to Blink 5 LEDs Independently?
You do not need a seperate hardware timer for each led. A single timer would do the job.:smile: Adapt the following code to suit your needs.
Code:
#config
__CONFIG _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_ON & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_ON & _XT_OSC
__CONFIG _CONFIG2, _WRT_OFF & _BOR40V
#endconfig
TIMER0 VAR BYTE
TIMER1 VAR BYTE
TIMER2 VAR BYTE
TIMER3 VAR BYTE
TIMER4 VAR BYTE
TIMER5 VAR BYTE
TIMER6 VAR BYTE
TIMER7 VAR BYTE
LED0 VAR PORTB.0
LED1 VAR PORTB.1
LED2 VAR PORTB.2
LED3 VAR PORTB.3
LED4 VAR PORTB.4
LED5 VAR PORTB.5
LED6 VAR PORTB.6
LED7 VAR PORTB.7
wsave VAR BYTE $70 SYSTEM
ssave VAR BYTE $71 SYSTEM
psave VAR BYTE $72 SYSTEM
GOTO START:
DEFINE INTHAND MYINT
ASM
MYINT
movwf wsave ; <=2k codespace
swapf STATUS,W ; <=2k codespace
clrf STATUS ; <=2k codespace
movwf ssave ; <=2k codespace
movf PCLATH,W ; <=2k codespace
movwf psave ; <=2k codespace
TSTF _TIMER0 ;test timer0
BTFSS STATUS,Z ;skip if zero
DECF _TIMER0,F ;decrement timer 0
TSTF _TIMER1
BTFSC STATUS,Z
DECF _TIMER1,F
TSTF _TIMER2
BTFSC STATUS,Z
DECF _TIMER2,F
TSTF _TIMER3
BTFSC STATUS,Z
DECF _TIMER3,F
TSTF _TIMER4
BTFSC STATUS,Z
DECF _TIMER4,F
TSTF _TIMER5
BTFSC STATUS,Z
DECF _TIMER5,F
TSTF _TIMER6
BTFSC STATUS,Z
DECF _TIMER6,F
TSTF _TIMER7
BTFSC STATUS,Z
DECF _TIMER7,F
BCF PIR1,0
MOVF psave,W
MOVWF PCLATH
SWAPF ssave,W
MOVWF STATUS
SWAPF wsave,F
SWAPF wsave,W
RETFIE
ENDASM
START:
ANSEL=0 'all pins are digital
ANSELH=0
TRISB=$00 'all outputs
PORTB=0
OPTION_REG=$80
T1CON=$01 'interrupt every 65.5 ms
PIE1=$01 'enable timer 1 interrupts
INTCON=$C0 'enable interrupts
AGAIN:
IF TIMER0=0 THEN
TIMER0=10
TOGGLE LED0
ENDIF
IF TIMER1=0 THEN
TIMER1=9
TOGGLE LED1
ENDIF
IF TIMER2=0 THEN
TIMER2=5
TOGGLE LED2
ENDIF
IF TIMER3=0 THEN
TIMER3=7
TOGGLE LED3
ENDIF
IF TIMER4=0 THEN
TIMER4=12
TOGGLE LED4
ENDIF
IF TIMER5=0 THEN
TIMER5=6
TOGGLE LED5
ENDIF
IF TIMER6=0 THEN
TIMER6=8
TOGGLE LED6
ENDIF
IF TIMER7=0 THEN
TIMER7=11
TOGGLE LED7
ENDIF
GOTO AGAIN
pic used is a 16F882.
-
Re: Single PIC to Blink 5 LEDs Independently?
I will indeed try that out with a 1fF1825. Could you please clarify for me where I set the individual on/off values for each of the 8 LEDs? In my existing implementation (5 separate 12F683's) I have code like this:
Code:
' Changing the value for "Cycle" will change the time it takes
' to fade from 100% to 0% (or 0% to 100% if duty is increasing)
' Lower number = faster fade in/out
Cycle = 1
' Higher step value produces faster fade, but too high a value
' will introduce flicker
STEP_CNTR = 2
Main:
' Fade in
For Duty = 0 TO 255 step STEP_CNTR
PWM LED_0, Duty, Cycle
Next
' Stay on LGHTS_ON_MS
HIGH LED_0
Pause LGHTS_ON_MS
' Fade out
For Duty = 255 TO 0 STEP -STEP_CNTR
PWM LED_0, Duty, Cycle
Next
' Stay off for LGHTS_OFF_MS
Pause LGHTS_OFF_MS
' Fade in
For Duty = 0 TO 255 step STEP_CNTR
PWM LED_0, Duty, Cycle
Next
' Stay on LGHTS_ON_MS
HIGH LED_0
Pause (LGHTS_ON_MS - 200)
' Fade out
For Duty = 255 TO 0 STEP -STEP_CNTR
PWM LED_0, Duty, Cycle
Next
' Stay off for LGHTS_OFF_MS
Pause (LGHTS_OFF_MS + 100)
GOTO Main
(In actuality, I extend the fade in/stay on/fade out/stay off with various timings to randomize the effect. Old 1960's Christmas tree lights did not have constant blink rates).
-
Re: Single PIC to Blink 5 LEDs Independently?
I've tried adapting Darrel's example from this thread, but no luck with a PIC16F1825 - PORTC.0-3 do not blink (PORTC.0-2 are off; PORTC.3 is on) but PORTC.4 blinks properly. What am I doing wrong here? I've had to adapt Darrel's code for the PIC16F1825 and reduced the number of blinkies to 5 from 8.
Code:
'****************************************************************
'* Name : UNTITLED.BAS *
'* Author : Ross Waddell *
'* Notice : Copyright (c) 2012 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 10/27/2012 *
'* Version : 1.0 *
'* Notes : PIC16F1825 *
'* : *
'****************************************************************
DEFINE OSC 4
DEFINE BLINKYFREQ 100 ; 10mS periods
' ***************************************************************
' Device Fuses
' ***************************************************************
' PIC chip data sheets can be found here: C:\Program Files\Microchip\MPASM Suite
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF
__config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF
#ENDCONFIG
OSCCON = %01101000 ' 4MHz internal osc
DATA 50,22,38,75,17;,40,62,13 ; default periods for each Output
;----------------------------------------------------------------
CCPR1val CON EXT : @CCPR1val = (OSC*1000000/4)/ BLINKYFREQ
CCPR1 VAR WORD EXT : @CCPR1 = CCPR1L
Timer1 VAR WORD EXT : @Timer1 = TMR1L
CCPIF VAR PIR1.2
LoopLED VAR BYTE[5]
LoopCON VAR BYTE[5]
x VAR BYTE
;----[Initialize]------------------------------------------------
FOR x = 0 to 4 ; load the periods from EEPROM
READ x, LoopCON(x)
NEXT X
;-- setup CCP1 and Start Timer1 --
CCPR1 = CCPR1val ; set compare value
CCP1CON = %00001011 ; compare mode, special event
Timer1 = 0 ; clear Timer1
T1CON.0 = 1 ; start Timer1
ANSELC = 0
TRISC = 0 ; PORTC all OUTPUT
;----[Main Program Loop]----------------------------------------
Main:
;x = (x + 1) // 8
x = (x+1)&4
PORTC.0(x) = !(LoopLED(x) < LoopCON(x))
LoopLED(x) = (LoopLED(x) + 1) // (LoopCON(x) << 1)
IF x != 4 THEN Main
Waiting: IF !CCPIF THEN Waiting
CCPIF = 0
GOTO Main
-
Re: Single PIC to Blink 5 LEDs Independently?
Ok, so I answered my own question.
This works:
This doesn't:
The question now becomes: is there a way to set the on/off periods individually for each of the 5 LEDs? The code above has the LEDs blink with the same on time as off; I need to be able to make some of the 'off' times longer than the 'on' and vice versa.
-
Re: Single PIC to Blink 5 LEDs Independently?
Quote:
The question now becomes: is there a way to set the on/off periods individually for each of the 5 LEDs?
Yes, but you have to create the individual ON/OFF periods.
That code only has 1 period, for a 50% dutycycle.
So many things you can do.
So little time to explain.
Twinkle Twinkle little tree ...
Code:
DEFINE OSC 4
DEFINE BLINKYFREQ 100 ; 10mS periods
' ***************************************************************
' Device Fuses
' ***************************************************************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF
__config _CONFIG2, _PLLEN_OFF & _STVREN_ON & _BORV_LO & _LVP_OFF
#ENDCONFIG
OSCCON = %01101000 ' 4MHz internal osc
;----------------------------------------------------------------
LEDcount CON 5 ; Number of LEDs on the PORT
OnTimes DATA 50,22,38,75, 5 ; default periods for each Output
OffTimes DATA 150,45,38,95,34
;----------------------------------------------------------------
#DEFINE USE_RANDOM_SEQUENCE ; comment for contiuous Sequence
#IFDEF USE_RANDOM_SEQUENCE
RND VAR WORD : RND = 13864
MIN_ON CON 10 ; Minimum random ON time
MAX_ON CON 100 ; Maximum random ON time
MIN_OFF CON 10 ; Minimum random OFF time
MAX_OFF CON 100 ; Maximum random OFF time
RandPeriod VAR WORD[LEDcount]
RandPeriods DATA WORD 1000, WORD 1250, WORD 1500, WORD 1750, WORD 2000
#ENDIF
;----------------------------------------------------------------
CCPR1val CON EXT : @CCPR1val = (OSC*1000000/4)/ BLINKYFREQ
CCPR1 VAR WORD EXT : @CCPR1 = CCPR1L
Timer1 VAR WORD EXT : @Timer1 = TMR1L
CCPIF VAR PIR1.2
LoopLED VAR BYTE[LEDcount]
OnTime VAR BYTE[LEDcount]
OffTime VAR BYTE[LEDcount]
x VAR BYTE
;----[Initialize]------------------------------------------------
FOR x = 0 to LEDcount - 1 ; load the periods from EEPROM
READ OnTimes+x, OnTime(x)
READ OffTimes+x, OffTime(x)
#IFDEF USE_RANDOM_SEQUENCE
READ RandPeriods+(x<<1), WORD RandPeriod(x)
#ENDIF
NEXT X
;-- setup CCP1 and Start Timer1 --
CCPR1 = CCPR1val ; set compare value
CCP1CON = %00001011 ; compare mode, special event
Timer1 = 0 ; clear Timer1
T1CON.0 = 1 ; start Timer1
ANSELC = 0
TRISC = 0 ; PORTC all OUTPUT
;----[Main Program Loop]----------------------------------------
Main:
x = (x + 1) // LEDcount
PORTC.0(x) = !!(LoopLED(x) < OnTime(x))
LoopLED(x) = (LoopLED(x) + 1) // (OnTime(x) + OffTime(x))
#IFDEF USE_RANDOM_SEQUENCE
RandPeriod(x) = RandPeriod(x) - 1
IF RandPeriod(x) = 0 THEN
READ RandPeriods+(x<<1), WORD RandPeriod(x)
RANDOM RND
OnTime(x) = (MAX_ON - MIN_ON)* RND.HighByte / 255 + MIN_ON
OffTime(x)= (MAX_OFF - MIN_OFF)* RND.LowByte / 255 + MIN_OFF
ENDIF
#ENDIF
IF x != (LEDcount - 1) THEN Main
Waiting: IF !CCPIF THEN Waiting
CCPIF = 0
GOTO Main
-
Re: Single PIC to Blink 5 LEDs Independently?
My god ... it's ... it's beautiful :) Just like a 1960's string of Christmas tree lights, the exact effect I'm after. I can't thank you enough, Darrel!
One last query (I hope) - since I only need 5 output pins I would like to convert this to a 12F683. When I do, I get the 'ol "Redefinition of VAR" error pointing to this line:
Code:
CCPR1 VAR WORD EXT : @CCPR1 = CCPR1L
The whole code is here:
Code:
'****************************************************************
'* Name : UNTITLED.BAS *
'* Author : Ross Waddell *
'* Notice : Copyright (c) 2012 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 10/27/2012 *
'* Version : 1.0 *
'* Notes : PIC12F683 *
'* : *
'****************************************************************
DEFINE OSC 4
DEFINE BLINKYFREQ 100 ; 10mS periods
' ***************************************************************
' Device Fuses
' ***************************************************************
' PIC chip data sheets can be found here: C:\Program Files\Microchip\MPASM Suite
#CONFIG
__config _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_OFF & _BOD_ON & _CP_OFF & _CPD_OFF
#ENDCONFIG
OSCCON = %01100000 ' 4MHz internal osc
;----------------------------------------------------------------
LEDcount CON 5 ; Number of LEDs on the PORT
OnTimes DATA 50,22,38,75,17 ; default periods for each Output
OffTimes DATA 150,45,38,95,117
;----------------------------------------------------------------
#DEFINE USE_RANDOM_SEQUENCE ; comment for contiuous Sequence
#IFDEF USE_RANDOM_SEQUENCE
RND VAR WORD : RND = 13864
MIN_ON CON 15 ; Minimum random ON time
MAX_ON CON 115 ; Maximum random ON time
MIN_OFF CON 15 ; Minimum random OFF time
MAX_OFF CON 200 ; Maximum random OFF time
RandPeriod VAR WORD[LEDcount]
RandPeriods DATA WORD 1000, WORD 1250, WORD 1500, WORD 1750, WORD 2000
#ENDIF
;----------------------------------------------------------------
CCPR1val CON EXT : @CCPR1val = (OSC*1000000/4)/ BLINKYFREQ
CCPR1 VAR WORD EXT : @CCPR1 = CCPR1L
Timer1 VAR WORD EXT : @Timer1 = TMR1L
CCPIF VAR PIR1.5
LoopLED VAR BYTE[LEDcount]
OnTime VAR BYTE[LEDcount]
OffTime VAR BYTE[LEDcount]
x VAR BYTE
;----[Initialize]------------------------------------------------
FOR x = 0 to (LEDcount - 1) ; load the periods from EEPROM
READ OnTimes+x, OnTime(x)
READ OffTimes+x, OffTime(x)
#IFDEF USE_RANDOM_SEQUENCE
READ RandPeriods+(x<<1), WORD RandPeriod(x)
#ENDIF
NEXT X
;-- setup CCP1 and Start Timer1 --
CCPR1 = CCPR1val ; set compare value
CCP1CON = %00001011 ; compare mode, special event
Timer1 = 0 ; clear Timer1
T1CON.0 = 1 ; start Timer1
ANSEL = 0
TRISIO = 0 ; PORTC all OUTPUT
;----[Main Program Loop]----------------------------------------
Main:
x = (x + 1) // LEDcount
GPIO.0(x) = !!(LoopLED(x) < OnTime(x))
LoopLED(x) = (LoopLED(x) + 1) // (OnTime(x) + OffTime(x))
#IFDEF USE_RANDOM_SEQUENCE
RandPeriod(x) = RandPeriod(x) - 1
IF RandPeriod(x) = 0 THEN
READ RandPeriods+(x<<1), WORD RandPeriod(x)
RANDOM RND
OnTime(x) = (MAX_ON - MIN_ON)* RND.HighByte / 255 + MIN_ON
OffTime(x)= (MAX_OFF - MIN_OFF)* RND.LowByte / 255 + MIN_OFF
ENDIF
#ENDIF
IF x != (LEDcount - 1) THEN Main
Waiting: IF !CCPIF THEN Waiting
CCPIF = 0
GOTO Main
Since there are no include files, my Google search didn't point to anything other than that. Is this too much to expect from a 12F?
-
Re: Single PIC to Blink 5 LEDs Independently?
Looking at the compiler include file for a 12f683 the CCPR1 VAR WORD EXT has already been included. I think you should be able to comment this line out.
Can you please tell me what the following line of code does:
GPIO.0(x) = !!(LoopLED(x) < OnTime(x))
Cannot find any reference to !!
-
Re: Single PIC to Blink 5 LEDs Independently?
Quote:
Originally Posted by
grahamg
Can you please tell me what the following line of code does:
GPIO.0(x) = !!(LoopLED(x) < OnTime(x))
It is equivelent to ...
Code:
IF LoopLED(x) < OnTime(x) THEN
GPIO.0(x) = 1
ELSE
GPIO.0(x) = 0
ENDIF
What you would like to do is a direct assignment of a True/False comparison to a variable.
Code:
GPIO.0(x) = LoopLED(x) < OnTime(x)
But LoopLED(x) < OnTime(x) is a "Logical" expression that can't be assigned to a BIT variable.
The bitwise NOT operator (!) can convert the logical expression to a bitwise expression that can be assigned to a BIT variable.
A single ! will invert the result, so a second ! is used to invert it back.
Somtimes you want the result inverted, and you can use a single !.
Other times you might invert the logic of the comparison, use a single !, which gives you a non-inverted result.
-
Re: Single PIC to Blink 5 LEDs Independently?
Darrel - do you also think I can simply comment out this line to compile for a 12F629?
CCPR1 VAR WORD EXT : @CCPR1 = CCPR1L
-
Re: Single PIC to Blink 5 LEDs Independently?
Hi,
I think you also have to add some lines very specific for the used chip ...
especially to deal with GPIO.3 ... which is input only pin ... ;)
Alain
-
Re: Single PIC to Blink 5 LEDs Independently?
I overlooked that GP3 is input only, Alain. So the 12F629 has only 5 output pins. That would still work for the 5 blinky LEDs but I've been expanding Darrel's example to include 2 other non-random blinky LEDs in order to further reduce the # of components, so if I end up with 6-7 different blink rates I might as well stay with the 16F1825 (since there doesn't appear to be any PICs with 10-12 pins).
-
Re: Single PIC to Blink 5 LEDs Independently?
Quote:
Originally Posted by
RossWaddell
My god ... it's ... it's beautiful :)
Yes, the code is beautiful (can speak for the lights, but I'm sure their nice too).
Have you seen one of Darrel's breadbord layouts? Those are equally as beautiful.
-
Re: Single PIC to Blink 5 LEDs Independently?
Quote:
Originally Posted by
Darrel Taylor
It is equivelent to ...
Code:
IF LoopLED(x) < OnTime(x) THEN
GPIO.0(x) = 1
ELSE
GPIO.0(x) = 0
ENDIF
Like any invention, after the explanation, it seems obvious. However, this is a coding construct I loved learning.
-
Re: Single PIC to Blink 5 LEDs Independently?
Cool! The man is an artist!
Kudos to Darrel.
Ioannis
-
Re: Single PIC to Blink 5 LEDs Independently?
Quote:
Originally Posted by
Darrel Taylor
It is equivelent to ...
Code:
IF LoopLED(x) < OnTime(x) THEN
GPIO.0(x) = 1
ELSE
GPIO.0(x) = 0
ENDIF
What you would like to do is a direct assignment of a True/False comparison to a variable.
Code:
GPIO.0(x) = LoopLED(x) < OnTime(x)
But
LoopLED(x) < OnTime(x) is a "Logical" expression that can't be assigned to a BIT variable.
The bitwise NOT operator (!) can convert the logical expression to a bitwise expression that can be assigned to a BIT variable.
A single ! will invert the result, so a second ! is used to invert it back.
Somtimes you want the result inverted, and you can use a single !.
Other times you might invert the logic of the comparison, use a single !, which gives you a non-inverted result.
Could the comparison have been reversed, like this?
Code:
GPIO.0(x) = !(LoopLED(x) >= OnTime(x))
Also, is the GPIO.0(x) a valid PBP construct? It's not very intuitive (to me). I would think that GPIO.0 is the GP0 pin and then the (x) looks really alien...
-
Re: Single PIC to Blink 5 LEDs Independently?
Thanks guys, but I learned the !! from Charles Leo (my boss).
It's great to be in the offices of melabs. :)
Mike,
Yup, that's the correct way to "invert the logic of the comparison, use a single !, which gives you a non-inverted result.".
And while it does look strange, the (x) in GPIO.0(x) is the offset from GPIO.0.
If x = 0 then it uses GPIO.0
If x = 2, it uses GPIO.2
You can start from any bit.
With GPIO.2(x)
If x = 0 then it uses GPIO.2
If x = 2, it uses GPIO.4
This notation can only be used in direct assignments (using = sign).
You cannot use it as PIN designators in PBP commands like SERIN/OUT, HIGH/LOW etc.
-
Re: Single PIC to Blink 5 LEDs Independently?
No argument from me, SteveB - the elegance of the solution is indeed beautiful!
Would I gain any better resolution/exactitude of timings by increasing the oscillator? The 16F1825 can go up to 32Mhz internal with the pullup enabled. I've added to Darrel's solution to include another blinky without randomization of the periods, so it needs to be on for 20ms and off for 480ms (i.e. it blinks twice a second).
-
Re: Single PIC to Blink 5 LEDs Independently?
Quote:
Originally Posted by
RossWaddell
Would I gain any better resolution/exactitude of timings by increasing the oscillator?
The timing is maintained by the CCP module and Timer1. Those periods will remain the same reqardless of the CPU's frequency.
Increasing the frequency will only allow more instructions to be executed between periods.
The way I left it, only 4.5 mS of the 10 mS periods are being used to run the 5 led's.
You should be able to add 2 more without any problems.
-
Re: Single PIC to Blink 5 LEDs Independently?
I switched to a PIC16F88 since I needed a chip which had 8 pins of the same port (i.e. PORTB0-7). I thought I had it working using RB0-6 (7 blinkies) but realized this chip has the external interrupt on RB0, which I will need for the button to toggle 'FlashMode'. So I moved everything over to PORTA and now the LED connected to RA7 kind of flickers and is no way near the 1.5 sec on/0.5 sec off flash rate set in code.
Code:
'****************************************************************
'* Name : Formation_Engine_Running_Lights_16F88_4Mhz_Int.pbp*
'* Author : Ross A. Waddell *
'* Notice : Copyright (c) 2012 *
'* : All Rights Reserved *
'* Date : 10/29/2012 *
'* Version : 1.0 *
'* Notes : Strobe lights, nacelle lights (steady-on and *
'* Christmas flashers) and running lights for the *
'* TOS Enterprise *
'* : *
'****************************************************************
' ***************************************************************
' Pin Connections
' ***************************************************************
' RA0 -> Flashing lights for nacelle engines 1 (x2)
' RA1 -> Flashing lights for nacelle engines 2 (x2)
' RA2 -> Flashing lights for nacelle engines 3 (x2)
' RA3 -> Flashing lights for nacelle engines 4 (x2)
' RA4 -> Flashing lights for nacelle engines 5 (x2)
' RA5 -> Dummy output (MCLR is input only)
' RA6 -> Secondary hull strobe/formation lights (x2)
' RA7 -> Primary hull running lights (x4)
' RB0 -> Button for toggling running light flash mode
' RB1 -> Steady-on lights for nacelle engines (x10)
' Secondary Hull Strobes Lights
' =============================
' The two strobe locastions are:
' - Port/starboard rear secondary hull (just forward of the "1837" marking),
' horizontally inline with the shuttlebay flight deck
' The strobe light flashed at the rate of twice per second,
' or every 12 film frames. Since it's a strobe, it stays on
' for much less time than a running light; approx. .020 sec
' Nacelle engine lights
' =====================
' (a) The colours used were: red, blue, green, amber and pink, all standard colours
' they had for common Christmas lights of the time.
' (b) They were all Christmas lights (C7, too big for a 1/350).
' (c) Amber was steady (5 in a star pattern), the other 5 blinked at various rates
' Running lights
' ==============
' The running light locations on the primary hull are (4):
' - Saucer Port [top] (red) - 1
' - Saucer Starboard [top] (green) - 1
' - Saucer Port/Starboard [bottom (white) - 2
' The TOS E running lights flash at a base timing of 1-1/2 sec (36 frames) on,
' 1/2 sec (12 frames) off (FlashMode = 0)
' Alternate is 1/2 sec on, 1.5 sec off (reverse of above). (FlashMode = 1)
' In "The Corbomite Maneuver", the lights were on for 18 frames and off for 20
' (FlashMode = 2)
' >> These modes are available via a momentary button
DEFINE OSC 4 ; Set oscillator 4Mhz
DEFINE BLINKYFREQ 100 ; 10mS periods
' ***************************************************************
' Device Fuses
' ***************************************************************
' PIC chip data sheets can be found here: C:\Program Files\Microchip\MPASM Suite
#CONFIG
__config _CONFIG1, _FOSC_INTOSCIO & _WDTE_ON & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _LVP_OFF
#ENDCONFIG
' ***************************************************************
' Initialization
' ***************************************************************
OSCCON = %01100000 ; 4MHz internal osc
ANSEL = 0 ; PIC16F88 only
TRISA = 0 ; PORTA all output
TRISB = %00000001 ; Make PORTB pin 0 input for flash mode button
LEDcount CON 8 ; Number of blinking LEDs on PORTA
' BL1,BL2,BL3,BL4,BL5,MCLR,STB
OnTimes DATA 50 ,22 ,38 ,75 ,17 ,2 ,2 ; default "on" periods for each output
OffTimes DATA 150 ,45 ,38 ,95 ,117,2 ,48 ; default "off" periods for each output
; (Strobe flashes 2 times per second
; or every 500ms; subtract "on" time)
' Running lights will be handled slightly differently
' FlashMode Values
' ================
' 0 = 1-1/2 sec (36 frames) on, 1/2 sec (12 frames) off (Trek Ace, HobbyTalk)
' 1 = 1/2 sec (12 frames) on, 1-1/2 sec (36 frames) off (Master Replica model)
' 2 = 3/4 sec (18 frames) on, 5/6 sec (20 frames) off ("The Corbomite Maneuver")
FlashMode_Default CON 0
EE_FlashMode DATA FlashMode_Default
FlashMode VAR BYTE
READ EE_FlashMode, FlashMode
;----------------------------------------------------------------
#DEFINE USE_RANDOM_SEQUENCE ; comment for contiuous Sequence
#IFDEF USE_RANDOM_SEQUENCE ; randomization used for BL1-5 only
RND VAR WORD : RND = 13864
MIN_ON CON 15 ; Minimum random ON time
MAX_ON CON 115 ; Maximum random ON time
MIN_OFF CON 15 ; Minimum random OFF time
MAX_OFF CON 200 ; Maximum random OFF time
RandPeriod VAR WORD[LEDcount-3]
RandPeriods DATA WORD 1000, WORD 1250, WORD 1500, WORD 1750, WORD 2000
#ENDIF
CCPR1val CON EXT : @CCPR1val = (OSC*1000000/4)/ BLINKYFREQ
;CCPR1 VAR WORD EXT : @CCPR1 = CCPR1L
Timer1 VAR WORD EXT : @Timer1 = TMR1L
CCPIF VAR PIR1.2
LoopLED VAR BYTE[LEDcount]
OnTime VAR BYTE[LEDcount]
OffTime VAR BYTE[LEDcount]
x VAR BYTE
LED_STDY_ON VAR PORTB.1 ; Alias PORTB.1 as "LED_STDY_ON"
;Old_FlashMode VAR BYTE
PRI_HULL_LGHTS_ON_MS VAR BYTE
PRI_HULL_LGHTS_OFF_MS VAR BYTE
;----[Initialize on/off periods & random sequencing (if enabled)]---------------
; (only set up first 7 blinkies; the 8th [running lights] is separate)
FOR x = 0 to (LEDcount - 2) ; Load the periods from EEPROM
READ OnTimes+x, OnTime(x)
READ OffTimes+x, OffTime(x)
#IFDEF USE_RANDOM_SEQUENCE
IF x < 5 THEN
READ RandPeriods+(x<<1), WORD RandPeriod(x)
ENDIF
#ENDIF
NEXT X
GOSUB SetFlashRates ; Set up flash rates based on saved "FlashMode" val
;-- setup CCP1 and Start Timer1 --
CCPR1 = CCPR1val ; set compare value
CCP1CON = %00001011 ; compare mode, special event
Timer1 = 0 ; clear Timer1
T1CON.0 = 1 ; start Timer1
HIGH LED_STDY_ON ; Turn on steady-on LEDs
;----[Main Program Loop]----------------------------------------
Main:
x = (x + 1) // LEDcount
PORTA.0(x) = !!(LoopLED(x) < OnTime(x))
LoopLED(x) = (LoopLED(x) + 1) // (OnTime(x) + OffTime(x))
#IFDEF USE_RANDOM_SEQUENCE
IF x < 5 THEN
RandPeriod(x) = RandPeriod(x) - 1
IF RandPeriod(x) = 0 THEN
READ RandPeriods+(x<<1), WORD RandPeriod(x)
RANDOM RND
OnTime(x) = (MAX_ON - MIN_ON)* RND.HighByte / 255 + MIN_ON
OffTime(x)= (MAX_OFF - MIN_OFF)* RND.LowByte / 255 + MIN_OFF
ENDIF
ENDIF
#ENDIF
IF x != (LEDcount - 1) THEN Main
Waiting: IF !CCPIF THEN Waiting
CCPIF = 0
GOTO Main
SetFlashRates:
If FlashMode = 0 Then
PRI_HULL_LGHTS_ON_MS = 150
PRI_HULL_LGHTS_OFF_MS = 50
ElseIf FlashMode = 1 Then
PRI_HULL_LGHTS_ON_MS = 50
PRI_HULL_LGHTS_OFF_MS = 150
Else
PRI_HULL_LGHTS_ON_MS = 75
PRI_HULL_LGHTS_OFF_MS = 83
EndIf
OnTime(8) = PRI_HULL_LGHTS_ON_MS
OffTime(8) = PRI_HULL_LGHTS_OFF_MS
RETURN
END
What am I doing wrong? In case anyone is wondering, I only want to randomize RA0-4 flash rates. Also, RA5 (MCLR) is input only so I had to make that a dummy output pin.
Is there something special about RA7 because of Timer1?
-
Re: Single PIC to Blink 5 LEDs Independently?
Not really ...
Code:
OnTimes DATA 50 ,22 ,38 ,75 ,17 ,2 ,2 ; default "on" periods for each output
OffTimes DATA 150 ,45 ,38 ,95 ,117,2 ,48 ; default "off" periods for each output
nothing missing here ??? :rolleyes:
Alain
-
Re: Single PIC to Blink 5 LEDs Independently?
Alain - not sure what you're referring to. Although I'm using 8 LEDs the 8th one is set up differently. You can see that farther done in the code with the GOSUB. The second last '2's are for the dummy MCLR pin. Rolls eyes.
Darrel mentioned that the 'PORTB.0(x)' notation represents the offset from RB0, so maybe I'll try reverting to PortB but use 'PORTB.1(x)' to leave RB0 for the interrupt.
-
Re: Single PIC to Blink 5 LEDs Independently?
Ross,
if you have declared:
LEDcount CON 8
and
OnTime VAR BYTE[LEDcount]
OffTime VAR BYTE[LEDcount]
that will translates to an array indexed from 0 to 7, so
OnTime(8) = PRI_HULL_LGHTS_ON_MS
OffTime(8) = PRI_HULL_LGHTS_OFF_MS
Will not result in what you expect.
-
Re: Single PIC to Blink 5 LEDs Independently?
If the array is 0-based then it should be this:
OnTime(7) = PRI_HULL_LGHTS_ON_MS
OffTime(7) = PRI_HULL_LGHTS_OFF_MS
Oh, man - a real newbie mistake. Thanks Steve!
-
Re: Single PIC to Blink 5 LEDs Independently?
Been there, done that, missing hair to prove it!
-
Re: Single PIC to Blink 5 LEDs Independently?
That was it, all right. Code works as expected - no need to switch back to PORTB.1(x). Now all I have to do is add the interrupt and handler.
Thanks again, Steve - I poured over that code at 12:30 am last night but didn't spot that index error.
-
2 Attachment(s)
Re: Single PIC to Blink 5 LEDs Independently?
This may not be the right place to ask a technical question about the PIC 16F88 chip, but I thought I'd start here.
I've got the prototype working and have been focusing on the schematic/board layout to finish this project (finally). After getting back some test PCBs for the blinking LEDs, I noticed that the 5 steady on LEDs connected to PORTA.0 via a 2N2222A transistor are not as bright as the other 5 blinking LEDs connected to PORTB.1-6 (note that PORTB.0 is needed for a button and that PORTB.7-8 are used for other blinking lights). I've looked over the datasheet for the PIC 16F88 but I'm a bit confused by the current limitations on page 163 (18.0 Electrical Characteristics). I had hoped that by using a 10k resistor between the 16F88 pins and the base of the 2N2222A that I could sink more current and hence drive more LEDs (PORTA.0 will ultimately need to drive 10 LEDs (5 per side of the model - total of 200mA for PORTA) while each of PORTB.1-6 will drive 2 LEDs (total of 200mA for PORTB). I see that it says 'Maximum current sunk by PORTA/B: 100mA' but I thought that a transistor (maybe a MOSFET?) would work.
Am I dreaming here? Do I need to look for some other solution? I'd hate to move away from this single chip utilizing Darrel's most elegant code.
PBP Code: Attachment 6797
Eagle Schematic: Attachment 6796
-
Re: Single PIC to Blink 5 LEDs Independently?
I am not sure that I understood what you want to do. But looking on your schematic, I really do not think that is a good idea to have a pot drive the collector of the 2N2222 and then the transistor drive a load of 200mA. It is not good practice.
If you need to control the power to your load, then a PWM controlling the base of the transistor is sure more appropriate.
Ioannis
-
Re: Single PIC to Blink 5 LEDs Independently?
I got the design from another source. The idea was to provide a way to control the brightness of the LEDs without having to have the trim pot inside the model (the PCB will be in a base for easy access).
The trim pots work great for all the other instances, just not the 5 steady-on LEDs. Also, I cannot use PWM in this code at all - it completely throws off the blinking algorithm created by Darrel.
-
Re: Single PIC to Blink 5 LEDs Independently?
I've looked at your schematic, and im not sure what you are doing with those transistors. Are you using them just to turn on and off the leds? is your pots there, to tune the current for the leds?
I use N-Mosfets, instead of transistors, they act more like a switch, transistors turn on more the more voltage/current their fed, but a fet can be turned on fully with a minimal of power. You can drive a FET directly from the chip, no resistor needed. heres what I would do, +5v to Pot Pin 1, Gnd to Pot Pin 3, Pot Pin 2 goes to LED +, LED- goes to FET Drain, FET Source goes to GND, FET Gate goes directly to PIC PIN. this allows to to turn on and off your LEDs with very little to no current/voltage loss on the FET, all FETs will be turned on the same ammount. FETs do not get as warm as regular transistors and can usually handle more current.
The only thing I see a problem with is how many LEDs in parallel you hook up to each POT, You can turn on a LED with 10-25ma, if you have 5 turned on and running at 125ma, that may cause a wattage problem for the POT. But this may not be a problem, It all depends on application and use.
#1 though, you shouldnt be sinking or driving LEDs to the PIC directly, its fine to do this on a breadboard for testing and such, however if your using many leds, its good to throw in a resistor. That notice on how much the chip can sink current wasnt placed there so you could sink current from leds, its a electrical rating for the chip for all outputs, when you hook up a button with a debounce circuit, the chip has to sink som of that current, each pin that has a high input with a resistor that the pic makes low, has to sink current. all these add up, if you start adding LEDs thats alot more it has to handle. It can make the chip work eratic, or fail, it may not happen today or tomarrow. best to just use the pins for data or drive another device to handle the voltage/current.
OH there is also another good reason to use FETs, you can use a seperate voltage source of a much higher voltage, you could drive 12volt headlights on a car using the right FET and they would behave just like the LED, or a Motor, or lots of things. Like I said a FET is like a 1-Direction Switch, either on or off.
Have fun, your project sounds interesting. I did the same type of project a few months back with very little code, not much different than yours. I just now read your thread so I didnt have a chance to post code before you got it working the way you wanted. good luck. :)
-
Re: Single PIC to Blink 5 LEDs Independently?
The transistors are there so I can drive up to 10 LEDs per PIC pin. The trim pots are to control the LED brightness (via current change).
-
Re: Single PIC to Blink 5 LEDs Independently?
try the N-Mosfets out, I think you will end up liking them better than transistors. if you have a company name and a .com email you can get free samples from Fairchild Semiconductor to test them out. their "BS270" is very good, handles 400ma with a 5ohm resistance, but up to 2 amps with pulses. thats enough without the pulses to drive 25 leds.
below is an example of how to hook them up, very easy and once you get into MOSFETS they tend to end up in tons of your projects :)
http://peu.net/temp/rgbschem.gif
this is not my schematic, but it looks like a circuit i would build.
-
Re: Single PIC to Blink 5 LEDs Independently?
I have some BS170's so I'll give those a try.
If I still want to implement LED brightness control with the code Darrel came up with earlier in this thread, I wonder if there is a way to combine this with his SPWM_INT.bas module; instead of just setting the port pin high (on), send a SWPM at a user-adjustable duty cycle for the duration of the 'on' period.
-
Re: Single PIC to Blink 5 LEDs Independently?
you can do that easily if you want them all to dim at the same rate using the PICs PWM going into the gate of a seperate FET with its drain tied to all the fets, sources. and its source to ground, this adds a ~.5v voltage drop but you can compensate by adjusting your pots.
I did this on a guys truck, he wanted 2 sets of floorboard lights, operated from a single pushbutton, but he also wanted to control their brightness, it was easy enought to set a 2 bit binary output to 2 FETS, and have them tied to a 3rd FET that was drivin by the PWM pin. and I just used a POT to set the PWM, and a button to select the lights (left, right, both, off).
-
Re: Single PIC to Blink 5 LEDs Independently?
you could also use the pulseout ant treat the FET's like a servo, and adjust duty cycle from 0 to 100,
also have a look at my post about adding PWMs to pics that have none or need more.
-
Re: Single PIC to Blink 5 LEDs Independently?
Quote:
Originally Posted by
wdmagic
you can do that easily if you want them all to dim at the same rate using the PICs PWM going into the gate of a seperate FET with its drain tied to all the fets, sources. and its source to ground, this adds a ~.5v voltage drop but you can compensate by adjusting your pots.
I did this on a guys truck, he wanted 2 sets of floorboard lights, operated from a single pushbutton, but he also wanted to control their brightness, it was easy enought to set a 2 bit binary output to 2 FETS, and have them tied to a 3rd FET that was drivin by the PWM pin. and I just used a POT to set the PWM, and a button to select the lights (left, right, both, off).
But did the LEDs blink? It sounds like your LEDs were steady-on with brightness control. For my application, I need to control the brightness of blinking LEDs. You can see the full code file above (created by Darrel) but I think the relevant portion is:
Code:
CCPR1val CON EXT : @CCPR1val = (OSC*1000000/4)/ BLINKYFREQ
;CCPR1 VAR WORD EXT : @CCPR1 = CCPR1L
Timer1 VAR WORD EXT : @Timer1 = TMR1L
CCPIF VAR PIR1.2
;----[Initialize on/off periods & random sequencing (if enabled)]---------------
; (only randomize first 5 blinkies; 6th is strobe which must remaing constant)
; (running lights (7th) are set up separately)
FOR x = 0 to (LEDcount - 2) ; Load the periods from EEPROM
READ OnTimes+x, OnTime(x)
READ OffTimes+x, OffTime(x)
#IFDEF USE_RANDOM_SEQUENCE
IF x < 5 THEN
READ RandPeriods+(x<<1), WORD RandPeriod(x)
ENDIF
#ENDIF
NEXT X
;-- setup CCP1 and Start Timer1 --
CCPR1 = CCPR1val ; set compare value
CCP1CON = %00001011 ; compare mode, special event
Timer1 = 0 ; clear Timer1
T1CON.0 = 1 ; start Timer1
;----[Main Program Loop]----------------------------------------
Main:
' Check if flash mode has changed
IF FlashMode <> Old_FlashMode Then
Old_FlashMode = FlashMode
GOSUB SetNavLtsFlashRates
EndIF
x = (x + 1) // LEDcount
PORTB.1(x) = !!(LoopLED(x) < OnTime(x))
LoopLED(x) = (LoopLED(x) + 1) // (OnTime(x) + OffTime(x))
#IFDEF USE_RANDOM_SEQUENCE
IF x < 5 THEN
RandPeriod(x) = RandPeriod(x) - 1
IF RandPeriod(x) = 0 THEN
READ RandPeriods+(x<<1), WORD RandPeriod(x)
RANDOM RND
OnTime(x) = (MAX_ON - MIN_ON)* RND.HighByte / 255 + MIN_ON
OffTime(x)= (MAX_OFF - MIN_OFF)* RND.LowByte / 255 + MIN_OFF
ENDIF
ENDIF
#ENDIF
IF x != (LEDcount - 1) THEN Main
Waiting: IF !CCPIF THEN Waiting
CCPIF = 0
GOTO Main