Posts | Comments

Planet Arduino

Archive for the ‘IC’ Category

Introduction

This is the second of three articles that will examine the LM391x series of LED driver ICs. The first covered the LM3914, this will cover the LM3915 and the LM3916 will follow. The goal of these is to have you using the parts in a small amount of time and experiment with your driver ICs, from which point you can research further into their theory and application.

Although these parts have been around for many years, the LM3915 isn’t used that much however for the sake of completeness we’re writing the tutorial. The LM3915 offers a simple way to display a logarithmic voltage level using one or more groups of ten LEDs with a minimum of fuss. If you’re wanting to make a VU meter, you should use the LM3916 which we will cover in the final instalment of this trilogy.

Instead of having each LED represent a voltage level as with the LM3914, each LED connected to the LM3915 represents a 3 dB (decibel) change in the power level of the signal. For more on decibels, check out Wikipedia.

To display these power level changes we’ll run through a couple of examples that you can use in your own projects and hopefully give you some ideas for the future. Originally by National Semiconductor, the LM391X series is now handled by Texas Instruments.

LM3915

Getting Started

You will need the LM3915 data sheet, so please download that and keep it as a reference. First – back to basics. The LM3915 controls ten LEDs. It controls the current through the LEDs with the use of only one resistor, and the LEDs can appear in a bar graph or single ‘dot’ when in use. The LM3915 contains a ten-stage voltage divider, each stage when reached will illuminate the matching LED (and those below it in level meter mode).

Let’s consider the most basic of examples (from page two of the data sheet) – a simple logarithmic display of voltage between 0 and 10V:

LM3915 demo board circuitAfter building the circuit you can connect a signal to measure via pin 5, and the GND to pin 2. We’ve built the circuit exactly as above on some stripboard for demonstration purposes, with the only difference being the use of an 8.2kΩ resistor for R2:

LM3915 demo board

To show this in action we use a signal of varying AC voltage – a sine wave at around 2 kHz. In the following video, you can see the comparison of the signal’s voltage against the LEDs being illuminated, and you will see the logarithmic voltage increase represented by the LEDs:

We used the bar display mode for the voltage increase, and the dot display mode for the voltage decrease. Did you notice that during the voltage decrease, the LEDs below the maximum level being displayed were dim? As the signal’s voltage was varying very quickly, the change in the LED’s location is a blur due to the speed of change. In the video below, we’ve slowed the frequency right down but kept the same maximum voltage.

Well that was a lot of fun, and gives you an idea of what is possible with the LM3915.

Displaying weaker signals

In non-theoretical situations your input signal won’t conveniently be between 0 and 10 V. For example the line level on audio equipment can vary between 1 and 3V peak to peak. For example, here’s a random DSO image from measuring the headphone output on my computer whilst playing some typical music:

audio signal LM3915 PC sound

Although it’s an AC signal we’ll treat it as DC for simplicity. So to display this random low DC voltage signal we’ll reduce the range of the display to 0~3V DC. This is done using  the same method as with the LM3914 – with maths and different resistors.

Consider the following formulae:

LM3915 reference voltage formula

As you can see the LED current (Iled) is simple, however we’ll need to solve for R1 and R2 with the first formula to get our required Vref of 3V. For our example circuit I use 2.2kΩ for R2 which gives a value of 1.8kΩ for R1. However putting those values in the ILED formula gives a pretty low current for the LEDs, about 8.3 mA. Live and learn – so spend time experimenting with values so you can match the required Vref and ILED.

Nevertheless in this video below we have the Vref of 3V and some music in from the computer as a sample source of low-voltage DC. This is not a VU meter! Wait for the LM3916 article to do that.

Again due to the rapid rate of change of the voltage, there is the blue between the maximum level at the time and 0V.

Chaining multiple LM3915s

This is covered well in the data sheet, so read it for more on using two LM3915s. Plus there are some great example circuits in the data sheet, for example the 100W audio power meter on page 26 and the vibration meter (using a piezo) on page 18.

Conclusion

As always I hope you found this useful. Don’t forget to stay tuned for the final instalment about the LM3916. And if you made it this far – check out my new book “Arduino Workshop” from No Starch Press.

In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.

Sep
13

Tutorial – LM3914 Dot/Bar Display Driver IC

bar, display, dot, driver, Electronics, example, IC, LED, level, LM3914, LM3915, LM3916, TI, tronixstuff, tutorial, voltmeter Comments Off on Tutorial – LM3914 Dot/Bar Display Driver IC 

Introduction

This is the first of three tutorials that will examine the LM391x series of LED driver ICs. In this first tutorial we cover the LM3914, then the LM3915 and LM3916 will follow. The goal of these tutorials is to have you using the parts in a small amount of time and experiment with your driver ICs, from which point you can research further into their theory and application.

Although these parts have been around for many years, the LM3914 in particular is still quite popular. It offers a simple way to display a linear voltage level using one or more groups of ten LEDs with a minimum of fuss.

With a variety of external parts or circuitry these LEDs can then represent all sorts of data, or just blink for your amusement. We’ll run through a few example circuits that you can use in your own projects and hopefully give you some ideas for the future. Originally by National Semiconductor, the LM391X series is now handled by Texas Instruments.

LM3914

Getting Started

You will need the LM3914 data sheet, so please download that and keep it as a reference. So – back to basics. The LM3914 controls ten LEDs. It controls the current through the LEDs with the use of only one resistor, and the LEDs can appear in a bar graph or single ‘dot’ when in use. The LM3914 contains a ten-stage voltage divider, each stage when reached will illuminate the matching LED (and those below it in level meter mode).

Let’s consider the most basic of examples (from page two of the data sheet) – a voltmeter with a range of 0~5V:

 LM3914 5V voltmeter circuit

The Vled rail is also connected to the supply voltage in our example. Pin 9 controls the bar/dot display mode – with it connected to pin 3 the LEDs will operate in bar graph mode, leave it open for dot mode. The 2.2uF capacitor is required only when “leads to the LED supply are 6″ or longer”. We’ve hooked up the circuit above, and created a 0~5V DC source via a 10kΩ potentiometer with a multimeter to show the voltage – in the following video you can see the results of this circuit in action, in both dot and bar graph mode:

Customising the upper range and LED current

Well that was exciting, however what if you want a different reference voltage? That is you want your display to have a range of 0~3 V DC? And how do you control the current flow through each LED? With maths and resistors. Consider the following formulae:

LM3914 formulae

As you can see the LED current (Iled) is simple, our example is 12.5/1210 which returned 10.3 mA – and in real life 12.7 mA (resistor tolerance is going to affect the value of the calculations).

Now to calculate a new Ref Out voltage – for example  we’ll shoot for a 3 V meter, and keep the same current for the LEDs. This requires solving for R2 in the equation above, which results with R2 = -R1 + 0.8R1V. Substituting the values – R2 = -1210 + 0.8 x 1210 x 3 gives a value of 1694Ω for R2. Not everyone will have the E48 resistor range, so try and get something as close as possible. We found a 1.8 kΩ for R2 and show the results in the following video:

You can of course have larger display range values, but a supply voltage of no more than 25 V will need to be equal to or greater than that value. E.g. if you want a 0~10 V display, the supply voltage must be >= 10V DC.

Creating custom ranges

Now we’ll look at how to create  a lower range limit, so you can have displays that (for example) can range from a non-zero positive value. For example, you want to display levels between 3 and 5V DC. From the previous section, you know how to set the upper limit, and setting the lower limit is simple – just apply the lower voltage to pin 4 (Rlo).

You can derive this using a resistor divider or other form of supply with a common GND. When creating such circuits, remember that the tolerance of the resistors used in the voltage dividers will have an affect on the accuracy. Some may wish to fit trimpots, which after alignment can be set permanently with a blob of glue.

Finally, for more reading on this topic – download and review the TI application note.

Chaining multiple LM3914s

Two or more LM3914s can be chained together to increase the number of LEDs used to display the levels over an expanded range. The circuitry is similar to using two independent units, except the REFout (pin 7) from the first LM3914 is fed to the REFlo (pin 4) of the second LM3914 – whose REFout is set as required for the upper range limit. Consider the following example schematic which gave a real-world range of 0~3.8V DC:

LM3914

The 20~22kΩ resistor is required if you’re using dot mode (see “Dot mode carry” in page ten of the data sheet). Moving on, the circuit above results with the following:

Where to from here?

Now you can visually represent all sorts of low voltages for many purposes. There’s more example circuits and notes in the LM3914 data sheet, so have a read through and delve deeper into the operation of the LM3914. Furthermore Dave Jones from eevblog.com has made a great video whcih describes a practical application of the LM3914:

Conclusion

As always I hope you found this useful. Don’t forget to stay tuned for the second and third instalments using the LM3915 and LM3916. Full-sized images are on flickr. And if you made it this far – check out my new book “Arduino Workshop” from No Starch Press.

In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.

The post Tutorial – LM3914 Dot/Bar Display Driver IC appeared first on tronixstuff.

Aug
13

Tutorial – Arduino and PCF8563 real time clock IC

arduino, clock, i2c, IC, NXP, PCF8563, real, Real-time clock, RTC, time, tronixstuff, tutorial Comments Off on Tutorial – Arduino and PCF8563 real time clock IC 

Use the NXP PCF8563 real-time clock IC with Arduino in chapter fifty-four of our Arduino Tutorials. The first chapter is here, the complete series is detailed here.

Updated 20/08/2013

Introduction

Recently a few people have been asking about the PCF8563 real-time clock IC from NXP – so this is a tutorial on how to use it for time, date, alarm clock and square-wave generation purposes.

The PCF8563 is another inexpensive RTC that can be used with an Arduino or other platforms due to the wide operating voltage (1 to 5.5V DC), I2C interface, and very low power consumption (when powered by a backup battery it only draws 0.25 μA). If you aren’t up to speed on the I2C interface, please review the I2C tutorials before moving forward. And please download the data sheet (.pdf).

The PCF8563 is available in various chip packages, for the curious we’re using the TSSOP8 version mounted on a breakout board:

PCF8563_SMD

Don’t panic – you can also get it in a breadboard-friendly DIP (through-hole) package as well, and also on a pre-built module from the usual suspects.

Demonstration Circuit

If you have a pre-made module, you can skip to the next section. However if you’re making up the circuit yourself, you will need:

  • One 32.768 kHz crystal
  • Two 1N4148 diodes*
  • One 3V coin cell (with holder)*
  • Two 10kΩ resistors
  • One 0.1 uF capacitor

And here’s the schematic:

PCF8563

* You can skip the diodes and battery if you don’t want a backup power supply when the main power is turned off or removed. Pin 3 is for the interrupt output (we’ll consider that later) and pin 7 is for the square-wave oscillator output.

Communicating with the PCF8563

Now to get down into the land of I2C once more. When looking through the data sheet NXP mentions two bus addresses, which have the same 7-bits finished with either a 1 for read or 0 for write. However you can just bitshift it over one bit as we don’t need the R/W bit – which gives you a bus address of 0×51.

Next you need to know which registers store the time and date – check the register map (table 4) on page 7 of the data sheet:

PCF8563 time date registers

 There will be a few other registers of interest, but we’ll return to those later. For now, note that the time and date start from 0×02. And one more thing – data is stored in the BCD (binary-coded- decimal) format. But don’t panic, we have a couple of functions to convert numbers between BCD and decimal.

Writing the time and date is a simple matter of collating the seconds, minutes, hours, day of week, day of month, month and year into bytes, converting to BCD then sending them to the PCF8563 with seven Wire.write() functions. Reading the data is also easy, just set the pointer to 0×02 and request seven bytes of data – then run them through a BCD to decimal conversion. With a catch.

And that catch is the need to sort out unwanted bits. Revisit table 4 in the data sheet – if you see an x that’s an unused bit. If any of them are a 1 they will mess up the BCD-decimal conversion when reading the register, so they need to be eliminated just like a whack-a-mole. To do this, we perform an & (bitwise AND) operation on the returned byte and mask out the unwanted bits with a zero. How does that work?

Example – the byte for dayOfMonth is returned – we only need bits 5 to 0. So 6 and 7 are superfluous. If you use (dayOfMonth & B00111111) the & function will set bits 6 and 7 to zero, and leave the other bits as they were.

Now to put all that together in a demonstration sketch. It puts everything mentioned to work and simply sets the time to the PCF8563, and then returns it to the serial monitor. The data is kept in global variables declared at the start of the sketch, and the conversions between BCD and decimal are done “on the fly” in the functions used to send or retrieve data from the PCF8563. Read through the following sketch and see how it works for yourself:

// Example 54.1 - PCF8563 RTC write/read demonstration

#include "Wire.h"
#define PCF8563address 0x51

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
String days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

byte bcdToDec(byte value)
{
  return ((value / 16) * 10 + value % 16);
}

byte decToBcd(byte value){
  return (value / 10 * 16 + value % 10);
}

void setPCF8563()
// this sets the time and date to the PCF8563
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.write(decToBcd(second));  
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));     
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(dayOfWeek));  
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void readPCF8563()
// this gets the time and date from the PCF8563
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(PCF8563address, 7);
  second     = bcdToDec(Wire.read() & B01111111); // remove VL error bit
  minute     = bcdToDec(Wire.read() & B01111111); // remove unwanted bits from MSB
  hour       = bcdToDec(Wire.read() & B00111111); 
  dayOfMonth = bcdToDec(Wire.read() & B00111111);
  dayOfWeek  = bcdToDec(Wire.read() & B00000111);  
  month      = bcdToDec(Wire.read() & B00011111);  // remove century bit, 1999 is over
  year       = bcdToDec(Wire.read());
}

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // change the following to set your initial time
  second = 0;
  minute = 28;
  hour = 9;
  dayOfWeek = 2;
  dayOfMonth = 13;
  month = 8;
  year = 13;
  // comment out the next line and upload again to set and keep the time from resetting every reset
  setPCF8563();
}

void loop()
{
  readPCF8563();
  Serial.print(days[dayOfWeek]); 
  Serial.print(" ");  
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/20");
  Serial.print(year, DEC);
  Serial.print(" - ");
  Serial.print(hour, DEC);
  Serial.print(":");
  if (minute < 10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");  
  if (second < 10)
  {
    Serial.print("0");
  }  
  Serial.println(second, DEC);  
  delay(1000);
}

And a quick video of this in operation:

If all you need to do is write and read the time with the PCF8563, you’re ready to go. However there’s a few more features of this unassuming little part which you might find useful, so at least keep reading…

Square-wave output

As with any clock or RTC IC, an oscillator is involved, and as mentioned earlier you can take this from pin 7 of the PCF8563. However – it’s an open-drain output – which means current flows from the supply voltage into pin 7. For example if you want to blink an LED, connect a 560Ω resistor between 5V and the anode of the LED, then connect the cathode to pin 7 of the PCF8563.

The frequency is controlled from the register at 0x0D. Simply write one of the following values for the respective frequencies:

  • 10000000 for 32.768 kHz;
  • 10000001 for 1.024 kHz;
  • 10000010 for 32 kHz;
  • 10000011 for 1 Hz;
  • 0 turns the output off and sets it to high impedance.

The following is a quick demonstration sketch which runs through the options:

// Example 54.2 - PCF8563 square-wave generator (signal from pin 7)

#include "Wire.h"
#define PCF8563address 0x51

void PCF8563oscOFF()
// turns off oscillator
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x0D);
  Wire.write(0);
  Wire.endTransmission();
}

void PCF8563osc1Hz()
// sets oscillator to 1 Hz
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x0D);
  Wire.write(B10000011);
  Wire.endTransmission();
}

void PCF8563osc32Hz()
// sets oscillator to 32 kHz
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x0D);
  Wire.write(B10000010);
  Wire.endTransmission();
}

void PCF8563osc1024kHz()
// sets oscillator to 1.024 kHz
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x0D);
  Wire.write(B10000001);
  Wire.endTransmission();
}

void PCF8563osc32768kHz()
// sets oscillator to 32.768 kHz
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x0D);
  Wire.write(B10000000);
  Wire.endTransmission();
}

void setup()
{
  Wire.begin();
}

void loop()
{
  PCF8563osc1Hz();
  delay(2000);
  PCF8563osc32Hz();
  delay(2000);
  PCF8563osc1024kHz();
  delay(2000);
  PCF8563osc32768kHz();
  delay(2000);
  PCF8563oscOFF();
  delay(2000);
}

And the resulting waveforms from slowest to highest frequency. Note the sample was measured from a point between the LED and resistor, so the oscillations don’t vary between the supply voltage and zero:

PCF8563_1Hz

PCF8563_32Hz

PCF8563_1024Hz

PCF8563_32768Hz

Self-awareness of clock accuracy

The PCF8563 monitors the oscillator and supply voltage, and if the oscillator stops or the voltage drops below a certain point – the first bit of the seconds register (called the VL bit) is set to 1. Thus your sketch can tell you if there’s a chance of the time not being accurate by reading this bit. The default value is 1 on power-up, so you need to set it back to zero after setting the time in your sketch – which is done when you write seconds using the code in our example sketches. Then from that point it can be monitored by reading the seconds register, isolating the bit and returning the value.

Examine the function checkVLerror() in the following example sketch. It reads the seconds byte, isolates the VL bit, then turns on D13 (the onboard LED) if there’s a problem. The only way to restore the error bit to “OK” is to re-set the time:

// Example 54.3 - PCF8563 RTC write/read demonstration with error-checking

#include "Wire.h"
#define PCF8563address 0x51

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
String days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

byte bcdToDec(byte value)
{
  return ((value / 16) * 10 + value % 16);
}

byte decToBcd(byte value){
  return (value / 10 * 16 + value % 10);
}

void setPCF8563()
// this sets the time and date to the PCF8563
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.write(decToBcd(second));  
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));     
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(dayOfWeek));  
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void readPCF8563()
// this gets the time and date from the PCF8563
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(PCF8563address, 7);
  second     = bcdToDec(Wire.read() & B01111111); // remove VL error bit
  minute     = bcdToDec(Wire.read() & B01111111); // remove unwanted bits from MSB
  hour       = bcdToDec(Wire.read() & B00111111); 
  dayOfMonth = bcdToDec(Wire.read() & B00111111);
  dayOfWeek  = bcdToDec(Wire.read() & B00000111);  
  month      = bcdToDec(Wire.read() & B00011111);  // remove century bit, 1999 is over
  year       = bcdToDec(Wire.read());
}

void checkVLerror()
// this checks the VL bit in the seconds register
// and turns on D13 if there's a possible accuracy error
{
  byte test;
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(PCF8563address, 1);
  test = Wire.read(); 
  test = test & B10000000;
  if (test == B10000000)
  {
    // error
    digitalWrite(13, HIGH);
    Serial.println("Uh-oh - possible accuracy error");
  } else 
  if (test != B10000000)
  {
    digitalWrite(13, LOW);
  }
}

void setup()
{
  Wire.begin();
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  Serial.begin(9600);
  // change the following to set your inital time
  second = 0;
  minute = 42;
  hour = 11;
  dayOfWeek = 2;
  dayOfMonth = 13;
  month = 8;
  year = 13;
  // comment out the next line and upload again to set and keep the time from resetting every reset
  // setPCF8563();
}

void loop()
{
  readPCF8563();
  Serial.print(days[dayOfWeek]); 
  Serial.print(" ");  
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/20");
  Serial.print(year, DEC);
  Serial.print(" - ");
  Serial.print(hour, DEC);
  Serial.print(":");
  if (minute < 10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");  
  if (second < 10)
  {
    Serial.print("0");
  }  
  Serial.println(second, DEC);  
  checkVLerror();
  delay(1000);
}

And now for a demonstration of the error-checking at work. We have the PCF8563 happily returning the data to the serial monitor. Then the power is removed and restored. You see D13 on the Arduino-compatible board turn on and then the error is displayed in the serial monitor:

This function may sound frivolous, however if you’re building a real product or serious project using the PCF8563, you can use this feature to add a level of professionalism and instil confidence in the end user.

Alarm Clock

You can use the PCF8563 as an alarm clock, that is be notified of a certain time, day and/or day of the week – at which point an action can take place. For example, trigger an interrupt or turn on a digital output pin for an external siren. Etcetera. Using the alarm in the sketch is quite similar to reading and writing the time, the data is stored in certain registers – as shown in the following table from page seven of the data sheet:

PCF8563 alarm registers

However there is a catch – the MSB (most significant bit, 7) in the registers above is used to determine whether that particular register plays a part in the alarm. For example, if you want your alarm to include hours and minutes, bit 7 needs to be set to 1 for the hour and minute alarm register. Don’t panic – you can easily set that bit by using a bitwise OR (“|”) and B10000000 to set the bit on with the matching data before writing it to the register.

Checking if the alarm has occurred can be done with two methods – software and hardware. Using software you check bit 3 of the register at 0×01 (the “AF” alarm flag bit). If it’s 1 – it’s alarm time! Then you can turn the alarm off by setting that bit to zero. Using hardware, first set bit 1 of register 0×01 to 1 – then whenever an alarm occurs, current can flow into pin 3 of the PCF8563. Yes - it’s an open-drain output – which means current flows from the supply voltage into pin 3. For example if you want to turn on an LED, connect a 560Ω resistor between 5V and the anode of the LED, then connect the cathode to pin 3 of the PCF8563. To turn off this current, you need to turn off the alarm flag bit as mentioned earlier.

Now let’s put all that into a demonstration sketch. It’s documented and if you’ve been following along it shouldn’t be difficult at all:

// Example 54.4 - PCF8563 alarm clock demonstration

#include "Wire.h"
#define PCF8563address 0x51

byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte alarmMinute, alarmHour, alarmDay, alarmDayOfWeek;
String days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

byte bcdToDec(byte value)
{
  return ((value / 16) * 10 + value % 16);
}

byte decToBcd(byte value){
  return (value / 10 * 16 + value % 10);
}

void setPCF8563alarm()
// this sets the alarm data to the PCF8563
{
  byte am, ah, ad, adow;
  am = decToBcd(alarmMinute);
  am = am | 100000000; // set minute enable bit to on
  ah = decToBcd(alarmHour);
  ah = ah | 100000000; // set hour enable bit to on
  ad = decToBcd(alarmDay);
  ad = ad | 100000000; // set day of week alarm enable bit on
  adow = decToBcd(alarmDayOfWeek);
  adow = ad | 100000000; // set day of week alarm enable bit on

  // write alarm data to PCF8563
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x09);
  Wire.write(am);  
  Wire.write(ah);

  // optional day of month and day of week (0~6 Sunday - Saturday)
  /*
  Wire.write(ad);
  Wire.write(adow);  
  */
  Wire.endTransmission();

  // optional - turns on INT_ pin when alarm activated  
  // will turn off once you run void PCF8563alarmOff()
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x01);
  Wire.write(B00000010);
  Wire.endTransmission();
}

void PCF8563alarmOff()
// turns off alarm enable bits and wipes alarm registers. 
{
  byte test;
  // first retrieve the value of control register 2
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x01);
  Wire.endTransmission();
  Wire.requestFrom(PCF8563address, 1);
  test = Wire.read();

  // set bit 3 "alarm flag" to 0
  test = test - B00001000;

  // now write new control register 2  
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x01);
  Wire.write(test);
  Wire.endTransmission();
}

void checkPCF8563alarm()
// checks if the alarm has been activated
{
  byte test;
  // get the contents from control register #2 and place in byte test;
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x01);
  Wire.endTransmission();
  Wire.requestFrom(PCF8563address, 1);
  test = Wire.read();
  test = test & B00001000; // isolate the alarm flag bit
  if (test == B00001000) // alarm on?
  {
    // alarm! Do something to tell the user
    Serial.println("** alarm **");
    delay(2000);

    // turn off the alarm
    PCF8563alarmOff();
  }
}

void setPCF8563()
// this sets the time and date to the PCF8563
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.write(decToBcd(second));  
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));     
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(dayOfWeek));  
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void readPCF8563()
// this gets the time and date from the PCF8563
{
  Wire.beginTransmission(PCF8563address);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(PCF8563address, 7);
  second     = bcdToDec(Wire.read() & B01111111); // remove VL error bit
  minute     = bcdToDec(Wire.read() & B01111111); // remove unwanted bits from MSB
  hour       = bcdToDec(Wire.read() & B00111111); 
  dayOfMonth = bcdToDec(Wire.read() & B00111111);
  dayOfWeek  = bcdToDec(Wire.read() & B00000111);  
  month      = bcdToDec(Wire.read() & B00011111);  // remove century bit, 1999 is over
  year       = bcdToDec(Wire.read());
}

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // change the following to set your initial time
  second = 50;
  minute = 44;
  hour = 13;
  dayOfWeek = 1;
  dayOfMonth = 19;
  month = 8;
  year = 13;
  // comment out the next line and upload again to set and keep the time from resetting every reset
  setPCF8563();

  alarmMinute = 45;
  alarmHour = 13;
  // comment out the next line and upload again to set and keep the alarm from resetting every reset  
  setPCF8563alarm();
}

void loop()
{
  readPCF8563();
  Serial.print(days[dayOfWeek]); 
  Serial.print(" ");  
  Serial.print(dayOfMonth, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/20");
  Serial.print(year, DEC);
  Serial.print(" - ");
  Serial.print(hour, DEC);
  Serial.print(":");
  if (minute < 10)
  {
    Serial.print("0");
  }
  Serial.print(minute, DEC);
  Serial.print(":");  
  if (second < 10)
  {
    Serial.print("0");
  }  
  Serial.println(second, DEC);  
  delay(1000);

  // alarm?
  checkPCF8563alarm();
}

This is the same as the example 54.1, however we’ve added the required functions to use the alarm. The required alarm data is stored in the global bytes:

byte alarmMinute, alarmHour, alarmDay, alarmDayOfWeek;

and is written to the PCF8563 using the function:

void setPCF8563alarm()

Note the use of bitwise OR (“|”) to add the enable bit 7 to the data before writing to the register. The interrupt pin is also set to activate at the end of this function, however you can remove that part of the code if unnecessary. We also demonstrate checking the alarm status via software using the function:

void checkPCF8563alarm()

which simply reads the AF bit in the register at 0×01 and let’s us know if the alarm has occurred via the Serial Monitor. In this function you can add code to take action for your required needs. It also calls the function:

void PCF8563alarmOff()

which retrieves the contents of the register at 0×01, sets the AF bit to zero and writes it back. We do this to preserve the status of the other bits in that register. For the curious and non-believers you can see this sketch in action through the following video, first the software and then the hardware interrupt pin method (an LED comes on at the alarm time and is then turned off:

 Conclusion

Hopefully you found this tutorial useful and now have the confidence to use the PCF8563 in your own projects. Furthermore I hope you learned something about the I2C bus and can have satisfaction in that you didn’t take the lazy option of using the library. People often say to me “Oh, there’s a library for that”, however if you used every library – you’d never learn how to interface things for yourself. One day there might not be a library! And then where would you be? So learning the hard way is better for you in the long run. If you have any questions leave a comment below, or ask privately via the contact page.

And if you enjoy my tutorials, or want to introduce someone else to the interesting world of Arduino – check out my book (now in a second printing) “Arduino Workshop” from No Starch Press.

In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.

The post Tutorial – Arduino and PCF8563 real time clock IC appeared first on tronixstuff.

Learn how to use MC14489 LED display driver ICs with Arduino in chapter fifty-one of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – A tutorial on the Arduino universe. The first chapter is here, the complete series is detailed here.

Updated 12/05/2013

Introduction

Recently we’ve been looking at alternatives to the MAX7219 LED display driver IC due to pricing and availability issues (stay tuned for that one) – and came across an old but still quite useful IC – the MC14489 from Motorola (now Freescale Semiconductor). The MC14489 can drive five seven-segment LED numbers with decimal point, or a combination of numbers and separate LEDs. You can also daisy-chain more than one to drive more digits, and it’s controlled with a simple serial data-clock method in the same way as a 74HC595 shift register. Sourcing the MC14489 isn’t too difficult – it’s available from element14, Newark, Digikey, and so on – or if you’re not in a hurry, try the usual suspects like Futurlec.

For the purpose of the tutorial we’ll show you how to send commands easily from your Arduino or compatible board to control a five-digit 7-segment LED display module - and the instructions are quite simple so they should translate easily to other platforms. Once you have mastered the single module, using more than one MC14489 will be just as easy. So let’s get started.

Hardware

Before moving forward, download the data sheet (pdf). You will need to refer to this as you build the circuit(s). And here’s our subject in real life:

mc14489

For our demonstration display we’ll be using a vintage HP 5082-7415 LED display module. However you can use almost any 7-segment modules as long as they’re common-cathode - for example, Sparkfun part number COM-11405. If you’re using a four-digit module and want an extra digit, you can add another single digit display. If you want a ruler, the design files are here.

Connecting the MC14489 to an LED display isn’t complex at all. From the data sheet consider Figure 9 (click the image to enlarge):

schematic

Each of the anode control pins from the MC14489 connect to the matching anodes on your display module, and the BANK1~5 pins connect to the matching digit cathode pins on the display module. You can find the MC14489 pin assignments on page 1 of the data sheet. Seeing as this is chapter fifty-one  - by now you should be confident with finding such information on the data sheets, so I will be encouraging you to do a little more of the work.

Interesting point – you don’t need current-limiting resistors. However you do need the resistor Rx – this controls the current flow to each LED segment. But which value to use? You need to find out the forward current of your LED display (for example 20 mA) then check Figure 7 on page 7 of the data sheet (click image to enlarge):

currentgraph

To be conservative I’m using a value of 2k0 for Rx, however you can choose your own based on the data sheet for your display and the graph above.  Next – connect the data, clock and enable pins of the MC14489 to three Arduino digital pints – for our example we’re using 5, 6 and 7 for data, clock and enable respectively. Then it’s just 5V and GND to Arduino 5V and GND – and put a 0.1uF capacitor between 5V and GND. Before moving on double-check the connections – especially between the MC14489 and the LED display.

Controlling the MC14489

To control the display we need to send data to two registers in the MC14489 – the configuration register  (one byte) and the display register (three bytes). See page 9 of the data sheet for the overview. The MC14489 will understand that if we send out one byte of data it is to send it the configuration register, and if it receives three bytes of data to send it to the display register. To keep things simple we’ll only worry about the first bit (C0) in the configuration register – this turns the display outputs on or off. To do this, use the following:

 digitalWrite(enable, LOW);
 shiftOut(data, clock, MSBFIRST, B00000001); // used binary for clarity, however you can use decimal or hexadecimal numbers
 digitalWrite(enable, HIGH);
 delay(10);

and to turn it off, send bit C0 as zero. The small delay is necessary after each command.

Once you have turned the display on – the next step is to send three bytes of data which represent the numbers to display and decimal points if necessary. Review the table on page 8 of the data sheet. See how they have the binary nibble values for the digits in the third column. Thankfully the nibble for each digit is the binary value for that digit. Furthermore you might want to set the decimal point – that is set using three bits in the first nibble of the three bytes (go back to page 9 and see the display register). Finally you can halve the brightness by setting the very first bit to zero (or one for full brightness).

As an example for that – if you want to display 5.4321 the three bytes of data to send in binary will be:

1101 0101 0100 0011 0010 0001

Let’s break that down. The first bit is 1 for full brightness, then the next three bits (101) turn on the decimal point for BANK5 (the left-most digit). Then you have five nibbles of data, one for each of the digits from left to right. So there’s binary for 5, then four, then three, then two, then one.

 digitalWrite(enable, LOW); 
 shiftOut(data, clock, MSBFIRST, B11010101); // D23~D16 
 shiftOut(data, clock, MSBFIRST, B01000011); // D15~D8
 shiftOut(data, clock, MSBFIRST, B00100001); // D7~D0
 digitalWrite(enable, HIGH);
 delay(10);

To demonstrate everything described so far, it’s been neatly packaged into our first example sketch – Example 51.1:

// Example 51.1
// Motorola MC14489 with HP 5082-7415 5-digit, 7-segment LED display
// 2k0 resistor on MC14489 Rx pin
// John Boxall 2013 CC by-sa-nc
// define pins for data from Arduino to MC14489
// we treat it just like a 74HC595
int data = 5;
int clock = 6;
int enable = 7;
void setup()
{
 pinMode(data, OUTPUT);
 pinMode(enable, OUTPUT);
 pinMode(clock, OUTPUT);
 displayOn(); // display defaults to off at power-up
}
void displayTest1()
// displays 5.4321
{
 digitalWrite(enable, LOW); // send 3 bytes to display register. See data sheet page 9
 // you can also insert decimal or hexadecimal numbers in place of the binary numbers
 // we're using binary as you can easily match the nibbles (4-bits) against the table
 // in data sheet page 8
 shiftOut(data, clock, MSBFIRST, B11010101); // D23~D16 
 shiftOut(data, clock, MSBFIRST, B01000011); // D15~D8
 shiftOut(data, clock, MSBFIRST, B00100001); // D7~D0
 digitalWrite(enable, HIGH);
 delay(10);
}
void displayTest2()
// displays ABCDE
{
 digitalWrite(enable, LOW); // send 3 bytes to display register. See data sheet page 9
 // you can also insert decimal or hexadecimal numbers in place of the binary numbers
 // we're using binary as you can easily match the nibbles (4-bits) against the table
 // in data sheet page 8
 shiftOut(data, clock, MSBFIRST, B10001010); // D23~D16 
 shiftOut(data, clock, MSBFIRST, B10111100); // D15~D8
 shiftOut(data, clock, MSBFIRST, B11011110); // D7~D0
 digitalWrite(enable, HIGH);
 delay(10);
}
void displayOn()
// turns on display
{
 digitalWrite(enable, LOW);
 shiftOut(data, clock, MSBFIRST, B00000001);
 digitalWrite(enable, HIGH);
 delay(10);
}
void displayOff()
// turns off display
{
 digitalWrite(enable, LOW);
 shiftOut(data, clock, MSBFIRST, B00000000);
 digitalWrite(enable, HIGH);
 delay(10);
}
void loop()
{
 displayOn();
 displayTest1();
 delay(1000);
 displayTest2();
 delay(1000);
 displayOff();
 delay(500);
}

… with the results in the following video:


Now that we can display numbers and a few letters with binary, life would be easier if there was a way to take a number and just send it to the display.

So consider the following function that takes an integer between 0 and 99999, does the work and sends it to the display:

void displayIntLong(long x)
// takes a long between 0~99999 and sends it to the MC14489
{
 int numbers[5];
 byte a=0; 
 byte b=0; 
 byte c=0; // will hold the three bytes to send to the MC14489 

 // first split the incoming long into five separate digits
 numbers[0] = int ( x / 10000 ); // left-most digit (will be BANK5)
 x = x % 10000; 
 numbers[1] = int ( x / 1000 );
 x = x % 1000; 
 numbers[2] = int ( x / 100 );
 x = x % 100; 
 numbers[3] = int ( x / 10 );
 x = x % 10; 
 numbers[4] = x % 10; // right-most digit (will be BANK1)

 // now to create the three bytes to send to the MC14489
 // build byte c which holds digits 4 and 5
 c = numbers[3];
 c = c << 4; // move the nibble to the left
 c = c | numbers[4];
 // build byte b which holds digits 3 and 4
 b = numbers [1];
 b = b << 4;
 b = b | numbers[2];
 // build byte a which holds the brightness bit, decimal points and digit 1
 a = B10000000 | numbers[0]; // full brightness, no decimal points

 // now send the bytes to the MC14489
 digitalWrite(enable, LOW);
 shiftOut(data, clock, MSBFIRST, a);
 shiftOut(data, clock, MSBFIRST, b);
 shiftOut(data, clock, MSBFIRST, c); 
 digitalWrite(enable, HIGH);
 delay(10); 
}

So how does that work? First it splits the 5-digit number into separate digits and stores them in the array numbers[]. It then places the fourth digit into a byte, then moves the data four bits to the left – then we bitwise OR the fifth digit into the same byte. This leaves us with a byte of data containing the nibbles for the fourth and fifth digit. The process is repeated for digits 2 and 3. Finally the brightness bit and decimal point bits are assigned to another byte which then has the first digit’s nibble OR’d into it. Which leaves us with bytes a, b and c ready to send to the MC14489. Note that there isn’t any error-checking – however you could add a test to check that the number to be displayed was within the parameter, and if not either switch off the display (see example 51.1) or throw up all the decimal points or … whatever you want.

You can download the demonstration sketch for the function – Example 51.2, and view the results in the following video:

You can also display the letters A to F by sending the values 10 to 15 respectivel to each digit’s nibble. However that would be part of a larger application, which you can (hopefully) by now work out for yourself. Furthermore there’s some other characters that can be displayed – however trying to display the alphabet using 7-segment displays is somewhat passé. Instead, get some 16-segment LED modules or an LCD.

Finally, you can cascade more than one MC14489 to control more digits. Just run a connection from the data out pin on the first MC14889 to the data pin of the second one, and all the clock and enable lines together. Then send out more data – see page 11 of the data sheet. If you’re going to do that in volume other ICs may be a cheaper option and thus lead you back to the MAX7219.

Conclusion

For a chance find the MC14489 is a fun an inexpensive way to drive those LED digit displays. We haven’t covered every single possible option or feature of the part – however you will now have the core knowledge to go further with the MC14489 if you need to move further with it. And if you enjoy my tutorials, or want to introduce someone else to the interesting world of Arduino – check out my new book “Arduino Workshop” from No Starch Press.

In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.


Learn how to use MC14489 LED display driver ICs with Arduino in chapter fifty-one of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – A tutorial on the Arduino universe. The first chapter is here, the complete series is detailed here.

Updated 12/05/2013

Introduction

Recently we’ve been looking at alternatives to the MAX7219 LED display driver IC due to pricing and availability issues (stay tuned for that one) – and came across an old but still quite useful IC – the MC14489 from Motorola (now Freescale Semiconductor). The MC14489 can drive five seven-segment LED numbers with decimal point, or a combination of numbers and separate LEDs. You can also daisy-chain more than one to drive more digits, and it’s controlled with a simple serial data-clock method in the same way as a 74HC595 shift register. Sourcing the MC14489 isn’t too difficult – it’s available from element14, Newark, Digikey, and so on – or if you’re not in a hurry, try the usual suspects like Futurlec.

For the purpose of the tutorial we’ll show you how to send commands easily from your Arduino or compatible board to control a five-digit 7-segment LED display module - and the instructions are quite simple so they should translate easily to other platforms. Once you have mastered the single module, using more than one MC14489 will be just as easy. So let’s get started.

Hardware

Before moving forward, download the data sheet (pdf). You will need to refer to this as you build the circuit(s). And here’s our subject in real life:

mc14489

For our demonstration display we’ll be using a vintage HP 5082-7415 LED display module. However you can use almost any 7-segment modules as long as they’re common-cathode - for example, Sparkfun part number COM-11405. If you’re using a four-digit module and want an extra digit, you can add another single digit display. If you want a ruler, the design files are here.

Connecting the MC14489 to an LED display isn’t complex at all. From the data sheet consider Figure 9:

schematic

Each of the anode control pins from the MC14489 connect to the matching anodes on your display module, and the BANK1~5 pins connect to the matching digit cathode pins on the display module. You can find the MC14489 pin assignments on page 1 of the data sheet. Seeing as this is chapter fifty-one  - by now you should be confident with finding such information on the data sheets, so I will be encouraging you to do a little more of the work.

Interesting point – you don’t need current-limiting resistors. However you do need the resistor Rx – this controls the current flow to each LED segment. But which value to use? You need to find out the forward current of your LED display (for example 20 mA) then check Figure 7 on page 7 of the data sheet:

currentgraph

To be conservative I’m using a value of 2k0 for Rx, however you can choose your own based on the data sheet for your display and the graph above.  Next – connect the data, clock and enable pins of the MC14489 to three Arduino digital pints – for our example we’re using 5, 6 and 7 for data, clock and enable respectively. Then it’s just 5V and GND to Arduino 5V and GND – and put a 0.1uF capacitor between 5V and GND. Before moving on double-check the connections – especially between the MC14489 and the LED display.

Controlling the MC14489

To control the display we need to send data to two registers in the MC14489 – the configuration register  (one byte) and the display register (three bytes). See page 9 of the data sheet for the overview. The MC14489 will understand that if we send out one byte of data it is to send it the configuration register, and if it receives three bytes of data to send it to the display register. To keep things simple we’ll only worry about the first bit (C0) in the configuration register – this turns the display outputs on or off. To do this, use the following:

digitalWrite(enable, LOW);
shiftOut(data, clock, MSBFIRST, B00000001); // used binary for clarity, however you can use decimal or hexadecimal numbers
digitalWrite(enable, HIGH);
delay(10);

and to turn it off, send bit C0 as zero. The small delay is necessary after each command.

Once you have turned the display on – the next step is to send three bytes of data which represent the numbers to display and decimal points if necessary. Review the table on page 8 of the data sheet. See how they have the binary nibble values for the digits in the third column. Thankfully the nibble for each digit is the binary value for that digit. Furthermore you might want to set the decimal point – that is set using three bits in the first nibble of the three bytes (go back to page 9 and see the display register). Finally you can halve the brightness by setting the very first bit to zero (or one for full brightness).

As an example for that – if you want to display 5.4321 the three bytes of data to send in binary will be:

1101 0101 0100 0011 0010 0001

Let’s break that down. The first bit is 1 for full brightness, then the next three bits (101) turn on the decimal point for BANK5 (the left-most digit). Then you have five nibbles of data, one for each of the digits from left to right. So there’s binary for 5, then four, then three, then two, then one.

digitalWrite(enable, LOW); 
shiftOut(data, clock, MSBFIRST, B11010101); // D23~D16 
shiftOut(data, clock, MSBFIRST, B01000011); // D15~D8
shiftOut(data, clock, MSBFIRST, B00100001); // D7~D0
digitalWrite(enable, HIGH);
delay(10);

To demonstrate everything described so far, it’s been neatly packaged into our first example sketch:

// Example 51.1
// Motorola MC14489 with HP 5082-7415 5-digit, 7-segment LED display
// 2k0 resistor on MC14489 Rx pin
// John Boxall 2013 CC by-sa-nc
// define pins for data from Arduino to MC14489
// we treat it just like a 74HC595
int data = 5;
int clock = 6;
int enable = 7;
void setup()
{
 pinMode(data, OUTPUT);
 pinMode(enable, OUTPUT);
 pinMode(clock, OUTPUT);
 displayOn(); // display defaults to off at power-up
}
void displayTest1()
// displays 5.4321
{
 digitalWrite(enable, LOW); // send 3 bytes to display register. See data sheet page 9
 // you can also insert decimal or hexadecimal numbers in place of the binary numbers
 // we're using binary as you can easily match the nibbles (4-bits) against the table
 // in data sheet page 8
 shiftOut(data, clock, MSBFIRST, B11010101); // D23~D16
 shiftOut(data, clock, MSBFIRST, B01000011); // D15~D8
 shiftOut(data, clock, MSBFIRST, B00100001); // D7~D0
 digitalWrite(enable, HIGH);
 delay(10);
}
void displayTest2()
// displays ABCDE
{
 digitalWrite(enable, LOW); // send 3 bytes to display register. See data sheet page 9
 // you can also insert decimal or hexadecimal numbers in place of the binary numbers
 // we're using binary as you can easily match the nibbles (4-bits) against the table
 // in data sheet page 8
 shiftOut(data, clock, MSBFIRST, B10001010); // D23~D16
 shiftOut(data, clock, MSBFIRST, B10111100); // D15~D8
 shiftOut(data, clock, MSBFIRST, B11011110); // D7~D0
 digitalWrite(enable, HIGH);
 delay(10);
}
void displayOn()
// turns on display
{
 digitalWrite(enable, LOW);
 shiftOut(data, clock, MSBFIRST, B00000001);
 digitalWrite(enable, HIGH);
 delay(10);
}
void displayOff()
// turns off display
{
 digitalWrite(enable, LOW);
 shiftOut(data, clock, MSBFIRST, B00000000);
 digitalWrite(enable, HIGH);
 delay(10);
}
void loop()
{
 displayOn();
 displayTest1();
 delay(1000);
 displayTest2();
 delay(1000);
 displayOff();
 delay(500);
}

… with the results in the following video:


Now that we can display numbers and a few letters with binary, life would be easier if there was a way to take a number and just send it to the display.

So consider the following function that takes an integer between 0 and 99999, does the work and sends it to the display:

void displayIntLong(long x)
// takes a long between 0~99999 and sends it to the MC14489
{
 int numbers[5];
 byte a=0; 
 byte b=0; 
 byte c=0; // will hold the three bytes to send to the MC14489 

 // first split the incoming long into five separate digits
 numbers[0] = int ( x / 10000 ); // left-most digit (will be BANK5)
 x = x % 10000; 
 numbers[1] = int ( x / 1000 );
 x = x % 1000; 
 numbers[2] = int ( x / 100 );
 x = x % 100; 
 numbers[3] = int ( x / 10 );
 x = x % 10; 
 numbers[4] = x % 10; // right-most digit (will be BANK1)

 // now to create the three bytes to send to the MC14489
 // build byte c which holds digits 4 and 5
 c = numbers[3];
 c = c << 4; // move the nibble to the left
 c = c | numbers[4];
 // build byte b which holds digits 3 and 4
 b = numbers [1];
 b = b << 4;
 b = b | numbers[2];
 // build byte a which holds the brightness bit, decimal points and digit 1
 a = B10000000 | numbers[0]; // full brightness, no decimal points

 // now send the bytes to the MC14489
 digitalWrite(enable, LOW);
 shiftOut(data, clock, MSBFIRST, a);
 shiftOut(data, clock, MSBFIRST, b);
 shiftOut(data, clock, MSBFIRST, c); 
 digitalWrite(enable, HIGH);
 delay(10); 
}

So how does that work? First it splits the 5-digit number into separate digits and stores them in the array numbers[]. It then places the fourth digit into a byte, then moves the data four bits to the left – then we bitwise OR the fifth digit into the same byte. This leaves us with a byte of data containing the nibbles for the fourth and fifth digit. The process is repeated for digits 2 and 3. Finally the brightness bit and decimal point bits are assigned to another byte which then has the first digit’s nibble OR’d into it. Which leaves us with bytes a, b and c ready to send to the MC14489. Note that there isn’t any error-checking – however you could add a test to check that the number to be displayed was within the parameter, and if not either switch off the display (see example 51.1) or throw up all the decimal points or … whatever you want.

You can download the demonstration sketch for the function – Example 51.2, and view the results in the following video:

You can also display the letters A to F by sending the values 10 to 15 respectivel to each digit’s nibble. However that would be part of a larger application, which you can (hopefully) by now work out for yourself. Furthermore there’s some other characters that can be displayed – however trying to display the alphabet using 7-segment displays is somewhat passé. Instead, get some 16-segment LED modules or an LCD.

Finally, you can cascade more than one MC14489 to control more digits. Just run a connection from the data out pin on the first MC14889 to the data pin of the second one, and all the clock and enable lines together. Then send out more data – see page 11 of the data sheet. If you’re going to do that in volume other ICs may be a cheaper option and thus lead you back to the MAX7219.

Conclusion

For a chance find the MC14489 is a fun an inexpensive way to drive those LED digit displays. We haven’t covered every single possible option or feature of the part – however you will now have the core knowledge to go further with the MC14489 if you need to move further with it. And if you enjoy my tutorials, or want to introduce someone else to the interesting world of Arduino – check out my new book “Arduino Workshop” from No Starch Press.

LEDborder

In the meanwhile have fun and keep checking into tronixstuff.com. Why not follow things on twitterGoogle+, subscribe  for email updates or RSS using the links on the right-hand column? And join our friendly Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, helpful to each other –  and we can all learn something.

The post Tutorial – Arduino and MC14489 LED Display Driver appeared first on tronixstuff.

Apr
01

Vehicle OBD2 Arduino Shield with STN1110 IC

arduino, ELM327, IC, OBD, OBD2, STN1110 Comments Off on Vehicle OBD2 Arduino Shield with STN1110 IC 

obd2shield_artistic

sigalabs.com have designed and build a great OBD2 Arduino Shield using STN110 IC :

The STN110 is a multiprotocol OBD to UART interpreter IC. It provides an easy means of accessing vehicle data, including diagnostic trouble codes, MIL status, VIN, Inspection and Maintenance (I/M) information, In-use Performance Tracking (IPT), and hundreds of real-time parameters.

It is compatible with famous ELM327 commands but introduce many new great features.

Vehicle OBD2 Arduino Shield with STN1110 IC - [Link]

Mar
22

Something is rotten in Denmark (Bio-Hacks)

around the world, biohacking, Copenhagen, Hacks, Hardware, IC, inspiration, Makerspaces Comments Off on Something is rotten in Denmark (Bio-Hacks) 

Labitat, 3/2013

Massimo and I had the chance to visit a Labitat makerspace in Copenhagen. I have to thank Martin Markus to let us in on a non-visit day and move underground, where the lab is.

The main reason of our visit was getting in touch with the Bio-Hackers and Maker Community meeting there, get them involved in the Call of Makers for the upcoming European Maker Faire in Rome. We had a good time in talking with them about the strange situation we are witnessing here in Europe: many languages, many nations, one big movement of people tinkering around stuff. Get everybody to know about this event and the chance to meet and talk to each other is a massive task. But we are going to overcome it!

Labitat, 3/2013

The place is just super. I’ve been involved in the making of a makespaces in the last three years of my life, but I have no words in describing the feelings I had in witnessing the massive amount of contents that basement kept. No joke.

I tried my best in recovering those objects, those feelings and this odd XXIst century knowledge in a pool set of Flickr, where I tried to describe and follow the different projects I’ve seen.

 

Why visiting makerspaces is to me just like standing on giants shoulders? Basically because I know the problems and I see better, streamlined solutions answering (better than ours in Fablab Torino. You guys feel free to comment and make me feel naiv about the Fridge,  Bio Hacks, the communication billboards, and the AtMEGA 16u2 hack from Dennis.

 

Nov
15

Arduino Mp3 Player – Arduino JukeBox

IC, jukebox, mp3, mp3 player, music, vs1002d, vs1003, vs1053 Comments Off on Arduino Mp3 Player – Arduino JukeBox 

A full Arduino MP3 player using a SD card and a MP3 module based on a chip from VLSI (VS1002d, VS1003 VS1053). The player includes a small amplifier and two speakers, making it a small Jukebox in the age of Ipods. The project includes a small library for the management of the MP3 and the SD chip. A Funny Arduino project ..

via [arduino-guay]



  • Newsletter

    Sign up for the PlanetArduino Newsletter, which delivers the most popular articles via e-mail to your inbox every week. Just fill in the information below and submit.

  • Like Us on Facebook