Sunday, March 29, 2015

A small power supply

As I mentioned in the previous post, I have been building a small bench power supply. It is loosely inspired by the instructable here. That design has a LM2596S module to convert from unregulated DC to regulated DC with voltage and maximum current controls, and a voltmeter/ammeter module for displaying the output levels. It also uses an Arduino to indicate whether the voltage or the current is limited. What I built omits this last part. I don't really see it as needed, as the module has a built in LED that conveys most of the same information. It's labelled CC/CV and is off when the voltage is limiting and on when the current is limiting; more on what this means in a moment. All I did was to unsolder the one that is built into the board and solder on an external LED, so I can bring it out to the front panel when I put it in a case. I did the same for the OK LED on the module. I also used a different meter. And finally, I omitted the on-off switch and the output on/off switch from the instructable design. So the final design looks like this:

(Image generated by MooseCAD).

The specific LM2596S module I used is this one, and the meter is this one. I bought both on ebay from a seller called nyplatform. Note that one difference with the original design is that the thin black wire (power for the display) does have to be connected or the display does not come on.

My input was a wall wart with a variable output that I had lying around. It has a 2.1mm connector. I have several other wall warts with fixed output, and an old Thinkpad power adapter with the same connector. Any of them will do. The weakest spot in the components I used was the 2.1mm socket from MCM Electronics, which doesn't make a very good connection and has to be jiggled sometimes to make it work. I'll replace this at some point.

Adapting the power module

The power module is designed to be used in a battery charger. If you follow the link, you'll see it has three adjustment potentiometers attached to the board, one for the voltage, one for the current limit, and one which sets the threshold at which charging is considered to be complete. We are only interested in the first two, and we want to replace them by free standing potentiometers. Unlike the instructables design, I used regular 270 degree linear ones, not 10 turn wirewound ones. The 10 turn ones are expensive and I don't think I need that level of control. You have to unsolder the adjustment pots from the board so you can solder on wires going to the free standing ones instead. Unsoldering the adjustment pots from the module turned out to be quite hard to do, and I ended up damaging one of the PCB tracks for the wiper of the current adjust. Fortunately, there is a small pad on the module PCB which it connects to, and I was able to solder a wire to it. For one of the pots, I soldered on a header, but after doing this I decided it didn't offer an real advantages electrically or mechanically, and so I soldered the wires directly to the board for the other one. I also removed the power and CC/CV LEDs and soldered on external ones instead. Note that if you remove the CC/CV LED, you must attach either an external LED or a resistor instead or you lose the ability to set a current limit. You can see why by examining the circuit diagram, which shows it is part of the feedback into the LM2596. The result looks like this:

I'll package it up into a box when I get one of a suitable size.

Controls

There are two controls, one for setting the voltage and one the current. The original instructables article is not very clear on how these controls work. Perhaps this will help. The module will provide output at the voltage you set, provided the load on it stays below the current limit that you set. If the load tries to draw more current than this, then the voltage will drop to keep the current at the threshold. When this is happening, the CC/CV light will come on.

For example, I connected a 10 ohm, 10 W resistor to the output and set the voltage to 5V with the current setting turned up to maximum. The meter shows a voltage of 5.02V and a current of 0.49A. Now I turned the current limit down. Eventually it reached the point where the current limit was below 0.49A. At this oint the CC/CV light comes on and the voltage drops. For example, with one setting I got 0.25 A and 2.61 V. Probably it's not exactly 2.5V due to the tolerance of the resistor. Note that I had not changed the voltage setting: it was just the current limit which was forcing the module to output a lower voltage.

The function of the other ("OK") LED is a little less clear: it is on when the current limit has not been reached and is off when it has been reached, but there is also a gap when neither is on.

I imagine in most cases when I am going to use this power supply, I'll just have the current setting on maximum, as I'm typically more interested in setting a voltage limit.

One last thing is to see how the output looks on a scope. Here it is:

Removing the DC and zooming in shows about 3mV oscillations for about 5V output:

When current limited the shape is slightly different:


Thursday, March 26, 2015

A small power supply, quick note

I am building a small power supply based on two designs at instructables (this and this). More about them in a later post. The designs are based on a LM2596 module such as this one. I was curious to know what the design of this module is. It looks like it comes from here. This site (mpja.com) looks nice, by the way: plenty of good stuff.

Saturday, March 14, 2015

Capacitance Meter and Transistor Tester

It's useful to have a way of measuring capacitors and doing quick checks on the pinout of transistors. In the case of capacitors, I find the labeling is often too small for me to read easily, or in the case of some SMD capacitors, not present at all. A nice, versatile design for such a device can be found here, in German. Now the last time I spoke any German was about the same time I started doing electronics, sometime in the 1970s. Fortunately English translations of the manual exist, at the SVN archive and in various other places. The most recent version I found was this one. You can find various sites around the web which describe it, including this slightly snippy evaluation of it.

There are many Chinese copies of the design. The one I got came as a kit from banggood. I ordered it from their US warehouse and it arrived within a week. There's a predrilled case available, but that was only available from China, so it will take longer to arrive. You can also get it already assembled from many places - just to a search on ebay. Assembling the kit was pretty straightforward. I have some tricks that help, like counting the pins on the IC socket as you solder them to avoid missing any out, and using a tiny piece of blu-tac to hold the sockets and power connector to the board while soldering them. The board looks well made and all the components were present, and the microcontroller that is at the heart of the design comes pre-programmed. There are two spacers for mounting the LCD on, and my one complaint is that it rests on top of a LED unless you get the LED really flat to the board or bend it slightly out of the way.

The manual describes and advanced menu and a calibration mode. They have to be selected at compile time, and I assume this wasn't done as neither function seems to work. According to the manual, a long press on the test button should put it into the advanced menu, and connecting the three test inputs together should get you calibration mode. Other than that, a few quick tests on known components all gave the right results.

I mentioned starting electronics in the 1970s (I stopped again around 1984 in favor of writing programs). My second ever project was a capacitance meter, from an article in either Electronics Today International or Everyday Electronics. It worked by generating a signal at a known frequency and then measuring the impedance of the capacitor. I never got it to work, due to a combination of my poor soldering technique and lack of knowledge about how to debug a circuit.


Wednesday, March 11, 2015

A quick tip

I'll post this here in case it helps anyone else. I bought a couple of Arduino Nanos from a Chinese site. They did not work when I first connected them to my Windows machine (Vista). At first I thought this was because they did not have a bootloader on them, and I would need to follow a process such as this one. However, this was not the problem. It was that the serial interface on the board was not recognised. The usual installation instructions such as this for installing a driver did not work: the driver was not present in the Arduino drivers directory. However, I found that the drivers from this site worked fine. I used the driver link not the driver installer link. And the Nanos did come with a bootloader.

Sunday, March 08, 2015

Kibble Cannon, Version 1

We play food games with our dog, such as hiding food in toys, or scattering it around the house. The idea is that if you put food in his bowl, it's gone in about 15 seconds. Playing food games makes it last longer, as well as providing entertainment for both him and us. But what if it could be automated? Then we could have the amusement without the effort, and we could also leave it set up for him while we are out. To this end, I propose the Kibble Cannon. It would fire pieces of kibble in random directions and at random times. In an ideal world it would make beeping noises and flash lights as well, though that's just for show.

As a first attempt at this, to see if this idea had any merit, I built little device consisting of a solenoid mounted on top of a servo. The solenoid is this one, driven much like this, with a TIP 120 and 2k2 resistor. I used a 12V supply. The servo is this one. There is a simple Arduino program to control it. It rotates the servo to a random angle, sends a short pulse to the solenoid and then waits for a little while:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Randomly set servo position, then fire, then delay.
#include 

#define FIREPIN 8
#define SERVOPIN 9
#define FLASHPIN 13
#define DELAYMIN 500
#define DELAYMAX 2000
#define FIRETIME 50

Servo servo;
 
void setup() {
  pinMode(FIREPIN, OUTPUT);
  pinMode(FLASHPIN, OUTPUT);
  randomSeed(analogRead(0)); // Read unnattached pin to get a random seed.
  servo.attach(SERVOPIN);
} 
 
void loop() {
  int pos = random(181);
  servo.write(pos);
  digitalWrite(FLASHPIN, HIGH);
  digitalWrite(FIREPIN, HIGH);
  delay(FIRETIME);
  digitalWrite(FIREPIN, LOW);
  delay(random(DELAYMIN, DELAYMAX));
  digitalWrite(FLASHPIN, LOW);
} 

You can see an example of it in action here. I am assisted in this video by my chief test engineer. The mechanical construction is a prototype: I used a couple of paperclips to hold the solenoid to the servo's disc, and slipped a piece of cardboard under the solenoid to make a platform for the piece of kibble. It will fire the kibble 2-3 feet.

Several things need to change. First, I think I need a solenoid with a longer travel or a higher acceleration, to fire the kibble further. A smoother launching platform, say a piece of rigid PVC tubing, would help. Next, I need a way of loading pieces of kibble onto the firing platform automatically. I will aim to address this in a future version.

Sunday, March 01, 2015

DACs, part 3

Here is another version of the DAC+Arduino signal generator. This version drops the idea of using interrupts, and instead sets the output values in a loop which invokes the builtin delay() and delayMicroseconds() functions. The delays are set from the period between samples of the waveform, minus a small amount to account for the time taken to execute the loop. We can make this time constant, or close to it, by precomputing all the output samples and storing them in an array.

The sine and triangle waves are quite clean, the square and sawtooth waves less so. I wonder if the MCP4921 doesn't like big voltage swings. Here are some sample outputs:


Square waves work to about 20kHz, the others to less, depending on how many samples you use.
And here is the code:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Delay-based version of the DAC driver.

#include "SPI.h"

// Waveform: define only one of the following.
#define SQUARE
//#define SAWTOOTH
//#define TRIANGLE
//#define SINE

// SS pin for the DAC.
#define DAC1SS 10

// Mask to select SS PIN on port b.
#define DAC1SSHI B100
#define DAC1SSLO B11111011

// Pin and mask for LDAC pin.
#define LDAC 9
#define LDACHI B10
#define LDACLO B11111101

// Range of values.
#define MIN_VALUE 0
#define MAX_VALUE 0xfff

// The desired frequency in Hz and the period in microseconds.
const unsigned long freq = 100UL;
const unsigned long period = 1000000 / freq;

// How many slices we divide the period into and the period of each.
#ifdef SQUARE
const unsigned int samples = 2;
#else
const unsigned int samples = 256;
#endif
const unsigned long sample_period = period / samples;

const double pi = 3.1415926;

// We will precompute all the sample values and store them here.
// This allows the main loop to run in a fixed time.
// Initialized in setup().
unsigned int* sample_values;

void SetValue(unsigned long value) {
  PORTB &= DAC1SSLO;
  if (value > MAX_VALUE) {
    value = MAX_VALUE;
  }
  byte data = (highByte(value) & 0x0f) | 0x30;
  SPI.transfer(data);
  data = lowByte(value);
  SPI.transfer(data);
  PORTB |= DAC1SSHI;
}

// Number of millisecond and microseconds between actions.
// Microseconds must be under 16384.
// Computed in setup.
unsigned int millis_delay;
unsigned int micros_delay;

void setup() {
  pinMode(DAC1SS, OUTPUT);
  pinMode(LDAC, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  
  sample_values = new unsigned int[samples];
#ifdef SQUARE
  sample_values[0] = MIN_VALUE;
  sample_values[1] = MAX_VALUE;
#endif
#ifdef SAWTOOTH
  float value = (float)MIN_VALUE;
  float sample_step = ((float)MAX_VALUE - MIN_VALUE)/(samples-1);
  for (int i = 0; i < samples; ++i) {
    sample_values[i] = (unsigned int)(value + 0.5);
    value += sample_step;
  }
#endif
#ifdef TRIANGLE
  unsigned int s2 = samples/2;
  float value = (float)MIN_VALUE;
  float sample_step = ((float)MAX_VALUE - MIN_VALUE)/s2;
  for (int i = 0; i < s2; ++i) {
    sample_values[i] = (unsigned int)(value + 0.5);
    value += sample_step;
  }
  for (int i = s2; i < samples; ++i) {
    sample_values[i] = (unsigned int)(value + 0.5);
    value -= sample_step;
  }
#endif
#ifdef SINE
  float value = (float)MIN_VALUE;
  double range = ((double)MAX_VALUE - MIN_VALUE)/2;
  for (int i = 0; i < samples; ++i) {
    double s = sin((2 * pi * i) / samples);
    // We have to raise the value from [-x,x] to [0,2x]
    sample_values[i] = (unsigned int)((s + 1) * range + MIN_VALUE + 0.5);
  }
#endif

  // Set delays with a little extra for the computation time.
  unsigned long slopped_period = sample_period - 15;
  millis_delay = slopped_period / 1000;
  micros_delay = slopped_period % 1000;
}

// Current sample index
unsigned int sample_number = 0;

void loop() {
  // Toggle LDAC to set the new value.
  PORTB &= LDACLO;
  unsigned long toggle_time = micros();
  PORTB |= LDACHI;

  sample_number = ++sample_number % samples;
  SetValue(sample_values[sample_number]);

  // Delay until the next action.
  delay(millis_delay);
  delayMicroseconds(micros_delay);
}