MAX7219 and 8 x 7 Segment LED Display

 

The code for this can be downloaded from my GitHub page here.

This display can be found on eBay here. It consists of two 4 digit seven segment LEDS with a MAX7219 driver IC. I have used the LedControl library available from here, the examples show the basic library use, but I wanted to be able to send data over a Serial connection. The MAX7219 presents some problems in sending a string of characters, unlike some other drivers like the TM1638 where a string can be sent, the MAX7219 needs to set each LED individually.

The sketch below allows a number up to 8 characters (or 7 with a minus sign) to be sent to the Serial port. It can be typed into the Serial Monitor, or sent from, say, a Bluetooth receiver. Characters are received one at a time and stored in an array, once all the data has been received the contents of the array are then sent to the relevant LEDs. The number is also available in the string stringNumber once all characters have been received.

The sketch shows the connections for the board to Arduino, five in total are needed, 5 volts, Ground, Data In is connected Arduino pin 12, CLK is connected to Arduino pin 11 and Load OS connected to Arduino pin 10.

Upload the sketch and switch to the Serial Monitor, select 9600 Baud and NL/CR. Type a number and it will appear on the LEDs, to clear and blank the display send a letter.

/***********************************************************
 * 
 * MAX7219 and 8x7 Segment LED Display
 * 
 * by Chris Rouse November 2015
 * 
 Connections
 pin 12 is connected to the DataIn 
 pin 11 is connected to the CLK 
 pin 10 is connected to LOAD 
 We have a single MAX7219. 
 * 
 * The number to display is read from the Serial Input
 * either type the number in the Serial Monitor
 * or via, for example, Bluetooth.
 * 
 * Only numbers are displayed, but negative 
 * and decimal fractions can be displayedz
 * 
 * For numbers less than zero, for example 0.125
 * must have a leading zero, ie 0.125 and not .125
 * 
 * The LED display can be cleared by sending any letter
 * 
 **********************************************************/
#include "LedControl.h" 
LedControl lc=LedControl(12,11,10,1);
int number[8];
int numLength = 0; // number of digitss
int i = 0;
int dp = 0; // position of decimal point, if any
int j = 0;
boolean minusSign = false; // false if negative number
boolean valid = false;
double displayNumber = 0;
String stringNumber;
void setup() {
  /*
   The MAX7219 is in power-saving mode on startup,
   we have to do a wakeup call
   */
  lc.shutdown(0,false);
  /* Set the brightness to a medium values */
  lc.setIntensity(0,8);
  /* and clear the display */
  lc.clearDisplay(0);
  /* Start Serial Monitor */
  Serial.begin(9600);
}

void printDigits() {
lc.clearDisplay(0);
for(i=0;i<numLength;i++) {
if( dp == numLength-i){
lc.setDigit(0,i,number[numLength-(i+1)],true);
}
else{
lc.setDigit(0,i,number[numLength-(i+1)],false);
}
}
}
//
void loop() {
if(Serial.available()){
j = 0;
numLength = 0;
dp=0;
stringNumber ="";
}
// get number to display
while (Serial.available()){
delay(10);
int a = Serial.read();
stringNumber = stringNumber + char(a);
if((a>47 && a< 58) || a == 45){ // ignore line end and decimal point
a = a - 48;
number[j] = a;
numLength=numLength+1;
if(numLength > 8){
numLength = 8; // stop overflow
}
j = j +1;
}
if(a == 46) { // decimal point
dp = numLength;
}
printDigits();
valid = true;
}
// check for a minus
if (number[0] == -3){
lc.setRow(0,numLength-1,B00000001); // print a minus sign
}
if(valid == true){
Serial.println(stringNumber); // this is the string sent to the Serial Port.
valid = false;
}
}

Advertisements

8 Seven Segment LED Display with Keys and LEDs using TM1638.

The sketch and library can be downloaded from my GitHub page here

Using the library available from here this board is easy to operate. Connecting the board to an Arduino requires five connections, Vcc to Arduino 5 volts, Gnd to Gnd. STB, CLK and DIO on the display board connect to 7, 9 and 8 on the Arduino.

The library contains a number of examples, but the pins used for Clock, Strobe and Digital Input varies in each example, so I have defined these at the start.

/*

TM1638 8 x Seven Segment Display with Keys and LEDs
Tests some functions
No key pressed displays decimal number
Key 1 pressed displays HEX value
Key 2 pressed displays binary value
Key 3 pressed clears displayed
Key 4 pressed displays a text string

Connections::
Vcc to Arduino 5 volts
Gnd to Arduino Gnd
Strobe, Digital I/O and clock are defined in the sketch
*/

#include <TM1638.h>
const int strobe = 7;
const int clock = 9;
const int data = 8;
int dots = 0x0; // display all decimal points, value in hexadecimal
int leds = 0xFF; // mask to display LEDS
byte keys; // key value
double number; // number to display
// define a module
TM1638 module(data, clock, strobe);

void setup() {
Serial.begin(9600);
module.clearDisplay(); // clear the display
number = 12345678; // decimal number
}

void loop() {
// display a number
  switch(keys){
case 0:
module.setDisplayToDecNumber(number, dots);
break;

case 1:
module.setDisplayToHexNumber(number, dots);
break;

case 2:
module.setDisplayToBinNumber(number, dots);
break;

case 4:
module.clearDisplay(); // clear the display
break;

case 8:
module.setDisplayToString("testing ");
break;

case 16:

break;

case 32:

break;

case 64:

break;

case 128:

break;

default:

break;
}
//

// get a key press
getKeyPressed();
//
}


void getKeyPressed(){
keys = module.getButtons();
Serial.println(keys);
// light the LED
module.setLEDs(keys & leds);
}

Testing RGB LEDs and the KY009 Three Colour LED.

The code is available on my GitHub page here.

Some versions of this board have resisistors in series with the LEDs, some do not. If resistors are not present then use a 390R resistor in series to limit the current.

I was not very impressed with this RGB LED board. It is nothing more than a three colour LED on a PCB, which is not a problem, however neither the Blue or the Red LEDs would work with PWM. This means that it’s not possible to achieve full colour mixing, although some limited mixing can be achieved. I tried a second board and on this one the Red and Blue LEDs would dim with PWM, but the green LED simply switched on and off.

I decided to write a sketch that could be used to test RGB LEDs with an Arduino. This sketch has two parts, the first switches LEDs on and off to provide a rainbow of colours, Red, Green, Yellow, Cyan, Blue and Violet. The second part tests the LEDs ability to fade in and out and each LED is tested separately. Either of the two routines can be switched off by setting either Of the variables rainbow or fader to false.

The LED in its naked form does not give very good colour mixing, so I made a simply diffuser by first cutting a ping pong ball in half then glueing some thin greasproof paper onto the open part of the ball. Place this dome (paper side down) over the RGB LED. An example of the diffuser is shown here.

Connect the common pin to pin 2, the Red LED to pin 3, the Green LED to pin 4 and the Blue LED to pin 5.



/*
RGB LED Test
This sketch checks a RGB LED to ensure that PWM can be used
to produce a complete range of colours
For best colour mixing results use a diffuser
*/
int gndPin = 2; // the RGB LED common connection
int redLed = 3; // the Red LED
int greenLed = 4; // the green LED
int blueLed = 5; // the blue LED
int brightness = 0; // how bright the LED is
int fadeAmount = 5; // how many points to fade the LED by
//
// set either of these to false to disable the effect
boolean rainbow = true; // enable the rainbow display
boolean fader = true; // enable the fade display
//
void setup() {
// declare pin 2 and 3 to be an output:
pinMode(gndPin, OUTPUT);
digitalWrite(gndPin, LOW);
pinMode(redLed, OUTPUT);
pinMode(greenLed, OUTPUT);
pinMode(blueLed, OUTPUT);
}

void loop(){
if (rainbow){
// Rainbow

for(int r=0; r<3; r++){
analogWrite(redLed, 255); // Red
delay(2000);
analogWrite(greenLed, 255); // Yellow
delay(2000);
analogWrite(redLed, 0); // Green
delay(2000);
analogWrite(blueLed, 128); //Blue/Green
delay(2000);
analogWrite(blueLed, 255); //Blue/Green
analogWrite(greenLed, 0); //Blue
delay(2000);
analogWrite(redLed, 255); // Violet
delay(2000);
analogWrite(redLed, 0); // LEDs all OFF
analogWrite(blueLed, 0);
}
}
// the fader effect
if(fader){
brightness = 0;
fadeAmount = 5;
redLedLoop();
analogWrite(redLed, 0);
//
brightness = 0;
fadeAmount = 5;
greenLedLoop();
//
analogWrite(greenLed, 0);
//
brightness = 0;
fadeAmount = 5;
blueLedLoop();
analogWrite(blueLed, 0);
}
}

// the fade routines
//
void redLedLoop() {
for(int i=0; i<255; i++){
analogWrite(redLed, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
}
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}

void greenLedLoop(){
//
for(int i=0; i<255; i++){
analogWrite(greenLed, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
}
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}

void blueLedLoop(){
for(int i=0; i<255; i++){
analogWrite(blueLed, brightness);
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness == 0 || brightness == 255) {
fadeAmount = -fadeAmount ;
}
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}

Four Digit Seven Segment LED Display

  

 

Update: LDR control of brightness can be found here.

This display has a TM1637 display driver and was made by Seed Studio although there are a number of copies around. The display has four connections, Vcc, Gnd, Clock and Data. I had so much trouble trying to get this to work, I found two different libraries but neither seemed to work. Even the library and example from Seed Studio just would not work for me.

Eventually I found this blog that explained what was needed. Most of the other tutorials used a number of libraries (anything up to five!) but this sketch used no library at all. It seems that the sequence used to send data to the driver has to be done in a specific way.

I wanted to build a clock, but the blog gave a sketch for a timer, so I have modified the original sketch so that the clock shows Hours and Minutes. The sketch is the work of the original blogger, but I publish my modified version here with the original author data intact.

The time can be set by editing the time set section, mine was set to start at 22:11. Edit this setting the time a minute or so fast then at the correct time press Reset on the Arduino. The clock shows time in the 24 hour format.

Connections:

Arduino TM1637 display
PIN #7 ------------------ CLK
PIN #8 ------------------ DIO
5V ---------------------- VCC
GND --------------------- GND

The Sketch:

/* TM1637 4 Digit Seven Segment Display, Clock
Credit to Blog 3D Logic.com */


/* 24 hour clock code by Chris Rouse

Connections:
Vcc on Display to 5 volts on Arduino
Gnd on Display to Gnd on Arduino
CLK on Display to Pin 2 on Arduino
DIO on Display to pin 3 on Arduino
*/

const int clock = 2;
const int data = 3;

/*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/
uint8_t digits[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f };
byte tcnt2;
//unsigned long time = 0; // 86390000;

/********************************************************
Set clock to desired time if required
Otherwise REM the next 3 lines out and the clock
will start from 00:00
Do not add leading zeros to the values
time is in 24 hour format
**********************************************************/
unsigned long setMinutes = 11;
unsigned long setHours = 22;
unsigned long time = (setMinutes * 60 * 1000) + (setHours * 3600 *1000);
/***************************************************************/

void setup()
{
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
setupInterrupt();

pinMode(clock, OUTPUT);
pinMode(data, OUTPUT);

// initialise display and set brightness
// 0x88 is dim and increasing value to 0x8C increases brightness
start();
writeValue(0x8c);
stop();

// clear display
write(0xff, 0xff, 0xff, 0xff);
}

// Credits for the interrupt setup routine:
// http://popdevelop.com/2010/04/mastering-timer-interrupts-on-the-arduino/
void setupInterrupt()
{
/* First disable the timer overflow interrupt while we're configuring */
TIMSK2 &= ~(1<<toie2);

</toie2);

/* Configure timer2 in normal mode (pure counting, no PWM etc.) */
TCCR2A &= ~((1<<wgm21) |="" (1<<wgm20));

TCCR2B &= ~(1<<wgm22);

</wgm22);

/* Select clock source: internal I/O clock */
ASSR &= ~(1<<as2);

</as2);

/* Disable Compare Match A interrupt enable (only want overflow) */
TIMSK2 &= ~(1<<ocie2a);

</ocie2a);

/* Now configure the prescaler to CPU clock divided by 128 */
TCCR2B |= (1<<cs22) |="" (1<<cs20);="" set="" bits

TCCR2B &= ~(1<<cs21); clear="" bit

/* We need to calculate a proper value to load the timer counter.
* The following loads the value 131 into the Timer 2 counter register
* The math behind this is:
* (CPU frequency) / (prescaler value) = 125000 Hz = 8us.
* (desired period) / 8us = 125.
* MAX(uint8) + 1 - 125 = 131;
*/
/* Save value globally for later reload in ISR */
tcnt2 = 131;

/* Finally load end enable the timer */
TCNT2 = tcnt2;
TIMSK2 |= (1<<toie2);
}</toie2);
/*
* Install the Interrupt Service Routine (ISR) for Timer2 overflow.
* This is normally done by writing the address of the ISR in the
* interrupt vector table but conveniently done by using ISR() */
ISR(TIMER2_OVF_vect) {
/* Reload the timer */
TCNT2 = tcnt2;

time++;
time = time % 86400000;

}

void loop()
{
unsigned long t = (unsigned long)(time/1000);
uint8_t minutes = (byte)((t / 60) % 60);
uint8_t hours = (byte)((t / 3600) % 23);
uint8_t seconds = (byte)(t % 60);

// blink onboard LED every Second
if(((seconds/2)*2) == seconds) {
digitalWrite(13, LOW);
}
else {
digitalWrite(13, HIGH);
}
//
// display the time
write(digits[hours / 10], digits[hours % 10] | ((seconds & 0x01) << 7), digits[minutes / 10], digits[minutes % 10]);
}

void write(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
{
start();
writeValue(0x40);
stop();

start();
writeValue(0xc0);
writeValue(first);
writeValue(second);
writeValue(third);
writeValue(fourth);
stop();
}

void start(void)
{
digitalWrite(clock,HIGH);//send start signal to TM1637
digitalWrite(data,HIGH);
delayMicroseconds(5);

digitalWrite(data,LOW);
digitalWrite(clock,LOW);
delayMicroseconds(5);
}

void stop(void)
{
digitalWrite(clock,LOW);
digitalWrite(data,LOW);
delayMicroseconds(5);

digitalWrite(clock,HIGH);
digitalWrite(data,HIGH);
delayMicroseconds(5);
}

bool writeValue(uint8_t value)
{
for(uint8_t i = 0; i < 8; i++)
{
digitalWrite(clock, LOW);
delayMicroseconds(5);
digitalWrite(data, (value & (1 << i)) >> i);
delayMicroseconds(5);
digitalWrite(clock, HIGH);
delayMicroseconds(5);
}

// wait for ACK
digitalWrite(clock,LOW);
delayMicroseconds(5);

pinMode(data,INPUT);

digitalWrite(clock,HIGH);
delayMicroseconds(5);

bool ack = digitalRead(data) == 0;

pinMode(data,OUTPUT);

return ack;
}

Things to do:
The brightness of the display can be altered and there are eight levels from dim to bright, adding an LDR circuit could be used to dim the display as the light level drops.