Dimming Leds with ULN2803

Thread Starter

MCrowe

Joined May 29, 2011
69
Cool, thanks for that. I like the idea of the shift register. I actually have some, as I was thinking of useing them before I went with the transistor array IC. As I said, I really wanted to leave the PWM modules alone as I was going to use them for my next very similiar project. But maybe I can use my servo driver instead and run brushless motors if I can get gearheads for them, or Brushed motors if I can get ESC's for them.

So, like I said, I dont know much about transistors. But if I just go ahead and build the transistor circuit Ernie posted it should be good right. OK good. Ill build it. Cheers.
 

SgtWookie

Joined Jul 17, 2007
22,230
Using an AND gate works, you would need 2x quad NAND gate ICs.

You could also gate the supply voltage to the LEDs like so:



Both transistors are either full off or on saturated so they shouldn't dissipate much power.
The schematic is quite work-able, but the resistor values are rather large. This will cause Q1 to fall out of saturation with a significant load of LEDs.

Don't know what your LED current is, so I'll just assume 20mA at the moment. Since you're using a ULN2803/8 LEDs, I'll also assume 8*20mA = 160mA total current required.

The 2N2907 is rated for up to 800mA continuously, but that's really pushing it. 500mA is a more realistic limit. With that high of collector current, you'd probably see a Vbe of around -1v.

So, to calculate the base resistor for a 160mA load, we'll use:
Rbase = (Vin - Vbe) / (Ic /10), where:
Vin = the voltage on the other side of the base resistor, relative to the emitter voltage.
Vbe = the voltage across the base and emitter, using the emitter as a reference point. This is typically 0.7v under a light load, but increases as Ib (base current) increases.
Ic = desired collector current.

Substituting:
Rbase = (-12v - -1v) / (-160mA / 10)
Rbase = -11v / -16mA
Rbase = 687.5 Ohms. That's a non-standard value, but 680 Ohms is.

For the base return resistor R1, you could use 3x to 5x the base resistor value; it's not very critical for such a low speed application.

So now you need to sink 16mA via Q2, which requires 1.6mA current on it's base.

I'll assume that you're supplying the PIC with Vcc=5v. Since Q2's collector current will be relatively small, I'll use 0.7v for Vbe.
Rbase = (5v-0.7v) / (16mA / 10) = 4.3v/1.6mA = 2687.5 Ohms, another non-standard value. 2.7k Ohms is plenty close enough. Keep in mind that your PIC I/O pins have a source/sink limit; make sure you don't exceed that.

You'll need to re-calculate your resistor values depending on your Vsupply and your desired load current. If your base currents are too low, you'll wind up with your transistors coming out of saturation, and very hot transistors/dim LEDs. If your base currents are too high, you'll be wasting power.
 
Last edited:

Thread Starter

MCrowe

Joined May 29, 2011
69
Ah, is this correct??

Not sure about some of the values I was trying to change..
Is it better to have larger or smaller resistors than calculated in certain spots?

And where I divide by 10, is that the gain of the transistor?

So I have 5v to PIC.
12v to LED's
3x LEDs at a time @ 25mA each. (75mA)
And PIC can sink/source max of 25mA.

Sooo, should this work? Sorry I keep having to ask but I really have trouble with transistors. Actually, I think I do understand it. (I've been writing this post for about 2 hours) so 10 is the gain right? So that why you divide by 10 to get the current at the base of Q1 and then the current needed as the output of Q2 (input of Q1) is 75mA/10, and at the base of Q2 75mA/10/10. Right. So does that mean the PIC is only sourcing .75mA?? That seems very low. OK, so maybe only slowely getting there.
 

Attachments

ErnieM

Joined Apr 24, 2011
8,377
Right, 10 is the current gain of the transistor. So 75mA out the collector of Q1 needs 75/10 = 7.5 mA thru the base, and 7.5 mA into the collector of Q2 needs 7.5/10 = .75mA into the base. (You have a typo computing Rbase for Q2 but got the correct value).

Those are minimum values for R2 and R3, you could go somewhat higher as the gain of 10 is a very conservative (but quite acceptable) value. The value of 10 used to measure Vce saturation is sometimes called the forced beta (gain), but the device still works albeit with a higher sat voltage if you use a higher value for gain.

R1 is small, though just about anything there will work. It's purpose is to give the small current that flows B to C (when Q1 is off) someplace to come from outside of the transistor. Without that resistor it must come from the emitter, which is only 50nA when Vbe is 0.5V (still very off), or 0.5/50nA= 10 meg ohms. That's a max value, anywhere between the 4.7K and 10,000K is fine.
 

SgtWookie

Joined Jul 17, 2007
22,230
You did just fine on your calculations, and it should work with no problems.

In cases where you are using a transistor as a saturated switch, you use a "forced beta" of 10, or a gain of 10. Sometimes you can "get away with" using a higher forced beta, but your Vce (voltage on the collector as measured from emitter) can start to become excessive, which means power dissipation (heating) in the transistor. Not all transistors are equal. Using the forced beta of 10 gives you the best chance of having the circuit work correctly.

It can be difficult to learn transistors. Using them as saturated switches is pretty easy though; not much to remember except you need 1/10 of the desired collector current going through the base.

You always want to start from the load end, and work backwards towards whatever is controlling the transistor base current. For a PIC, make sure that you don't approach the maximum I/O current, or your circuit will be more likely to fail.
 

Thread Starter

MCrowe

Joined May 29, 2011
69
Yeah sure, Ill post it as later today if I get a chance. What is the font meant to be on to maintain correct spacing? I have tried putting code tags around my code but ti doesn't work properly still. I think the font is wrong. Its almost impossible to get the correct spacing. Especially with larger code. Oh, that, and its written in to a larger program so ill try and pull out the relevant bits. Shouldn't be hard, as it just runs as an interrupt. I think it was your code I started working with? But I was very new at this and couldn't reverse engineer it so I decided to write my own. It basically works the same as your, I think? but I think yours had all the servo pulses together and then sent the signal low for as long as necessary to pad out the full 20ms. Is that right? But I made mine so that you divide the 20ms into how ever many servos your using. 1 to 8. Knowing that the max high time is 2.4ms. and 20 / 8 is 2.5ms. So, say your using 8 servos, you subtract that particular servos high time from 2.5 to get the low time. Make sense? If you using 4 servos, you subtract the serovs high time from 5ms (20/4).. Any way, ill post it as soon as I get a chance if you want to have a look at it. Cheers.
 

Thread Starter

MCrowe

Joined May 29, 2011
69
Wondered if any one could shed some light on a quite annoying problem I can't seem to solve.
What the $#!T. Was that some sort of weird pun my sub-conciousness dreamed up when I was first starting this thread... "Shed some light", problem with LED's?? really..

Any way,

Rich (BB code):
; INTERRUPT VECTOR JUMP ADDRESS
; ------------------------------------------------------------
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
org  H'04'   ; INTERRUPT VECTOR JUMP ADDRESS..
;  bcf  INTCON,7
;  BTFSC INTCON,2 ;TIMER0 OVERFLOW INTERRUPT.
;  GOTO TIMER0interrupt
 movwf   W_ISR           ; save main program context        
 swapf   STATUS,W        ;                                 
 movwf   S_ISR           ; save STATUS reg                 
 clrf    STATUS          ; force bank 0                    
 movfW   FSR            ;                                 
movwf   F_ISR           ; save FSR from MAIN                
movfw ISR_FSRsave  ; Restore FSR for Interrupt    
movwf FSR    ;          
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
;*****************************************************************************
;used to work out if any pins are high or all pins are low. and branch ;*
BTFSC PortFlag,1  ; CHECK IF FLAG (PORTD) BIT IS HIGH   ;*
GOTO DriveHigh  ; SKIPPED IF PORTD IS ALREADY ZEROS.  ;*
;else will SHIFT HIGH BIT.. making curret bit low.     ;*
;*****************************************************************************
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;DriveLow
 
;this section uses servo pulse to work out period, & sets servo high into timer.
;also calculate servo low time (period) and store in period register.  
 movfw   INDF           ; Servo[x] pulse. low byte, 600..2400   (CONTAINS SERVOxL) 
SUBWF   PeriodL,F  ; CALCULATES LOW BYTE OF PERIOD AND SAVES IN PeriodL REGISTER
MOVWF CCPR1L   ; should put servoLx in timer low       
 
incf    FSR,F           ;                                 
 movfw   INDF           ; Servo[x] pulse high byte, 600..2400   (CONTAINS SERVOxH)
BTFSS  STATUS,C    ; Test if Carry occured.
DECF PeriodH,F  ; If Carry occured, decrement PeriodH store back in File 
SUBWF   PeriodH,F  ; CALCULATES HIGH BYTE OF PERIOD AND SAVES IN PeriodH REGISTER
MOVWF CCPR1H   ; should put servoHx in timer High
;Sets Pin High (Pin is SHIFTED in next part of Subroutine.)
MOVFW PortShadow
MOVWF PORTE   ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
BSF  PortFlag,1  ; Set FLAG for test at start.
incf    FSR,F        ; INCREMENTS FSR ready for next time.
GOTO ISR_EXIT  ; 
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
DriveHigh        ;drives all pins low and set servo x low time (period)
;this section set Servo into timer.
MOVFW PeriodH   ;# ;Period times were calculated when storing Servo High times
MOVWF CCPR1H   ;# ;So now can just store in Timeer Register.
MOVFW PeriodL   ;# ;Period will be (20,000 / (ANY between 1&8) - Servo High Time.)
MOVWF CCPR1L   ;#
clrf PORTE   ;#
;#################################
 
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;RESTORE PERIOD TIME 
MOVLW HIGH D'6667' ;needs to be 6667 ;start with period normal. (20000 / (number of channel used 1...8))
MOVWF PeriodH
MOVLW LOW D'6667'
MOVWF PeriodL
;^^^^^^^^^^^^^^^^^^^^^^^^
;Clears PORTFLAG ready decision next time, and rotates PortShadow PIN.
bcf  PortFlag,1  ; Clear flag, so next run selects for PERIOD (Low part of signal)
clrc     ; clear carry to stop high bit being brough in.
RLF  PortShadow,F ; 00000001 <----- will rotate bits through Port Shadow.
 
;need to check incase I moved bit into carry.
;TESTS WHAT CHANNEL I AM UP TO. WILL NEED TO TEST CARRY IF I WANT FULL 8 BITS.
BTFSS PortShadow,3 ; IF PAST NUMBER OF REQUIRED SERVOS SKIP NEXT.    
GOTO ISR_EXIT  ; If STILL WITH REQUIRED SERVOS go to end of ISR.
MOVLW B'00000001'  ; If TIME FOR RESET, reset Count and Pin Select. 
MOVWF PortShadow  ; reset PortShadow to initial position '00000001'
 movlw   Servo           ; add Servo[0] base address  
movwf   FSR             ; setup indirect address 
ISR_EXIT
;^^^^^^^^^^^^^^^^^^^^^^^^^^
BCF  PIR1,2      ;BIT 2 IS CCP1F (CCP1 INTERUPT FLAG BIT) CLEAR SHOULD RESTART INTERRUPT. (WORKED IN TEST, GOOD)
EXITEXITEXIT
;^^^^^^^^^^^^^^^^^^^^^^^^^^^
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
;Save ISR and restor it on interrupt.           %
movfw FSR    ;          %
movwf ISR_FSRsave  ; Save FSR from INTERRUPT    %        
 movfw   F_ISR          ;                                 
 movwf   FSR             ; restore FSR                   
 swapf   S_ISR,W         ;                               
 movwf   STATUS          ; restore STATUS                 
 swapf   W_ISR,F         ; don't screw up STATUS         
 swapf   W_ISR,W         ; restore W-reg                 
 retfie                  ; return from interrupt         
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
]


So, In this part
Rich (BB code):
;RESTORE PERIOD TIME 
MOVLW HIGH D'6667' ;needs to be 6667 ;start with period normal. (20000 / (number of channel used 1...8))
MOVWF PeriodH
MOVLW LOW D'6667'
MOVWF PeriodL
You need to change the Period to how many servos you are using. So with 6667 I was using 3 servos. for 4 servos use 5000.



And this line,
Rich (BB code):
  BTFSS PortShadow,3 ; IF PAST NUMBER OF REQUIRED SERVOS SKIP NEXT.
Just change the number, (currently 3) to how ever many servos you want. Must match with the Period numbers.
 

Thread Starter

MCrowe

Joined May 29, 2011
69
Had to post seperately because my post got too long...

And this is just the initilisations. You will need to remove the things you dont want. I think I was using PWM on CCP2 which you DONT want. Maybe. Im sure you can figure it out. Should only run TIMER 1 in Special event mode.
Rich (BB code):
Rich (BB code):
InitTimers
MOVLW B'11000000'    ; ENABLES PERIPHAL INTERRUPTS. (SO I CAN USE PIE1) AND (BIT 5 FOR TIMER0 INTERRUPT.)
MOVWF INTCON     ; CONTAINS ENABLE AND FLAG BITS. (BIT7=GLOBAL INT ENABLE) (BIT6=PERIPHERAL INT ENABLE)  
MOVLW D'50'
MOVWF TMR0;TIMER0  ;~
bsf  STATUS,RP0
MOVLW B'11000011'    ;SET STUFF FOR TIMER0
MOVWF OPTION_REG    ;RBPU, INTEDG, T0CS (Clock Source, T0SE (Source Edge), PSA (Prescale assign), PS2 (pre-scale bits x3), PS1, PS0
MOVLW B'00000100'    ; ENABLE INTERRUPTS FOR TIMER 1. (INTERRUPT CONTROL REGISTER) CCP1IE (INTERRUPT ENABLE FOR CCP1.)
MOVWF PIE1      ; CONTAINS ENABLE BIT FOR INTERRUPTS
bcf  STATUS,RP0
 
MOVLW B'00000000'    ; CLEAR FLAG BIT TO ENABLE INTERRUPT?
MOVWF PIR1     ; CONTAINS FLAG BITS FOR INTERRUPTS.
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
movlw   HIGH d'20000'   ;~    ;timer1                              
MOVWF CCPR1H   ;~
movlw   LOW d'20000'    ;~                                 
MOVWF CCPR1L   ;~
;~
MOVLW B'00000001'  ;~  ;NOT USED <7:6>  |  PRESCALE<5:4>  |  OSCILLATOR ENABLE <3>  |  EXTERNAL CLOCK SYNC <2>  |  CLOCK SOURCE <1>  |  TIMER ENABLE<0>
MOVWF T1CON ;timer1 ;~  ;NOT SURE ABOUT OSCILATOR ENABLE BIT??? but is working fine.  
;~
MOVLW B'00001011'  ;~  ; SETS CCP1 (CAPTURE COMPARE MODULE 1) TO SPECIAL EVENT TRIGGER MODE
MOVWF CCP1CON;timer1 ;~  ; WILL RESET TIMER 1, AND GENERATE AN INTERRUPT and starts an AD conversion if enabled.
And last but not least, I apologise for the fact my code looks like apsolute crap. I've tried fixing it up but there is too much and I dont have time right now. Sorry. I used Code tags, changed font to Courier New and all that, but it still completely killed my spacings. The lines were all nice and neat, and indented and such. Looking at it here its almost impossible to read. Maybe if you want to try using it, copy it and past it into MPLAB and it might sort its self out again. I dont know. Also, Im still working on this code so it is a bit of a mess, but it does work. AND, some of my comment are probably incorrect as I was trying to figure out what everything did as I was programming and made a few rash assumptions.
 

Thread Starter

MCrowe

Joined May 29, 2011
69
Sooo, the circuit suggested work perfectly. Got my leds all coming on in a nice sequence with dimming and all. But....

They weren't bright enough. So I've upgraded to 350mA (1W) CREEs. This is going to be difficult isn't it? The above circuit (with changes to the resistors) wont work with 3W or power will it? I by asking that question I mean I know it won't. SgtWookie said I should be looking at more than about 500ma through that transistor. So. Whats the best way to go about powering these LED's.

My source is a 12v supply. Only need 3 Leds on at a time. At 350ma each max. I have a constant current source driver for them already with, I think, a "PT4115" chip on it. I have also read that it might be possible to add dimming to the existing driver which would make things much easier.

This is the driver I have. And I have tried it with 3 Leds at it works as expected.
http://www.dealextreme.com/p/mr16-3...rrent-regulated-led-driver-12-16v-input-13555

Its mentioned in one of the posts that I could add dimming to the drive circuit. Is this possible just with the PWM output from a Pic 16f877a?

Also, Im using the ULN2803 as a low side driver. <- is that the correct way to say it?
So that I can choose which LEDs are on, and the high side LED driver to PWM them for dimming.

So my other question is, can the ULN2803 handle this current? Im not good with transistors. Is it 500mA all up, or each channel/pin?

EDIT: I just found a different data sheet for the same device ULN2803 that says its 500ma for each pin. So it looks like that side of things is ok. Just the High side driver I need help with.

EDIT2: I have also found a much better data sheet for the PT4115. As long as that is the actualy chip on my LED driver this might be easy. It excepts PWM dimming. Can't wait to get home and find out now. Lol.

Thanks guys.
 
Last edited:

panic mode

Joined Oct 10, 2011
2,761
read datasheet, 500mA per channel for LN2803 is "Absolute Maximum" or "continuous current" if you can keep temperature low. normal operation is up to some 200-300mA.

ULN2803 is a low side driver, if you need high side driver, look at Allegro's UDN2981, UDN2982.
 

Thread Starter

MCrowe

Joined May 29, 2011
69
close but no cigar. I was only pulling 350mA per channel. max. More like 300ma but it was still too much. The ULN2803 was getting hot quick. But thats not my main issue.

I was using the LED driver (PT4115) as a high side driver with dimming, and the ULN2803 as a low side driver to control which lights were on. But it doesn't work. I think its something to do with the LED driver and the constant current feedback. I couldn't turn the LEDs all the way off at all, and the ULN2803 didn't really seem to have any control over what was on and what was off. It just changed things at random. some times all LEDs were on really bright some times all almost off, or 2 would be off, or half would be on half off. I really don't know why it doesn't work properly. Where should the ground for the ULN2803 and the Positive for the 2803 come from? The LED driver output or the source? I went with the ground for the ULN2803 going back to the LED ground outputs, as it needs this for current sensing doesn't it? I don't think this setup can work. Any ideas?
 
Top