Go Down

Topic: 4 Digit 7 Segment fun (Read 2158 times) previous topic - next topic

mrbaggins

I'm new to this, so please bear with me. I also searched and found some stuff on the old forum, but can't get it working. (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1265669651/15)

I have the 4 digit display (common anode) from Sparkfun.

I am attempting to control it with as few pins as possible, so am running it via a Shift Register.

The set up is :
Each digit anode is connected to a digital output on the arduino
Each segment is connected to resisted (330ohm) ground via a transistor, which is controlled by the shift register, which is controlled by 3 further pins on the arduino.

I got one digit working fine (Just ran the digit as permanently on from the 5V rail).

So I tried then to make it count to 9999 instead of 9.

I tried to do this by setting the first digit on, sending data to the shiftregister to show the number, then turning the digit off again. Lather rinse and repeat for each digit.

This has shown me a few problems.

One: More than one digit causes unexpected results, (10 -99 is reversed, 100+ I can't even work out what's going on) but commenting it down to single digits shows each one working as expected. (tens digit shows correct values, one's digit shows correct values, but not at the same time)
Two: I'm getting real bad gaps of nothing between numbers/digits, depending on where I put a delay. Was hoping switching fast enough would stop this...

Any hints?

graynomad

Quote
Any hints?

Yep, post your code.

Failing that I'd say line 48 has a semi colon straight after the if() statement :)

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

tomm

There are loads of examples of code around the net for this type of thing. You sound like you've got the right constituent parts in your code, just a little muddled up. As the above poster says, if we could see your code we can point you in the right direction.

mrbaggins

Code: [Select]

//Pin Definitions

//For the shift register
int data = 2;
int clock = 3;
int latch = 4;

//Used for single LED manipulation
int ledState = 0;
const int ON = HIGH;
const int OFF = LOW;

//The respective anode pins for each digit, first being left, fourth being right
int first = 9;
int second = 10;
int third = 11;
int fourth = 12;

//The dec equivalents for 0 - 9 in 7 segments
int number[]={126,12,182,158,204,218,250,14,254,222};

//The current value I want to show
int numToDisplay = 0;

int thou = 0;
int hund = 0;
int tens = 0;
int ones = 0;
/*
* setup() - this function runs once when you turn your Arduino on
* We set the three control pins to outputs
*/
void setup()
{
  pinMode(data, OUTPUT);
  pinMode(clock, OUTPUT); 
  pinMode(latch, OUTPUT); 
  pinMode(first, OUTPUT);
  pinMode(second, OUTPUT);
  pinMode(third, OUTPUT);
  pinMode(fourth, OUTPUT);
}

void loop()                   
{
  /Abuse integer division to get the relevant digits.
  thou = numToDisplay / 1000;
  hund = (numToDisplay - thou * 1000) / 100;
  tens = (numToDisplay ) / 10;  //<< I started just working on 00 - 99 to test, hence this.
  ones = (numToDisplay % 10);
 
  if (numToDisplay == 99)     //Same here.
    numToDisplay = 0;
    //<<Snipped out code for 100-9999, as this code had the same issues that 10-99 does.

  if(numToDisplay > 9) {              //If two digits
      for (int i = 0; i < 500; i++) {   //Delay loop to force display to 'delay' with two digits. Also tried using delay(x) but had similar (or same) issues.
        digitalWrite(third, HIGH);
        updateLEDs(number[tens]);
        digitalWrite(third, LOW);   
   
   
        digitalWrite(fourth,HIGH);
        updateLEDs(number[ones]);
        digitalWrite(fourth, LOW);
      }
  }
  if(numToDisplay < 10) { 
   for (int i = 0; i < 500; i++) {
      digitalWrite(fourth,HIGH);
      updateLEDs(number[ones]);
      digitalWrite(fourth, LOW);
   }
  }
 
 
  numToDisplay++;
}

//following code stolen from shift register example with the Arduino I bought.
/*
* updateLEDs() - sends the LED states set in ledStates to the 74HC595
* sequence
*/
void updateLEDs(int value){
  digitalWrite(latch, LOW);     //Pulls the chips latch low
  shiftOut(data, clock, MSBFIRST, value); //Shifts out the 8 bits to the shift register
  digitalWrite(latch, HIGH);   //Pulls the latch high displaying the data
}
/*
* updateLEDsLong() - sends the LED states set in ledStates to the 74HC595
* sequence. Same as updateLEDs except the shifting out is done in software
* so you can see what is happening.
*/
void updateLEDsLong(int value){
  digitalWrite(latch, LOW);    //Pulls the chips latch low
  for(int i = 0; i < 8; i++){  //Will repeat 8 times (once for each bit)
  int bit = value & B10000000; //We use a "bitmask" to select only the eighth
                               //bit in our number (the one we are addressing this time through
  value = value << 1;          //we move our number up one bit value so next time bit 7 will be
                               //bit 8 and we will do our math on it
  if(bit == 128){digitalWrite(data, HIGH);} //if bit 8 is set then set our data pin high
  else{digitalWrite(data, LOW);}            //if bit 8 is unset then set the data pin low
  digitalWrite(clock, HIGH);                //the next three lines pulse the clock pin
  delay(1);
  digitalWrite(clock, LOW);
  }
  digitalWrite(latch, HIGH);  //pulls the latch high shifting our data into being displayed
}
//These are used in the bitwise math that we use to change individual LEDs
//For more details http://en.wikipedia.org/wiki/Bitwise_operation
int bits[] = {B00000001, B00000010, B00000100, B00001000, B00010000, B00100000, B01000000, B10000000};
int masks[] = {B11111110, B11111101, B11111011, B11110111, B11101111, B11011111, B10111111, B01111111};
/*
* changeLED(int led, int state) - changes an individual LED
* LEDs are 0 to 7 and state is either 0 - OFF or 1 - ON
*/
void changeLED(int led, int state){
   ledState = ledState & masks[led];  //clears ledState of the bit we are addressing
   if(state == ON){ledState = ledState | bits[led];} //if the bit is on we will add it to ledState
   updateLEDs(ledState);              //send the new LED state to the shift register
}

graynomad

Here's one of your update code pieces

Code: [Select]
       digitalWrite(third, HIGH);
        updateLEDs(number[tens]);
        digitalWrite(third, LOW);   


Let's add some comments to indicate what this is doing

Code: [Select]
digitalWrite(third, HIGH); // turn on digit and have it display what ever crap was in the SR from the last digit
updateLEDs(number[tens]); // spent some time shifting the new digit in
                           // the correct digit is now displayed
digitalWrite(third, LOW);   // turn off the digit


This will just pulse the digit very briefly with the wrong number, then even more briefly with the right number, then turn it off.

Secondly: An Arduino pin will have trouble driving 7 LEDs, with a CA display you should have some form of high-side driver. CC is a lot easier. This however will only affect the brightness (and possibly damage the Mega chip).

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

mrbaggins

I'd heard that about the current draw, so I've over resisted a bit (only a little)... I should really get a power supply set up though...

As for the code, I noticed a REALLY faint outline of the wrong digits at time, which explains what you're saying.

So it should be: (pseudocode)
updateLEDs()
Set digit high
delay (very short)
set digit low

Or should I move the delay out and do it like I have above, with a for loop going over the entire digit set?

graynomad

#6
Apr 12, 2011, 03:37 am Last Edit: Apr 12, 2011, 03:39 am by Graynomad Reason: 1
I think the first thing to do is separate the acquiring of the 4 digits from the printing of them. These are two totally different functions and it's normally best that they have no real connection except the data. Mixing all the code together in one long "if this else that" construct makes things very hard to read and debug.

So the code would be something like this

Code: [Select]
loop() {
   get_data();
   print_data();
}


I would normally do the print_data() as an ISR on a timer interrupt but I don't think that's very easy to do on Arduino and anyway it means dicking with timers.

So I would suggest this for starters.

Code: [Select]

//For the shift register
int data = 2;
int clock = 3;
int latch = 4;

byte digits [4];
unsigned long last_mills;
int digit_pins [] = {9, 10, 11, 12};

void setup () {
pinMode(data, OUTPUT);
pinMode(clock, OUTPUT); 
pinMode(latch, OUTPUT); 

for (int i = 0; i < 4; i++) {
pinMode (digit_pins[i], OUTPUT);
}
}

void loop() {

get_data();

if (last_mills != millis()) {
last_mills = millis();
print_data(); // on the average this will run every mS,
// may be too fast but that can be changed
}

}

void get_data() {
// do whatever to put the 4 bytes into the "digits" array
// for the moment we'll just load some dummy values
digits[0] = 12;
digits[1] = 182;
digits[2] = 158;
digits[3] = 204;
}

void print_data () {

static byte curr_digit = 0;

digitalWrite (digit_pins[curr_digit], LOW);  // turn off the last digit

curr_digit++; // point to next digit
curr_digit &= B00000011;  // force wrap around from 3 to 0

shiftOut(data, clock, MSBFIRST, digits[curr_digit]);
digitalWrite (digit_pins[curr_digit], HIGH); // turn on this digit

}


I can't test this at present but at least it compiles.

If you can get this working you can then plug in some real code for the get_data() function.

______
Rob

Rob Gray aka the GRAYnomad www.robgray.com

Go Up