Pages: [1]   Go Down
Author Topic: 8 digts 7 segment LED display  (Read 3330 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi.
I'm moving my first steps with ad Arduino UNO, please be patient...

I would like to drive a 8 digits 7 segment display (8 segment to be precise as THere's also the dot).
I've read a couple of things about the 74HC595 wich seemed to be used on the little shield I get from Internet (http://www.miniinthebox.com/8-x-seven-segment-displays-module-for-arduino-595-driver_p411869.html) and it seemed complex but not so crazy.

At the first try I get unexpeted and random results.
I was thinking I had to drive a 64 positions register each one related to each segment but... now it's clear that's not the game I have to play.
In addition, taking a look at the two 4 digit display I can see that each has just 12 pins under each block of segment (24 in total) so there should be some kind of multiplexing I have to deal with to light the segment I cannot figure out.

-- Do anyone has already worked with this shield? (I cannot find out any tech document)

-- Do you know how many bits I have to deal with while eriting to the register before sending HIGH to the RCLK pin?

-- Is there any documentation around I can use to understand how to send data to the register as lo light the segment I want lo light?

Thanks to all.
(Please, simple english as mine is a disaster :-(( )

A.-
Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 524
Posts: 26466
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Is there any documentation on the part?
5 control pins - +5, Gnd, Clock, Data, Latch?
One shift register likely controlling the segments, one controlling which digit is selected.
So the game:
send out 2 bytes, one will have segment info, one will have digit control.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

>Is there any documentation on the part?
No

>5 control pins - +5, Gnd, Clock, Data, Latch?
Yes

>One shift register likely controlling the segments, one controlling which digit is selected.
>So the game: >send out 2 bytes, one will have segment info, one will have digit control.

Not understood.
If I try to send to send 24 bit (just fgured out thinkng of the 24 pin I can see under the digits), when I send High to 9 to 16 position I light the full segment (each bit lights an entire segment) but nothing happens if, at the same time, I set any of the bits from 1 to 8.
Is this related to what yore saying?

Thanks.
Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 524
Posts: 26466
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Sort of.
You will send 2 bytes to the part every 4 mS.
1 byte will determine what is displayed, the 2nd will determine where it is displayed.

The "what" is displayed usually comes from an array:
Code:
byte fontArray[] = {
B00111111, // 0   bit 0 = a, 1=b, 2=c, 3=d, 4=e, 5=f, 6=g, 7=decimal    High bit sources current for the selected segment
B00000110, // 1          a
B01011011, // 2    f            b
etc                                g
B01100111, // 9    e           c
};                                   d
The "where" comes from a 2nd array:
Code:
byte digitArray[] = {
B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111,}; // 0 sinks current for the digit selected
So you send out 2 bytes:
http://arduino.cc/en/Reference/ShiftOut
Code:
digitalWrite(latchPin, LOW);
shiftout(dataPin, clockPin, MSBFIRST,fontArray[x]); // these 2 lines may need to be swapped
shiftout(dataPin, clockPin, MSBFIRTS, digitArray[y]); // around, depends on how board is wired
digitalWrite(latchPin, HIGH);
This code would be in a loop, where one bye of fontArray data was sent out with one byte of digitArray.
Say you wanted to display the numbers 0 to 7 on the display. Then the loop might be:
Code:
for (x = 0; x<8; x=x+1){ // count from 0 to 7
digitalWrite(latchPin, LOW); // bring the shift register latch pin low
shiftout(dataPin, clockPin, MSBFIRST,fontArray[x]);  // shift out the segment info
shiftout(dataPin, clockPin, MSBFIRTS, digitArray[x]);  // shift out the digit select info
digitalWrite(latchPin, HIGH);   // bring the shift register latch pin high, moves the data to the outputs
delay (4);  // delay to let the data be seen at each digit (there are better ways to create this pause)
}
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

WOW!

This evening I'm going to read what you wrote in peace but...
.. do this means that I can write one digit a time so I need a lot of speed writing all the digits and rely on the persistence of my eye to get the whole 8 digits????

(Hope my english is understandable)

A.-
Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 524
Posts: 26466
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes. One digit at a time, with persistence of vision.

With 4mS/digit, and a 16 MHz clock, you have 64,000 clock cycles for every digit, so the speed writing is easily done.

Here is a way I do the time part so delay() is not needed.
Code:
unsigned long currentmillis();  // millis() and micros() are type unsigned long, 0x00000000 to 0xFFFFFFFF
unsigned long previousmillis();
unsigned long duration = 4;  // time in mS to display each digit
// declare other variables, and arrays discussed earlier

void setup(){
// do all the setup stuff, pinModes & stuff.
};

void loop(){
currentmillis = millis();  // capture the "time"
if ( (currentmillis - previousmillis)>=duration){  // 4 mS gone by yet?
previousmillis = previousmillis  + duration;  // reset for next time check

x=x+1;  // break down for:next loop so it can run within the time check
if (x==8){
x=0;  // reset  after passing 7
}
digitalWrite(latchPin, LOW); // bring the shift register latch pin low
shiftout(dataPin, clockPin, MSBFIRST,fontArray[x]);  // shift out the segment info
shiftout(dataPin, clockPin, MSBFIRTS, digitArray[x]);  // shift out the digit select info
digitalWrite(latchPin, HIGH);   // bring the shift register latch pin high, moves the data to the outputs
} // end time check
// do other stuff if desired while waiting for next time check
} // end void loop


Make sense?
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Well... even if with everything is still to put in order... IT WORKS!

Still using the bitRead() fuction (understood it's not the func for this job), still few problems with the delay, still to reengineer as to work in an environment where the main objective is something else, still to reorganize as to be used as a 'black box library' but... my main problem is behind.

Let's say the first time you come to Italy (if not already here) you get a serious bottle of wine.

Thanks a lot.

Alberto.-

Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 524
Posts: 26466
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, not too bad just from looking at a picture smiley-cool
We are cooking a turkey for dinner (it was still quite frozen on Christmas Day), I will think of your wine as we enjoy our meal smiley
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Thanks to all.

I would take a generic approach:

1) set up a timer isr that fires periodically. I think a 100hz refresh rate more than works for everyone. That means you need to refresh each digit about 1-2ms.
2) in the timer isr, keep track of which digit you are refreshing and pick up the font / segment information from a display buffer.

Once that is setup, the whole thing runs entirely in the background, regardless of what you do in the loop(). All you need to do there is to stuff the segment information into the display buffer, and the isr will take care of refreshing the leds.

Your leds will never flicker.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

> set up a timer isr

I don't have a precise project to work on but just spending time trying to learn something so I'm I'd be happy to try different approach.
As I neither know what a timer isr is I'll google around at first... any link to example or whatever can bu usefull for a beginner?

Thanks.

Alberto.-

P.S. @CrossRoads : really not bad from just a picture. :-)
Logged

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not a problem.

This is what I put together: the original code has a timer piece, a led piece and a user application which calls the timer piece which in turn calls the led piece to work.

Code:
//demo code to run ledx8 display in a timer isr
//for common anode 7segment displays. 8 digits

//pin configuration
//define segment pins
#define SEG_PORT  PORTD  //connection: p0 -> a, p1 -> b, ..., p6 -> g, p7 -> dp
#define SEG_DDR   DDRD
#define SEGs      0xff //all pins used
//output a value to the segment, active low
#define SEG_OUT(val)  SEG_PORT = (val)  //output a value on segport, common anode
//#define SEG_OUT(val)  SEG_PORT =~(val)  //output a value on segport, common cathode

//define digits
#define DIG0      A0  //most significant digit in the display
#define DIG1      A1
#define DIG2      A2
#define DIG3      A3
#define DIG4      A4
#define DIG5      A5
#define DIG6      12
#define DIG7      13  //least significant digit in the display

//macros to turn on / off a digit. active high (common anode)
//may need to adjust for your applications
#define DIG_ON(dig)  digitalWrite(dig, HIGH)
#define DIG_OFF(dig) digitalWrite(dig, LOW)

//timing constants - max of 64k ticks
#define TMR_1s    (F_CPU)  // 1 second
#define TMR_1ms   (TMR_1s / 1000) //1ms
#define TMR_2ms   (TMR_1ms * 2)    //2ms
#define TMR_3ms   (TMR_1ms * 3)    //2ms
#define TMR_4ms   (TMR_1ms * 4)    //2ms
#define TMR_5ms   (TMR_1ms * 5)   //5ms
#define TMR_10ms  (TMR_1ms * 10)  //10ms

//gloval variables
//display font for common anode display - active low
unsigned char const led8_segs[]= {
//common anode segment table for 7-segment display
//7seg connection:
//0->A: ~0x01
//1->B: ~0x02
//2->C: ~0x04
//3->D: ~0x08
//4->E: ~0x10
//5->F: ~0x20
//6->G: ~0x40
//7->DP:~0x80
0xC0, //'0'
0xF9, //'1'
0xA4, //'2'
0xB0, //'3'
0x99, //'4'
0x92, //'5'
0x82, //'6'
0xF8, //'7'
0x80, //'8'
0x98, //'9'
0x80 | 0x08, //'A'
0x80 | 0x01 | 0x02, //'b'
0x80 | 0x02 | 0x04 | 0x40, //'C'
0x80 | 0x01 | 0x20, //'d'
0x80 | 0x02 | 0x04, //'E'
0x80 | 0x02 | 0x04 | 0x08 //'F'
};

unsigned char lRAM[8]; //display buffer. active high

//timer isr
ISR(TIMER1_COMPA_vect) {
  led8_display();    //update the display
  //digitalWrite(DIG0, !digitalRead(DIG0));  //flip dig0 for debugging purposes
}

//initialize timer
void tmr1_init(unsigned short period) {
TCCR1B = TCCR1B & (~0x07); //turn off tmr1
TCCR1A = (0<<COM1A1) | (0<<COM1A0) | //output compare a pins normal operation
(0<<COM1B1) | (0<<COM1B0) | //output compare b pins normal operation
//(0<<COM1C1) | (0<<COM1C0) | //output compare c pins normal operation
(0<<WGM11) | (0<<WGM10) //wgm13..0 = 0b0100 -> ctc, top at ocr1a
;
TCCR1B = (0<<ICNC1) | //nput capture noise canceller disabled
(0<<ICES1) | //input capture edge selection on falling edge
(0<<WGM13) | (1<<WGM12) | //wgm13..0 = 0b0100 -> ctc, top at ocr1a
(0x01) //prescaler = 1:1
;
TCCR1C = (0<<FOC1A) | //forced output on ch a disabled
(0<<FOC1B) //| //forced output on ch b disabled
//(0<<FOC1C) //forced output on ch c disabled
;
OCR1A = period;
TCNT1 = 0; //reset the timer / counter
TIMSK1 = (0<<ICIE1) | //input capture isr: disabled
//(0<<OCIE1C) | //output compare isr for ch c: disabled
(0<<OCIE1B) | //output compare isr for ch b: disabled
(1<<OCIE1A) | //output compare isr for ch a: disabled
(0<<TOIE1) //tmr overflow interrupt: enabled
;
 
}

//initialize the display
void led8_init(void) {
  //initialize the segments
  SEG_OUT(0x00);  //clear the segment
  SEG_DDR |= SEGs;  //segments as output
 
  //initialize the digits
  DIG_OFF(DIG0); pinMode(DIG0, OUTPUT);
  DIG_OFF(DIG1); pinMode(DIG1, OUTPUT);
  DIG_OFF(DIG2); pinMode(DIG2, OUTPUT);
  DIG_OFF(DIG3); pinMode(DIG3, OUTPUT);
  DIG_OFF(DIG4); pinMode(DIG4, OUTPUT);
  DIG_OFF(DIG5); pinMode(DIG5, OUTPUT);
  DIG_OFF(DIG6); pinMode(DIG6, OUTPUT);
  DIG_OFF(DIG7); pinMode(DIG7, OUTPUT);
}

//update the display
void led8_display(void) {
  static unsigned char dig=0; //current digit to be turned on
  //optional: blanking
  //turn on respective digits
  switch (dig) {
    case 0: DIG_OFF(DIG7); DIG_ON(DIG0); dig = 1; break;
    case 1: DIG_OFF(DIG0); DIG_ON(DIG1); dig = 2; break;
    case 2: DIG_OFF(DIG1); DIG_ON(DIG2); dig = 3; break;
    case 3: DIG_OFF(DIG2); DIG_ON(DIG3); dig = 4; break;
    case 4: DIG_OFF(DIG3); DIG_ON(DIG4); dig = 5; break;
    case 5: DIG_OFF(DIG4); DIG_ON(DIG5); dig = 6; break;
    case 6: DIG_OFF(DIG5); DIG_ON(DIG6); dig = 7; break;
    case 7: DIG_OFF(DIG6); DIG_ON(DIG7); dig = 0; break;
    default: dig = 0; //dig reset to 0
  }
  SEG_OUT(lRAM[dig]); //output the segment data, for common anode
}

//convert a number to segment information
void ul2segs(unsigned char *str, unsigned long ul, unsigned char length) {
  while (length) {
    str[--length]=led8_segs[ul % 10]; ul /= 10;    //perform the conversion -> leading 0s
  };
}

void setup(void) {
  led8_init();  //reset the led module
  tmr1_init(TMR_1ms);  //set up tmr1 to fire periodically
  sei();  //enable interrupt
}


//user code
void loop(void) {
  static unsigned short i=0; //index to be displayed
  ul2segs(lRAM, i++, 8); //convert i to 8-digit segment information
  delay(1000); //increment i periodically
 
}

As configured, it drives a 8-digit 7-segment common anode display. The digits are updated once every 1ms (user configurable). All user needs to do is to fill lRAM with the data and it will be updated on the led display. You can generate a library (two actually, one for the timer and one for the display) from this to make your life easier.

You can easily change it to suit your own display types. You will notice that I used a very long delay() in the loop() to show how it is unaffected.

In case you want to know, led8_display() can also be called in the loop to update the display - if you don't want to enable interrupts.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

After your post I begun reading about Interrupts, Timer, ISR and some other of this stuff...

I'm quite ready to begin my first test but, it's incledibile, my worst nightmare now is how to installa the AVR-libc library... seems something I have to compile on my own and, anyway, the documentation isnt very friendly (to my knowledge).

Any link to tutorials about this?

Again thanks.. (and in the meanwhile go on googleing)

A.-
Logged

United Kingdom
Offline Offline
Tesla Member
***
Karma: 224
Posts: 6593
Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

An easy way to set up a regular timer interrupt is to use the MsTimer2 library.
Logged

Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

No tutorial, no new lib needed: your arduino comes with a full installation of gcc-avr so the code I gave earlier will compile.

The best tutorial you can have is the device datasheet.
Logged

Pages: [1]   Go Up
Jump to: