I just got my first oscilloscope. Complex analog circuits are now possible. |
As I mentioned in my last post, I working on a power distribution unit (PDU) for motorcycles, cars, and other DC applications. The project is very close to the testing phase and that means I will need to run this device at precise power levels and at precise temperatures. The testing protocol also includes vibration studies, but today we are just going to talk about precision current testing.
This can be done many different ways. You can just put a resistor to ground and use Ohm's Law to tell you how much current you are burning. If you want to change the current in use though, you will have to change the resistor. That is not very handy if you want to test your power supply at multiple currents as you will need a lot of different resistors. Since my system is running at about 14V and I am talking about 15A of current, I'll need some pretty beefy resistors and those are expensive.
Instead, I've decided to purpose build a constant current dummy load. This uses a single logical load resistor (I will have parallel resistors but they will behave as one) and adjusts the voltage across it to define the current that gets burned. I searched Amazon and found a pair of 100W chassis mount 0.1Ω resistors for $7. My requirement for this testing tool is to be able to burn up to 15A which is the maximum current load I have defined for the device. Using Ohm's Law that means I'll need to to be able to adjust the output voltage between near 0V and 1.5V. If you put 1.5V across a 0.1Ω resistor you get 15A, so that is the plan. I have not done all the calculations necessary to nail down the exact output for a given input, but doesn't really matter because the input is linear from 0V to 1.5V and you will measure the output across the load and do your Ohm's Law calcs based on the precisely measured (4 wire) resistance for that specific load resistor. 200W is just a tad bit low (about 10W by the numbers) but I'll mount these on a heat sink with a fan around if necessary.
There are a couple of options I could select to get 1.5V on the output. I could use a voltage regulator to get a "precise" voltage, but that isn't really a good option. Regulator's are not that precise. Instead I'll use a voltage reference. The one I had in the drawer was a 2.048V reference and I can count on it to output exactly that figure. It is a high impedance output though so I'll need to do something else with that. I could setup an op amp and voltage follower and have a low impedance voltage source. With that, the standard thing to do would be to put a voltage divider in the circuit with a potentiometer to adjust that output to another op amp and put an output transistor in that amps feedback loop. I've decided to NOT do this though. I don't have any nice pots (10 turn or 1 turn), so I've decided to doing something with some digital components as well. I've decided to use a DAC (an MCP4921) to produce the voltage, based on the aforementioned reference. To control the DAC I need a micro-controller. I had a tube of ATTiny85 MCUs and that is just perfect for my needs. The ATTiny85 is an 8 pin MCU with 5 IO, Vcc, GND, and reset pins. The DAC requires 3 pins as it uses an SPI interface. That leaves me 2 pins to the human/machine interface. I have a drawer full of rotary encoders (like a digital pot). It outputs a quadrature code which essentially tells you what direction the knob is being turned. The MCU keeps track of the current state and adds or subtracts based on the encoder input and then sends a command to the DAC to change its output.
My DAC is referenced to 2.048V and it is 12bit so it will output a linear voltage between near 0V and 2.048V at 4096 equal steps. Since I want only 1.5V I'll put a static voltage divider in the circuit and send that to the op amps which are controlling the output transistor.
I've seen a couple projects like this on the internet and they all used a system to control the output transistor that I don't like. They use a MOSFET which I like, but they simply bias the transistor in it's Ohmic region so that it is being used as a variable resistor. That causes the MOSFET to produce a lot more heat than if it were being run fully "enhanced" or "saturated" (we are talking about N channel enhancement MOSFETs). If you fully enhance it, power flows through it at lower resistance and your MOSFET will run cooler. It also means your analog circuit will need to be able to do fast, and preferably rail to rail, switching to keep the current constant. If fast rail to rail switching is what you need, then a comparator is a good thing to use.
I am using three op amps in the output transistor loop. The DAC feeds a voltage follower op amp and its output feeds the positive input of another. It's output feeds the positive of a third whose output drives the gate of the MOSFET. The MOSFET output runs into the negative terminal of the latter two op amps. This gives me a rail to rail PWM signal to the gate of MOSFET such that for each .1V I put into the first op amp, 1A goes through the load resistor. A nice system and my MOSFET runs as cool as possible.
This is the first analog circuit I've designed and built. It was made possible by the introduction of an oscilloscope to my lab. I like it! You can see my love of digital electronics has not died by my introduction of the MCU and DAC to a circuit that could have been done just as well with a nice 10 turn pot. No matter, the encoders are a dime a dozen and small while 10 turn pots are pricey and large.
Another challenge faced in this project is the fact that I am running an SPI device on an ATTiny85. This is worth mentioning because the ATTiny doesn't have a hardware SPI interface so it needs to be done in software. I didn't see any examples of this on the interwebz, so I'll post it up here in case it's is of use to anyone. I should also mention that the DAC I am using is a MCP4921 in case someone searches for a way to use this chip with a ATTiny they won't have to reinvent this wheel. The important things to notice are the use of the word (16 bit number) and the shiftout, highbyte, and lowbyte functions I am employing. These are built into the Arduino tool chain so as long as you can handle your latch pin by yourself you are in business.
int del=0;
word outputValue = 0;
byte data = 0;
int val = 0;
int csPin = 0;
int sckPin = 1;
int siPin = 2;
int ENC_A = 3;
int ENC_B = 4;
void setup()
{
pinMode(csPin, OUTPUT);
pinMode(sckPin, OUTPUT);
pinMode(siPin, OUTPUT);
pinMode(ENC_A, INPUT);
pinMode(ENC_B, INPUT);
digitalWrite(ENC_A,HIGH); //these pins do not have pull up resistors on an attiny...
digitalWrite(ENC_B,HIGH); //you must pull them up on the board.
}
void loop()
{
int enc = read_encoderJOM();
if(enc != 0) {
val = val + (enc*10);
val = min(val,4095);
val = max(val,0);
setDAC(val);
}
delayMicroseconds(50);
}
void setDAC(int value) {
outputValue = value;
digitalWrite(csPin, LOW);
data = highByte(outputValue);
data = 0b00001111 & data;
data = 0b00110000 | data;
shiftOut(siPin, sckPin, MSBFIRST, data);
data = lowByte(outputValue);
shiftOut(siPin, sckPin, MSBFIRST, data);
digitalWrite(csPin, HIGH);
delay(del);
}
int oldENC_A = 0;
int oldENC_B = 0;
int8_t read_encoderJOM() {
int a0Pin = digitalRead(ENC_A);
int a1Pin = digitalRead(ENC_B);
int returnVal = 0;
if(a0Pin != oldENC_A || a1Pin != oldENC_B) {
if(oldENC_A == a1Pin && oldENC_B != a0Pin) {
returnVal = -1;
} else if (oldENC_B == a0Pin && oldENC_A != a1Pin) {
returnVal = 1;
}
oldENC_A = a0Pin;
oldENC_B = a1Pin;
return returnVal;
} else {
return 0;
}
}
Entire circuit except for the output transistor and the load resistor. Those are visible in the video above. |
Comments
Post a Comment