Saturday, January 17, 2015

Seven segment displays on an Arduino

Adafruit sells a four digit, seven segment LED display. Unlike many of their products, they don't give a lot of help in hooking it up. They suggest that you should connect it with the transistors or a shift register on the common cathodes to sink enough current. I think this is probably unnecessary. If you connect the anodes through 1k resistors you get pretty good brightness. The current per segment should be something like 5V minus 0.6V for the diode (it may be more than this - 0.6V is for silicon and they are probably GaAsP), so this gives a current of 4.4mA per segment, or 35mA if you have all the segments on, provided you only drive one digit at a time. The Arduino should be able to handle this OK. At least mine didn't blow up when I set it up like this.

There's a couple of difficulties in getting it connected, and so I'll go through what I did in case it is helpful to anyone else. I don't think this kind of display is very well suited to using on an Arduino, at least if it is connected directly. You need to use 12 or 13 I/O lines for it, and the code has to continually refresh the display so it can't do much else. You can reduce the number of lines by using a shift register or and I/O extender, though the refresh problem remains. The description that follows shows how direct interfacing can be done if you really want to try it.

The datasheet that Adafruit links to is a bit misleading. It makes it look as if the display has twelve pins, 1-6 on the lower edge and 12-7 on the top one. In fact it has 14 pins, 1-7 on the lower edge and 14-8 on the upper one, reading from left to right if you are looking down on the display. The model I got had part number KW4-56NCLB-P, so you have to use the second of the two diagrams on the datasheet for the pins. It's a common cathode version, meaning the pointy end of the LEDs which the current comes out of are joined together. There cathode for each digit are connected together, as are the ones for the colon separator in the middle of the display. Typically, you would use it by setting one of the common cathodes to low (0V) to select that digit, with all the others high. Then you would set the pins for the segments you want to turn on to high while keeping the others low. For example, to display a 1 on the leftmost digit, pin 14 would be low and pins 11, 7, 10 and 6 high for the digit, and pins 9 and 4 would be high, with 13, 2, 1, 12, 3, 5, and 8 high for the segments.

This example may make the second difficulty apparent: the ordering of the pins is not at all logical: the segments don't come out in a nice order such as pins 1-8, they are in the order I just mentioned 13,2, 1, 12 etc. I assume this makes manufacturing easier by avoiding crossing tracks within the package. When you are using a breadboard, a trick that can help with this is to take jumper wires from the pins to another area of the breadboard, where you can put them into a more logical order. I've done this with ICs that have a weird pin ordering as well. There are eight LEDs per digit (seven segments plus a decimal point), it makes sense to bring them out with four in each block.

The breadboard that I have is a fairly common one in which there are two block of contacts, with 5 in each column.  The columns are labelled 1 through 64. I placed the display so that pins 1 and 14 were on column 50. I'll call the blocks of the breadboard A and B, with the top of the display (pins 8-14) going into A. The table for the wiring them goes like this:
Pin on the display Function of the pin Column on the breadboard Connect a jumper to...
1 Segment E 50B 41B
2 Segment D 51B 38A
3 Decimal point 52B 38B
4 Segment C 53B 39A
5 Segment G 54B 39B
6 Digit 4 55B 23B
7


8


9 Segment B 55A 40A
10 Digit 3 54A 23A
11 Digit 2 53A 24A
12 Segment F 52A 40B
13 Segment A 51A 41A
14 Digit 1 50A 25A

I didn't connect pins 7 and 8, which are for the colon. Now we have the four digit cathodes on 25A, 24A, 23A and 22A, segments A to D on 41A, 40A, 39A and 38A, and segments E to G and the decimal point on 41B, 40B, 39B and 38B. This is a much more logical ordering and it helps to stop your brain from hurting.

As I said before, each anode (segment) will have a 1k resistor on it. We need this to limit the current through the segment. Some people suggest putting the resistors on the digit cathodes, as then you only need four of them, or five if you use the colon. However, if you do it this way, the brightness will vary according to what the display is showing, as with more segments on there will be more current through the resistor and hence a larger voltage drop across it. So now you can connect up 8 1k resistors, keeping the nice ordering of the segments we achieved earlier. The resistors can span across some of the jumper wires to keep things tidy. Here's the table for the resistors:
Segment 10k resistor from... to...
Segment A 41A 37A
Segment B 40A 36A
Segment C 39A 35A
Segment D 38A 34A
Segment E 41B 37B
Segment F 40B 36B
Segment G 39B 35B
Decimal point 38B 34B

Now all that remains is to connect it up to the Arduino. I connected digits 1-4 (25A-22A on the breadboard) to I/O pins 2-5, and segments A-G plus the decimal point (37A-34A and 37B-34B) to pins 6-12. It looks like this:

The connections to the Arduino are very tidy with all the mess in the jumpers on the breadboard.

There is a code snippet here. It picks a random number from 0 to 9999 and displays it. To do the display, there is a function called displayNumber, which selects each digit in turn by setting the right one of pins 2-5 to LOW, sets up the segments that are on by setting some of pins 6-12 to HIGH and delays briefly to reduce flickering. To keep the display refreshed, this all has to be done in a loop.

On my display, there was one dead segment (the D segment of the first digit), but otherwise this works quite nicely.


Saturday, January 10, 2015

Persistence

The Arduino Sensorium that I described in previous posts is limited by the amount of RAM on the Arduino. Recall that it stores readings from its sensors periodically in a circular buffer, discarding old entries when it runs out of space. The example version I described earlier used a DHT11 sensor, and the reading was stored as temperature, humidity and team, each as a 16 bit integers. This only gives you around 170 entries before you get close to the RAM limits of the Arduino Uno.

A simple way of adding memory is to use a FRAM chip. Adafruit has a 32k byte one accessed through the I2C interface, and an 8k byte SPI version as well. The 32k byte chip would allow around 5,000 sensor readings of three integers. In addition, it is non-volatile memory, meaning you can turn the power off and still retain the data.

The main issue with using this chip is that you can't address it in a simple way, that is through pointers. Instead, you have to read or write it byte by byte using functions in the library provided by Adafruit. I wrote a class which makes this a little easier. The interface is meant to give roughly the same functionality as a native C fixed size array. The specific methods are different, and in particular, I decided not to overload the [] operator. Instead, there are Get and Set methods which take pointers to bytes to specify the location of the objects to be read or written, with templated GetItem and SetItem methods to allow writing of other data types. The code is here. It's written as a base class (StoredArray), and two subclasses. One of them (FRAMArray) stores the data in FRAM. The other (MemoryArray) stores the data in ordinary RAM, allowing you to easily switch code between the two kinds of storage.

I have a new version of the Sensorium code which illustrates this here. You select between FRAM or normal RAM with a #define. When you select the FRAM version it will use the existing data in FRAM, so that you can power down the Arduino, then restart it and add more sensor reading later (though the timestamps will not make sense if you do so). To clear the data, press down the button on input 3 within 3 seconds of resetting the Arduino. This is the same button used in the earlier version for initiating upload.

A quick note on the hardware configuration for this and for the original Sensorium.
  • Arduino pin 3 connects to a push button switch. This side of the switch has a 10k resistor to ground, the other side goes to 5V.
  • Arduino pin 4 goes to pin 2 of a DHT11 temperature/humidity sensor. This pin has a 10k resistor to 5V. Pin 1 (leftmost with the "grid" side facing you) goes to 5V, pin 4 to ground.
  • The new hardware for this version of a FRAM breakout board described above. It has 5V and ground connections as shown on the board (pins 1 and 2). SCL (pin 4 of the board) goes to the Arduino's A5 pin, and SDA (pin 5 of the board) goes to Arduino A4.
Next, to try some different sensors.

Sunday, January 04, 2015

All ears and thumbs

The circuit design for the Arduino sensorium from a couple of days ago is trivial, so that just leaves the physical construction. There aren't many external parts - a couple of resistors, a button, a battery clip and the sensor itself - but I wanted something physically quite stable. I didn't have a convenient plastic box for putting it in, so in the short term I decided to improvise. My first thought for the components was to put everything except the sensor on a tiny piece of stripboard (or Veroboard, as I can't help calling it). The sensor could then be connected on a longer cable to make it more convenient to place.

I did initially put it together this way, and then decided on something better. When I placed my initial order with Adafruit, they sent me a free "perma-proto" board (https://www.adafruit.com/products/1609). This is nice in a couple of ways. First, it's about the same size as the Arduino Uno board, something I'll come back to in a moment. Secondly, it has very fine tracks and plated through holes, which makes soldering to it easier than stripboard. If there is a piece of advice that I would offer my teenage self just getting started in electronics, it is this: relish your youth. When you get to the your 50s, it's going to be very hard to focus on small things, and soldering will involve much guesswork. Thank you, my teenage self will say, now can you tell me how to get more sex?

Because the perma-proto board is about the same size as the Arduino Uno board, you can easily strap them together. I did this with a piece of cardboard between them for insulation, holding the whole thing together with a large rubber band I find in my desk drawer. I had a couple of spare headers which I soldered to the perma-proto board and then connected the 5V, Ground and input pins from the Uno board with ordinary jumper cables. The battery clip goes to the Vin termainal on the board, again connected through a spare bit of header. The result, while not pretty, is just about robust enough to be carried round in a pocket. It'll do until I've ordered a more rigid box instead. Here's a couple of pictures.



Friday, January 02, 2015

A Sensorium

My first Arduino project is a "sensorium", for recording data from sensors, storing it and then later uploading it. The idea is that this is something you could carry around. It takes a reading such as temperature or UV periodically and save the readings in RAM. Pressing a button initiates a transfer over the serial line. The hardware is trivial: you can connect up a switch with just a pullup resistor, as in http://arduino.cc/en/Tutorial/Button, and connector a sensor such as the DHT11 temperature/humidity sensor as in https://learn.adafruit.com/dht/overview. During development I also found it helpful to hook up a LCD display. You can do debugging over the serial line, but if you are using the serial line for something else, another way of displaying what is going on is convenient. I used one of these: https://www.adafruit.com/products/181.

I've put the code online at http://www.friendlymoose.com/software.html. A line-by-line analysis would probably be boring, so here's a quick overview of the main elements. There is a template class, CircularBuffer, used to store the data and send it over the serial line. It keeps the data in a fixed size array. The parameter of the template indicates what kind of data to store. The buffer is circular, in the sense that once all the space has been used up, the oldest item will be overwritten. The serial protocol is quite simple. It sends one data item at a time, preceding by its size in bytes (one byte, and so a maximum of 255) and a one byte checksum. It then expects to get a one byte response code and the same checksum back. If it doesn't get an OK response, or if the checksum doesn't match up, or if it gets no response within a given time, it will try to resend the data a few times, and eventually give up. If the data does get through, it is removed from the buffer. I decided on sending only one data item at a time after some experiments with sending larger amounts of data. It turned out to be hard to get the timeout for the response right in a reliable way. There's a utility function to send several data items one by one.

There is a class DHTSensor for representing the data from the sensor. It also has methods for deciding if it is time to read the sensor and for reading it and storing the data in the circular buffer. In an ideal world, I would have written a base class here and subclassed it for the DHT11 sensor. Deciding on when to read the sensor is done by just looking at the millisecond timer and comparing it to when the last reading was taken. I have it set up for one reading per minute.

If I'm carrying this thing around, I want to run it from batteries, and that means saving power if possible. There is a base class PowerSaver with three variants, selected by a #define. One does nothing. One puts the Arduino into idle mode. It wakes up every millisecond. This is the one that I currently use. The final variant shuts down down the Arduino for 8 seconds at a time using a watchdog timer. The ideas here are based on http://www.gammon.com.au/power. The third version would give the best power saving, but it makes it hard to decided when the read the sensor, as the millisecond timer gets shut down as well. I'm not sure how well the power saving works in practice. Sometime I'll measure how long it takes to drain a fresh battery.

The button for initiating serial transfer fires an interrupt handler, which saves a boolean to be read by the main loop. Finally, the loop() function itself checks whether the button handler set the boolean and sends the data over the serial line if so. It also decides if it is time to read the sensor. At the end of the function, it puts the processor back into its low power state. The serial port is reopened each time the data is sent. This seems to work better when the serial line can be physically disconnected and reconnected.

The receiving end of the code, ardser, is written in Python and is also at http://www.friendlymoose.com/software.html. This is a Windows version, though only the port should need to be changed to work on Linux. It requires the pySerial library. I've had some difficulty making the connection work. The best sequence seems to be connect the USB cable, start ardser, then press the send button on the Arduino. The code outputs the triples of temperature (Fahrenheit), humidity (%) and time (seconds) sent from the Arduino. Here's an example, from my evening walk with the dog, with readings inside the house at the beginning and the very end.
 (6800, 4100, 60)
 (6800, 4100, 120)
 (7160, 4100, 180)
 (6440, 4100, 240)
 (5900, 4200, 300)
 (5720, 4400, 360)
 (5720, 4500, 420)
 (5720, 4500, 480)
 (5720, 4600, 540)
 (5720, 4700, 600)
 (5720, 4700, 660)
 (5720, 4700, 720)
 (6080, 4900, 780)
I doubt that this is very accurate. The temperature in my house is probably around 68F, and wunderground was reporting an outside temperature of around 57F, so this looks OK. I don't know what the humidity in the house is, and wunderground gives 60% outside, so it looks like the sensor is off, or there is a bug in the code that reads it.

More on the physical construction later.

Jan 10 2015: Updated Sensorium.ino with a couple of minor bug fixes.

Thursday, January 01, 2015

An ard coming we ad and an arder going

In mid-December, I was talking with a friend about getting a Pi and an Arduino. She had been thinking about doing the same (a Pi at least), and found herself asking what she would do with it. I had had the same thought, and it occurred to me to think less about the end result and more about the process. It's fun to knock bits of circuitry together and to program at a bit-twiddly level, or for that matter to write programs from the hip without the considerations of reliability and scalability that I have to bring to my professional work.

Having said that, I pretty quickly came up with a list of ten or so things I'd like to do, from my own ideas or inspired by things I read on the web, for either the Pi or the Arduino:
  • Play with RISCOS. See if !Draw is as good as I remember it to be.
  • Garage door opener. More exactly, something which will close the door after some length of time, in case I go away and forget. Ideally with remote monitoring.
  • Remove monitoring for door locks. The house alarm will go off if they are open, but it can't detect if they are locked.
  • Household web/media/backup server.
  • Temperature monitor, air quality monitor. More generally, a sensor board that I could carry around with me and upload data later on.
  • Household power consumption tracking.
  • Simple remote communication using off the shelf LEDs based on Dietz's ideas (http://www.forth-ev.de/filemgmt_data/files/TR2003-35.pdf).
  • Remote lighting control, so I don't have to get up from my desk to turn on the light.
  • Scanner replacement by hooking up a camera over USB. Recognize when a page has been placed under it, and take and correct an image automatically.
  • Remote or timed dog feeder.
  • Oscilloscope. Low frequency, but maybe better than the one I built using an Android phone.
The first thing I am working on is the sensor platform. More on this soon.