SMALL - espritmodel.com SMALL - Telemetry SMALL - Radio
Reply
Thread Tools
Old Feb 07, 2013, 04:31 PM
We want... Information!
Bruce Abbott's Avatar
Hastings, New Zealand
Joined Jan 2001
5,182 Posts
Quote:
Originally Posted by dmccormick001 View Post
Bruce, I already have some NPN and PNP MOSFETs,
PNP/NPN only applies to bipolar junction transistors. MOSFETs have no junctions, so they are either P channel or N channel.

Quote:
Can I substitute them in this circuit without major problems?
MOSFETs are driven by voltage rather than current, so you need a circuit like the one in post #7 (original here).

Quote:
One of the motors I'm powering draws almost 3 amps for part of it's range...

Would you please look at the datasheets on the transistors above and tell me if they look OK?
Those FETs will be fine at that current.

Quote:
I'm a little concerned, especially about the PNPs, because, even though the datasheet says they are suitable for DC motors, etc., the internal diode looks to me like it's turned the wrong way, at least compared to some circuit drawings I've seen.
The diode is the right way around.

Quote:
Also, do I still need the pull-up resistors with these MOSFETs, same values, etc.? I'm planning to use PN2222As to drive the NPN MOSFETs, since they don't handle any of the motor's current, that will work OK, right?
Yes. You can substitute the 2N7002's with PN222A's, just insert a resistor (eg. 4k7) between the MPU output and the base of the driver transistor. The 2k2 pullup resistor is necessary to develop a voltage for driving the P channel FET's gate.
Bruce Abbott is offline Find More Posts by Bruce Abbott
Reply With Quote
Sign up now
to remove ads between posts
Old Feb 07, 2013, 10:27 PM
Dave the Rave
dmccormick001's Avatar
Joined Jun 2007
873 Posts
OK, Bruce, I have the bridge circuit working nicely, and the programming on my PIC (16F683) is detecting the input pulse from the Rx and switching the motor's direction properly. I even have the program reversable via a jumper that pulls an input pin to ground! Now I need to add the current sensing, but I'm just not sure how to implement it. I can't decide whether I should use the AD Converter, or the Comparator. I think I'm supposed to add a low-value resistor between one of the NPN transistors (T1 and/or T5) and source/ground, and input that to the ADC of the PIC. But even though I've read the datasheet about 100 tmes, I can't understand how to set up the registers, or how to write the code to make use of it. I understand that the ADC measures the input, and converts it to a variable, can I just use that number as a threshold to tell the program what to do? In other words if the variable is greater than XXX, GOTO HERE: ELSE GOTO THERE:? I have some variable resistors, 0-10 ohms, that take 25 turns from end to end, hoping to be able to use them to find the correct value for the current sensing resistor.

I need the current sensing so the motor doesn't keep turning after it has reached the end of it's normal travel, because it's so strong that it jams itself up if alowed to turn too long at either end. My goal is to get the program to sample the ADC every 1/2 second or so while the gear is moving, and brake the motor if the current goes above a normal level. That will also provide some protection against anything that might obstruct the mechanism.

I can't thank you enough for your help, Bruce. I always learn a lot when you answer my questions, and I really appreciate the time you take to do it.
dmccormick001 is offline Find More Posts by dmccormick001
Reply With Quote
Old Feb 07, 2013, 10:58 PM
Registered User
Joined Oct 2012
224 Posts
Quote:
Originally Posted by dmccormick001 View Post

I can't thank you enough for your help, Bruce. I always learn a lot when you answer my questions, and I really appreciate the time you take to do it.
Bruce Abbot work in shop hoppy. ? he is good hardware and software.----> my dream
fantasy1988 is offline Find More Posts by fantasy1988
Reply With Quote
Old Feb 08, 2013, 02:05 AM
We want... Information!
Bruce Abbott's Avatar
Hastings, New Zealand
Joined Jan 2001
5,182 Posts
Quote:
Originally Posted by dmccormick001 View Post
I think I'm supposed to add a low-value resistor between one of the NPN transistors (T1 and/or T5) and source/ground,
If you insert a resistor in the ground side of the bridge (connected to the Source leads of both N channel FETs) then you can measure the motor current in either direction. In order to avoid excessive voltage drop the sense resistor must have a very low value (<<1 Ohm). Another way is to use on resistance of the FET itself to measure current. This has the advantage of protecting the FET against any current that might damage it, but is less accurate because FET resistance varies with temperature.

In both cases the measured voltage is quite low and sensitive to stray ground currents, so it may need to be amplified before feeding it into the MCU. At the very least you should put a low-pass rc filter on the A/D input to reduce noise spikes.

Quote:
even though I've read the datasheet about 100 tmes, I can't understand how to set up the registers, or how to write the code to make use of it.
First you must enable analog input on the pin you are using, and set the A/D clock source and divider in the ANSEL register. Then you set the justification (Left for an 8 bit result in ADRESH), reference voltage source, and the channel you want to measure, in the ADCON register. Finally, power up the A/D unit by setting the ADON bit.

To do an A/D conversion you simply set the GO/DONE bit and wait for it to clear, then read the value from ADRESH/ADRESL.

Here is some example code:-
Code:
;==============================================================
;            PIC12F675 A/D conversion example
;==============================================================

	banksel	TRISIO		; select register Bank 1

; set up I/O port directions
	movlw	1<<GP0		; GP0 is an input
	movwf	TRISIO		 

; select A/D clock source and analogue input(s)
	movlw	((1<<ADCS0)|(1<<ANS0)) ; clk/8, Analog I/O on GP0
	movwf	ANSEL		

	banksel	0		; select register Bank 0
	
; set up A/D convertor and turn it on
	movlw	(1<<ADON)	; left-justified, Vref=Vdd, channel 0, A/D on
	movwf	ADCON0
	.
	.
	.

; Do an A/D conversion
	bsf	ADCON0,GO       ; start A/D conversion
wait_ad:
	btfsc	ADCON0,GO       ; wait until done
	goto	wait_ad
	movf	ADRESH,w        ; get 8 bit result

Quote:
I understand that the ADC measures the input, and converts it to a variable, can I just use that number as a threshold to tell the program what to do?
Yes. For example, if your reference is Vdd at 5V and you are reading 8 bits, then each step is 5V/256 = 0.0195V, and a value of 10 would be ~0.2V.

Quote:
I have some variable resistors, 0-10 ohms, that take 25 turns from end to end, hoping to be able to use them to find the correct value for the current sensing resistor.
You probably need about 0.05 Ohms, which should be within the range of that pot. Just be careful to avoid long wires which could increase resistance and inductance.

Quote:
My goal is to get the program to sample the ADC every 1/2 second or so while the gear is moving, and brake the motor if the current goes above a normal level. That will also provide some protection against anything that might obstruct the mechanism.
The current measurement will probably be quite noisy, so I would read it often and take a running average. If this averaged current goes over the threshold then I would switch the motor off immediately. That way a short current spike which goes slightly over the threshold won't stop the motor, but it will still respond quickly to a genuine stall condition.
Bruce Abbott is offline Find More Posts by Bruce Abbott
Last edited by Bruce Abbott; Feb 08, 2013 at 02:12 AM.
Reply With Quote
Old Feb 08, 2013, 10:05 AM
Dave the Rave
dmccormick001's Avatar
Joined Jun 2007
873 Posts
Quote:
Originally Posted by Bruce Abbott View Post
The current measurement will probably be quite noisy, so I would read it often and take a running average. If this averaged current goes over the threshold then I would switch the motor off immediately. That way a short current spike which goes slightly over the threshold won't stop the motor, but it will still respond quickly to a genuine stall condition.
I was planning to use a FOR/NEXT Loop (I use PIC Basic Pro, I'm not too good at Assembly or even C) to allow the motor to run until the current sensing part of the circuit detects a spike that indicates the end of the movement. It takes the unit about 6 seconds to go from end to end, so if I set it up to read the ADC channel once every 10ms, then add the reading together, that should give me an average every 1 second, would that be often enough? That would give me roughly 6 readings as the gear goes from up to down, or vice versa. Does this look close to what I need?

Code:
C  VAR  WORD  ; Variable to store individual readings from ADC
C1 VAR WORD   ; Variable to store combined readings from ADC

GEARUP:
   LOW PORTA.0
   HIGH PORTA.1

RUNUP:
    For X = 1 to 10
          C1 = 0
          ADCIN 0, C
                C1 = C1 + C
                PAUSE 10
                   NEXT X
     IF C1 > 10 (or whatever the right number turns out to be) GOTO BRAKE
          GOTO RUNUP

BRAKE:
      LOW PORTA.0
      LOW PORTA.1
Quote:
In both cases the measured voltage is quite low and sensitive to stray ground currents, so it may need to be amplified before feeding it into the MCU.
Can I do this with a transistor? Or do I use an Op Amp?

Thanks again!
dmccormick001 is offline Find More Posts by dmccormick001
Reply With Quote
Old Feb 09, 2013, 03:02 AM
We want... Information!
Bruce Abbott's Avatar
Hastings, New Zealand
Joined Jan 2001
5,182 Posts
Quote:
Originally Posted by dmccormick001 View Post
if I set it up to read the ADC channel once every 10ms, then add the reading together, that should give me an average every 1 second, would that be often enough? That would give me roughly 6 readings as the gear goes from up to down, or vice versa. Does this look close to what I need?
You have the right idea, but I think 1 second is too long when the motor might be drawing over 3A. I would make the pause 2 rather than 10, to get a timeout of ~200mS.

When you start the motor there will be an initial current spike as it gets up to speed. Your code handles this well because it collect 10 samples before thinking about braking. However it then takes another 10 samples before making the next decision, so the response to the motor stalling while running is slower that it could be.

If you modify the code to take a running average then it can respond faster. To do this, store the samples in a buffer array. After the first 10 samples have been summed and tested for over-current, subtract the oldest sample from the total so it now consists of samples 2-10. Then read the ADC again, store the new sample over the oldest one in the buffer, and add it to the total. You now have the sum of samples 2-11. Keep doing that (stepping through the buffer array to get to the next oldest sample) until you sense a current overload indicating that the motor has stopped.

The code below should work, but I don't have PIC Basic Pro so I can't guarantee there are no errors!

Code:
AMPS VAR WORD[10] ; buffer to store ADC samples
OC CON 1234       ; over-current threshold value
C1 VAR WORD       ; Variable to store combined readings from ADC

GEARUP:
     LOW PORTA.0
     HIGH PORTA.1

RUNUP:
     For X = 0 to 9
         C1 = 0
         ADCIN 0, AMPS[X]
         C1 = C1 + AMPS[X]
         PAUSE 2                ; wait 2mS between samples
     NEXT X
     IF C1 > OC THEN GOTO BRAKE

     X=0                        ; point to oldest sample in buffer 
WAIT_STALL:
     C1=C1-AMPS[X]              ; subtract oldest sample from total
     ADCIN 0,AMPS[X]            ; get new sample (overwriting oldest sample)
     C1=C1+AMPS[X]	        ; add new sample to total
     IF C1 > OC THEN GOTO BRAKE ; exit if over-current
     X=X+1	                ; point to next-oldest sample in buffer
     IF X > 9 THEN X=0          ; circular buffer 	
     PAUSE 2                    ; pause 2mS between samples
     GOTO WAIT_STALL            ; continue checking for over-current

BRAKE:
      LOW PORTA.0
      LOW PORTA.1

Quote:
Can I do this with a transistor? Or do I use an Op Amp?
You should use an opamp, as this will be more accurate at low voltage. However I would first try using the signal directly, without amplification. You can filter the signal using a resistor in series followed by a capacitor to ground (eg. 10k and 1uF). The resistor also helps to protect the ADC input from over-voltage.
Bruce Abbott is offline Find More Posts by Bruce Abbott
Last edited by Bruce Abbott; Feb 09, 2013 at 03:07 AM.
Reply With Quote
Old Feb 09, 2013, 04:42 PM
Dave the Rave
dmccormick001's Avatar
Joined Jun 2007
873 Posts
I'm getting real close, Bruce! The way you arranged that variable array, entering the newest measurements into it while replacing the oldest is something I would never have dreamed of doing. Very clever, and it taught me a lot about how you can use an array, I've never seen anything like that done before.

Here's where I'm at now: I tried the variable resistors, and I was mistaken, they would only go as low as ~1 ohm. So I scrounged around in an old charger I had and found a 1/10 ohm 1 watt precision resistor, and inserted it into the circuit. I connected the sources of both of the N-channel FETs together to one side of the resistor, and connected that junction to the input channel of the ADC. (I used channel 7 because I was already using the pin for channel 0 for something else) .The other side of the resistor went to ground. I have the threshhold for OC set to 3000. I also added a 2 second pause at the beginning of the RUNUP section to allow the motor to get moving before it began taking measurements. Finally, I added a 10k resistor in series with a .01uf ceramic disc cap to the input pin of the ADC. I'm not sure if that's how you meant for the filter, but that's the best I could figure looking at other circuits.

OK, if I remove the motor from the circuit completely, the program runs and does what it's supposed to do. I've put some LEDs on the outputs to the FETs so I can see which output pins are high and which are low. If I connect the motor, it runs until the 2 second delay is over and goes to BRAKE. (I also have a blue led that comes on once the program goes to the BRAKE section.) If I start the program with the motor disconnected, and then plug the motor up, it runs until it hits the end but never goes to BRAKE. If I remove the sense wire, the program runs continuously, and never goes to BRAKE, not matter what I do, so it seems that the sense circuit is doing something, but not consistently, and not predictably, either. I'm not sure if I should keep increasing the OC value, or if my current sensing resisitor is the wrong size, or if the code isn't quite right. I don't know how to calculate what size resistor I should be using, or how to determine what number the OC constant should be set to. If the ADC were returning the maximum number every time, it looks to me like C1 should never get bigger than 255 * 10, so I don't think making OC threshold larger than 3000 will solve anything.

I'm posting the code, the bridge circuit is the one from the link you posted to your website. My PIC is a 16F684, I have the MCLR pin pulled high with a 10K ohm. Any ideas?

Code:
;****************************************************************

;***** Set Configuration Fuses *****

__CONFIG
_INTRC_OSC_NOCLKOUT
_WDT_ON
_PWRTE_OFF
_MCLRE_OFF
_CP_OFF
_BODEN_ON

@    errorlevel  -302  ; Suppress message 302

;DEFINE OSC4             ; Sets up 4MHz internal oscillator
;DEFINE OSCCAL_1K 1      ; Use stored OSCCAL Value - REQUIRED -

DEFINE PULSIN_MAX 3000	; Maximum waiting time for PULSIN

ANSEL = 0       ; Set all inputs/outputs to digital
CMCON0 = 7      ; Analog comparators
ADCON0 = %10011101      ; Sets ADC inputs, Vref, and ouput
ADCON1.7 = 1


TRISA = 0      ; Set PortA outputs EXCEPT A.3 input
TRISC = 1      ; Set PortC to inputs

DEFINE ADC_BITS 10
DEFINE ADC_CLOCK 3      ; Sets ADC clock frequency

LOGICA  VAR PORTA.5     ; Output A to H Bridge
LOGICB  VAR PORTA.0     ; Output B to H Bridge
LOGICC  VAR PORTA.4     ; Output C to H Bridge
LOGICD  VAR PORTA.1     ; Output D to H Bridge
SW      VAR PORTC.0     ; Reversing switch or jumper
RX      VAR PORTC.1     ; Input from receiver

P       VAR WORD        ; Variable to store pulse width
PP      VAR WORD        ; Variable to store previous pulse width
R       var WORD        ; Variable to store reversing state (0 or 1)
X       var byte        ; Variable for loops
AMPS    VAR WORD[10]    ; Buffer to store ADC samples
C1      VAR WORD        ; Variable to store combined readings from ADC
OC      CON 3000        ; Over-current threshold value
                   
; **********************************************************************

INITIALIZE:        
        PAUSE 1000   ; Wait for PIC to stabilize
        R = 1
        IF SW = 1 then GOTO MAIN      ; Check for reversing switch closed
        R = 0

MAIN:
        LOW LOGICA      
        LOW LOGICB        
        LOW LOGICC        
        LOW LOGICD        ; Turn all outputs to motor off and Brake	
        		
RXIN:
        PULSIN RX,1,P      ; Input From Rx
            GOSUB REVRSE        ; Check reversing switch/jumper        
        IF (P < 90) THEN GOTO RXIN    ; Wait for Tx ON
        IF (P > 90) AND (P < 145) THEN GOTO GEARUP  ; Check gear switch on RX  
       	
GEARDOWN:
        HIGH LOGICB
        HIGH LOGICC
        
            GOTO MOTOR_RUN
     
GEARUP:
		HIGH LOGICA
        HIGH LOGICD      ; Outputs to rotate motor              
            
MOTOR_RUN:
          PAUSE 2000
          For X = 0 to 9
              C1 = 0
              ADCIN 7, AMPS[X]
              C1 = (C1 + AMPS[X])
              PAUSE 5                ; wait 2mS between samples
          NEXT X
          IF C1 > OC THEN GOTO BRAKE

          X = 0                        ; point to oldest sample in buffer
      
WAIT_STALL:
           C1 = (C1 - AMPS[X])              ; subtract oldest sample from total
           ADCIN 7, AMPS[X]            ; get new sample (overwriting oldest sample)
           C1 = (C1 + AMPS[X])	        ; add new sample to total
           IF C1 > OC THEN GOTO BRAKE ; exit if over-current
           X = (X + 1)	                ; point to next-oldest sample in buffer
           IF X > 9 THEN X = 0          ; circular buffer 	
           PAUSE 2                    ; pause 2mS between samples
           GOTO WAIT_STALL            ; continue checking for over-current

REVRSE:
       IF SW = 1 THEN     ; Check reversing switch/jumper state
             RETURN
       ELSE
             P = (300 - P)   ; Toggle value of pulse width if reversed
       ENDIF
             RETURN
            
BRAKE:
    LOW LOGICA      
    LOW LOGICB        
    LOW LOGICC        
    LOW LOGICD        ; Turn all outputs to motor off and Brake
    HIGH PORTA.2
    
    END
dmccormick001 is offline Find More Posts by dmccormick001
Reply With Quote
Old Feb 09, 2013, 09:57 PM
We want... Information!
Bruce Abbott's Avatar
Hastings, New Zealand
Joined Jan 2001
5,182 Posts
Quote:
Originally Posted by dmccormick001 View Post
I added a 10k resistor in series with a .01uf ceramic disc cap to the input pin of the ADC.
The capacitor must be wired in parallel, between the ADC input and Ground. To be effective it needs to be large enough to filter out spikes that are shorter than the measurement period. 10k+0.01uF will only filter out very short spikes (less than 0.5mS).

Simple RC Filter Calculator
Bruce Abbott is offline Find More Posts by Bruce Abbott
Reply With Quote
Old Feb 09, 2013, 11:04 PM
Dave the Rave
dmccormick001's Avatar
Joined Jun 2007
873 Posts
My mistake, I meant to say it is a .1uf cap.

I think I've found a (the?) problem. In the code you posted, there is a line inside the RUNUP section that sets the variable C1 to 0. The For/Next loop is supposed to get a measurement, then add it to C1 before comparing the result to the OC variable. But the C1=0 staement is inside the loop, and if I'm looking at it right, every time the loop comes back around C1 is re-set to 0 again. I moved it to right before the loop, and I think it's working now. A value of 100 for the OC variable causes it to go to BRAKE as soon as I connect the motor, but a value of 1000 allows it to run and it never goes to BRAKE. So like a Navy ship that's been "bracketed" by gunfire, I think I have it in my sights. I'm going to shrink the gap between those two numbers now and see what happens. I'll let you know.
dmccormick001 is offline Find More Posts by dmccormick001
Reply With Quote
Old Feb 10, 2013, 01:27 AM
We want... Information!
Bruce Abbott's Avatar
Hastings, New Zealand
Joined Jan 2001
5,182 Posts
Quote:
Originally Posted by dmccormick001 View Post
I think I've found a (the?) problem. In the code you posted, there is a line inside the RUNUP section that sets the variable C1 to 0. The For/Next loop is supposed to get a measurement, then add it to C1 before comparing the result to the OC variable. But the C1=0 statement is inside the loop,
You're right! It should be outside the loop. That's your code BTW, I just copied it.
Bruce Abbott is offline Find More Posts by Bruce Abbott
Reply With Quote
Old Feb 10, 2013, 07:56 AM
Dave the Rave
dmccormick001's Avatar
Joined Jun 2007
873 Posts
Is this the correct way to add the 1/10 ohm current sensing resistor and the low-pass filter components?
dmccormick001 is offline Find More Posts by dmccormick001
Reply With Quote
Old Feb 10, 2013, 03:10 PM
We want... Information!
Bruce Abbott's Avatar
Hastings, New Zealand
Joined Jan 2001
5,182 Posts
Quote:
Originally Posted by dmccormick001 View Post
Is this the correct way to add the 1/10 ohm current sensing resistor and the low-pass filter components?
No. The 10k resistor should be in series, like this:-
Bruce Abbott is offline Find More Posts by Bruce Abbott
Reply With Quote
Old Feb 10, 2013, 04:45 PM
Dave the Rave
dmccormick001's Avatar
Joined Jun 2007
873 Posts
OK, I'll change it. However, the good news is that it's working very well like it is! No telling how much better it will work once I fix the filter.

It allows the motor to run in either direction, and when it comes to the end it only takes it a fraction of a second to cut off. If I hold the gear with my hand while it's moving, it only takes a second or so to cut off, and I don't have to put too much pressure on it, either. I'm very happy with how that part of it is working. Now I'm adding the rest of the code to move the gear door servo(s), and I think I'm going to try to add a trim pot connected to the comparator to give us some speed reduction for the door servos.

Man, I've learned a lot about every part of it, from the circuit itself, to how to set up the PIC's registers, to using the ADC, and even how to put variables in an array. I can't thank you enough, Bruce. Hope I can return the favor someday, somehow. I'll post a video of the whole shebang once I get it all polished up.
dmccormick001 is offline Find More Posts by dmccormick001
Reply With Quote
Reply


Thread Tools

Similar Threads
Category Thread Thread Starter Forum Replies Last Post
Discussion Wiring/soldering help with 900mhx system pete914 FPV Talk 11 Jan 20, 2013 03:20 PM
Discussion dual h-bridge breakout board rocky79 DIY Electronics 0 Jan 19, 2013 12:50 PM
Help! need some electronic wiring help abletowinginc DIY Electronics 0 Jan 14, 2013 07:12 AM
Discussion Quad Wiring Diagram (Terminal Bridge) spackletoe Multirotor Talk 5 Nov 15, 2011 01:50 PM
Question H-Bridge circuit to dual polarity convertion help Angry_Monk Scratchbuilt Indoor and Micro Models 6 Aug 09, 2005 10:15 PM