LDR with 7 seg display and PWM output

CrossRoads: Did you look at the code I posted in #32?

I did read it, however I assumed that each register "linked" but needed at least 3 to 4 wires each. As for the code, I'm not too hot at the moment reading code. I loosely understand what you've written in principle, however I have to actually write this up and apply it in context to fully understand it. I'll order the shift registers, mock up 15 small led displays with it, then write the code to learn how to do it.

Below for instance is an example of the code I've written for a MM:SS timer. You'll look at it and think it's quite long winded. But self taught, so far it's the best I can do.

/* COMMON ANODE TIMER (with start, pause and reset):
   This Arduino code drives 4 separate 7 segment common ANODE LED displays
   Via a pushbutton switch, it starts a timer display from 00:00
   (mm:ss) to 59:59.  The button also pauses the timer.
   Holding the button in for greater than 2 seconds resets
   There is a built-in debounce to limit bouncing of pulses via the pushbutton.
   Includes an LDR to control the intensity of the digits
   Create by Chris in Feb 2015
*/

//--------------------------------------------------------------------------------------------

int A = 1;                   // Set to 0 (LOW) for common cathode.  Set to 1 for common anode digits
int B = 0;                   // Set to 1 (HIGH) for common cathode.  Set to 0 for common anode digits
int ldrIn = 14;              // Analog input pin A0.  Attach to first leg of LDR and 10K to GND
int aValue = 0;               // A variable used in controlling the light intensity value
int dValue = 0;               // A variable used in controlling the light intensity value

int buttonChange = 15;       // Analog in pin (A1) used to pause, restart and reset timer
                             // Other end of led to GND via a 10K resistor
int state = LOW;             // The current state of the output pin
int reading;                 // The current reading of the input pin
int previous = HIGH;         // The previous reading from the input pin
int check = 0;               // Used to pause the clock when the button is preassed - whilst reset
int delayMp = 2;             // Used to delay the muliplexing
int sec_ones = 0;            // Used to indicate what number the digit is set to
int sec_tens = 0;            // Used to increment the tens unit
int min_ones = 0;            // Used to increment the min_ones units
int min_tens = 0;            // Used to increment the min_tens units
long time1 = 0;              // Used in delaying for debouncing of pushbutton
long time2 = 0;              // Used in delaying the increment clock time
long secondMicro = 996000;   // One second increment clock time
long debounce = 500;         // Debounce time - longer than usual so it works for me
unsigned long currentMillis = 0;  //
unsigned long previousMillis = 0; //
int stepMultiplex = 1;       // Variable used to step through each segment
int reset = 2000;            // Duration required for button press to reset time
int firstTime = 1;           // Used in recording button press duration
unsigned long startTime = 0; // Used in recording button press duration
unsigned long pressTime = 0; // Used in recording button press duration


// the following array is used to define each led common
byte commons [4] = {6,9,10,11};   // pins to each digit common (these are PWM outputs)

// the following array is used to define each led segment for number 0 to 9
byte sevenSegmentPin[7] = {2,3,4,5,7,8,12};
byte sevenSegment[10][7] = {
  {B,B,B,B,B,B,A},    // this is 0
  {A,B,B,A,A,A,A},    // this is 1
  {B,B,A,B,B,A,B},    // this is 2
  {B,B,B,B,A,A,B},    // this is 3
  {A,B,B,A,A,B,B},    // this is 4
  {B,A,B,B,A,B,B},    // this is 5
  {B,A,B,B,B,B,B},    // this is 6
  {B,B,B,A,A,A,A},    // this is 7
  {B,B,B,B,B,B,B},    // this is 8
  {B,B,B,A,A,B,B},    // this is 9
};  


void setup()  //--------------------------------------------------
{
  Serial.begin(9600);
  for (byte i=0; i<7; i++)
  pinMode(sevenSegmentPin[i],OUTPUT); // this sets pins 2,3,4,5,6,8 and 12 as outputs

  for(byte i=0; i<4; i++)
  pinMode(commons[i], OUTPUT);         // this sets pins 6,9, 10 and 11 as outputs

  for (byte i=0; i<7; i++) {
    digitalWrite(sevenSegmentPin[i], sevenSegment[0][i]); // this sets pins 2,3,4,5,6 and 8 as 0
  }
}

// This is code for displaying the incremental digit for the "sec_ones"
void sevenSegWrite_1(byte sec_ones) {
  for (byte i=0; i<7; i++) {
    digitalWrite(sevenSegmentPin[i], sevenSegment[sec_ones][i]);
  }
}

// This is code for displaying the incremental digit for the "sec_tens"
void sevenSegWrite_2(byte sec_tens) {
  for (byte i=0; i<7; i++) {
    digitalWrite(sevenSegmentPin[i], sevenSegment[sec_tens][i]);
  }
}

// This is code for displaying the incremental digit for the "min_ones"
void sevenSegWrite_3(byte min_ones) {
  for (byte i=0; i<7; i++) {
    digitalWrite(sevenSegmentPin[i], sevenSegment[min_ones][i]);
  }
}

// This is code for displaying the incremental digit for the "min_tens"
void sevenSegWrite_4(byte min_tens) {
  for (byte i=0; i<7; i++) {
    digitalWrite(sevenSegmentPin[i], sevenSegment[min_tens][i]);
  }
}


void loop()  //--------------------------------------------------
{
  aValue = analogRead(ldrIn);              // Read the LDR analogue value on analog pin and
                                          // store the value between 0 and 1023
//  Serial.print("0l to 1023 value = ");
//  Serial.println(aValue);
  aValue = constrain (aValue, 20, 300);   // Constrain the value between 900 and 1010
  dValue = map (aValue, 20, 300, 0, 255); // The digital pin outputs values from 0 to 255
                                          // so convert the value received in the above line
  
  reading = digitalRead(buttonChange); // Check the state of the button
  currentMillis = millis();            // Set variable for multiplexing timing

  
// Used to toggle starting and pausing the clock...

if (reading == HIGH && previous == LOW && millis() - time1 > debounce) {
    if (state == HIGH) {
      state = LOW;
      time1 = millis ();
    }
    else {
      state = HIGH;
      time1 = millis();
    }
  }
  previous = reading;


// Used to check if the button is pressed long enough to reset the time

 if (reading == HIGH) {
   if (firstTime == 1) {
     startTime = millis();
     firstTime = 0;
   }
   pressTime = millis () - startTime;
 }
 else if (firstTime == 0) {
   firstTime = 1;
 }

 if (pressTime > 2000) {
    state = LOW;
    sec_ones=0;
    sec_tens=0;
    min_ones=0;
    min_tens=0;
    time1 = 0;
 }

//-------------------------------------------------------------------

  if(stepMultiplex == 1 && (currentMillis - previousMillis) >= delayMp) {
    digitalWrite(commons [0],B);  // Turn off the previous digit once time expires
    previousMillis=currentMillis;
    sevenSegWrite_1(sec_ones);
    analogWrite(commons [3],dValue);  // Turn on the sec_one digit
    stepMultiplex=2;
  }
  
  if(stepMultiplex == 2 && (currentMillis - previousMillis) >= delayMp) {
    digitalWrite(commons [3],B);  // Turn off the previous digit once time expires
    previousMillis=currentMillis;
    sevenSegWrite_2(sec_tens);
    analogWrite(commons [2],dValue);  // Turn on the sec_tens digit
    stepMultiplex=3;
  }
   
  if(stepMultiplex == 3 && (currentMillis - previousMillis) >= delayMp) {
    digitalWrite(commons [2],B);  // Turn off the previous digit once time expires
    previousMillis=currentMillis;
    sevenSegWrite_3(min_ones);
    analogWrite(commons [1],dValue);  // Turn on the min_one digit
    stepMultiplex=4;
  }

  if(stepMultiplex == 4 && (currentMillis - previousMillis) >= delayMp) {
    digitalWrite(commons [1],B);  // Turn off the previous digit once time expires
    previousMillis=currentMillis;
    sevenSegWrite_4(min_tens);
    analogWrite(commons [0],dValue);  // Turn on the min_tens digit
    stepMultiplex=1;
  }

//  The next few lines are used to advance the clock
  
  if (micros() - time2 > secondMicro && state == HIGH) {
    check=1;                            //this is used to pause the clock while the button is pressed
    if (check == 1 & reading == LOW) {
      sec_ones++;
      check=0;
    }
    
    if(sec_ones >9) {
      sec_ones=0;
      sec_tens++;
    }
    
    if(sec_tens>5) {
      sec_tens=0;
      min_ones++;
    }
    
    if(min_ones>9) {
      min_ones=0;
      min_tens++;
    }
    
    if(min_tens>5) {
      sec_ones=0;
      sec_tens=0;
      min_ones=0;
      min_tens=0;
    }
    time2 = micros();
  }
}

cjcj: I also did buy the DS3231 AT24C32 clock... I did however write code in a sketch to run my clock - and I was so proud of doing it. Is it better I use this module? Isn't that sort of cheating and relying on pre made components!

Why get a dog and bark yourself? The RTC module has several important advantages over using the Arduino as a clock. It will be much more accurate over long term, Arduino will probably loose/gain several mintues per day, vs several minutes per year with ds3231. RTC has battery back-up, so doesn't need re-setting every time Arduino is powered up/reset.

cjcj: I'll order the shift registers, mock up 15 small led displays with it, then write the code to learn how to do it.

Make sure to buy common-anode individual/single-digit 7-seg displays for your mock-up. You won't be able to use multi-digit displays without multiplexing them, and that wouldn't be an accurate mock-up of your final curcuit.

cjcj: Below for instance is an example of the code I've written for a MM:SS timer. You'll look at it and think it's quite long winded. But self taught, so far it's the best I can do.

Its good that you are practising your coding skills, but little of that code will be suitable for your project. You won't be multiplexing, you will be using shift registers and an RTC connected to the i2c bus. For now, better to spend your time getting the code for that RTC module working. Just send the output to serial monitor for now.

You are right. I already noticed I had to fiddle with microseconds in order to get the time accurate'sh. At least I learnt something with my code. As for the battery backup - yes, I didn't think of that.

I've already got small 7 segment common anode digits (10 at this stage, so I'll order another 1/2 dozen).

I do realize the multiplexing is out the window now. Again - good practice and I'm learning heaps.

CrossRoads: $2.30 per part - you guys down under get hosed on prices. Same for me is $1.74

Bob, could you check this LINK for shift registers on ebay. Do you think I should trust them?

Up to you. I don't trust anything on e-bay. I only by electronics from actual distributors. If this is just for personal use, that's different. I deliver a lot of what I buy, so I buy from known good suppliers. I also can't live with 3-4 week delivery time.

As for the code: have an array of elements that you will shift out.

dataArray[] = {
leftScoreTens,
leftScoreOnes,
rightScoreTens,
rightScoreOnes,
minutesTens,
minutesOnes,
secondsTens,
secondsOnes,
tenths,
//etc
};

Then send the data to the shift registers

digitalWrite (ssPin, LOW); // connects to RCLK
for (x=0; x<15; x=x+1){
SPI.transfer (fontArray[dataArray[x]]); // look up font mapping and send it out for data at location x in dataArray
}
digitalWrite (ssPin, HIGH); // connects to RCLK, outputs update on this rising edge.

CrossRoads: Up to you. I don't trust anything on e-bay....If this is just for personal use, that's different... I buy from known good suppliers...I also can't live with 3-4 week delivery time.

The 3 to 4 weeks is a pain, but in my it will take me a while to do this project. In my previous large project I did use ebay components alot of the time, except for anything high powered like the TPIC6B595s. Yes, this is not for "personal" use, so I might just order 15 of from a local suppler (rs components) and some "spares only" from ebay. This way I can start breadboarding earlier.

Thanks for all the snipits of code. They will come in handy when I get my PICs and start coding.

PaulRB: For now, better to spend your time getting the code for that RTC module working. Just send the output to serial monitor for now.

I did try my RTC, the only problem was that it was labelled on the ebay website as "DS3231", however I was sent a "DS1307" (no temperature on it). The $2 lost on this module is not the problem - only the 3-4 week waiting again! I connected it and tried some code anyway - time works well (but I've read the earlier DS1307 looses too much time as it is heat affected). New module on order.

Time for me to read some posts on shift registers and do some more practice...

cjcj: it was labelled on the ebay website as "DS3231", however I was sent a "DS1307"

On eBay? I hope you opened a dispute!

PaulRB: On eBay? I hope you opened a dispute!

I did write back to the seller saying "what tha". Interested to see what he does. If I have to return the unit, it'll probably cost me between $5 to $10. Some seller are just dishonest!

I expect they will send you a replacement, rather than risk a dispute case or poor feedback. Question is do they understand difference between ds1307 and ds3231, if they are one of those bazar-type vendors that sell false nails and clothes that no self respecting woman would be seen wearing in public except on a hen night!

Yes, your right. Not sure if they understand the difference either. I just had a reply from "Alice" and I had no idea what her reply ways so I wrote back in simpler english - "You send me wrong part. Please send me right part = DS3231 NOT". It makes me laugh. But at the same time I ordered another unit for about $2 from someone else - "Plan B".

You mean alice1101983? They run the TxHang shop. I was recommended them by another forum member and have used them a couple of times without a problem.

Now sorry if this question sounds a bit naive, but I'm trying to get my head how a TPIC6B595N shift register works and then daisy chaining 15 of them. I have setup 2 x 74HC595 with an exercise noted in a book called "Beginning Arduino" to try and understand registers. Is this what happens:

  • The Arduino generates binary code - 8 bits / 1 byte (i.e. 00010000) to depict a 7 segment digit number
  • This info is sent in serial (via a single line) to the shift register - pin 3 (SER IN)?
  • Each bit is sent/received 1 at a time and shoves the next spot in the register until all 8 are filled up (received)
  • To snapshot this, via the Arduino, "latch" is changed from Low to High - this is pin 12 (RCL) or the register
  • This flip causes the bits to be copied to each of register output pins (drain0 to drain7)
  • This then repeats replacing the bits in the shift register

Now, to cascade, is this correct? - All the 15 drain0's are connected together, and all 15 drain1's, are connected together etc, etc - All 15 latch pins are connected together - pin 12? - All 15 clock pins are connected together - pin 13? - To "shunt?" the 8 bits down from the first register to the next and next, pin 18 (SER OUT) is connected to pin 3 (SER IN) of the next register, and so on - Common anodes (in my case) are connected directly to 24V - The arduino PWM signal is connected to all the output enable pins (G) - pin 9 of each register - The arduino sends out 15 bytes at a time which fill each of the 15 shift registers

Is this the basic idea? So does this mean that 15 bytes of info are sent by the arduino ever microsecond or so, hence any change in 8-bit is displayed immediately in the 7 segment displays so 100 duty cycle? And does it also mean that the dimming all the displays is controlled by a PWM signal from the Arduino to pin 9 of every shift register which essentially essentially creates a sort of duty cycle/pulse width?

Maybe a question for Bob - other than the 15 shift registers, 20 pin IC sockets and 0.1uF caps for each register, is there any other basic components that I need to get started for this test?

cjcj:

  • The Arduino generates binary code - 8 bits / 1 byte (i.e. 00010000) to depict a 7 segment digit number
  • This info is sent in serial (via a single line) to the shift register - pin 3 (SER IN)?
  • Each bit is sent/received 1 at a time and shoves the next spot in the register until all 8 are filled up (received)
  • To snapshot this, via the Arduino, “latch” is changed from Low to High - this is pin 12 (RCL) or the register
  • This flip causes the bits to be copied to each of register output pins (drain0 to drain7)
  • This then repeats replacing the bits in the shift register

Now, to cascade, is this correct?

  • All the 15 drain0’s are connected together, and all 15 drain1’s, are connected together etc, etc
  • All 15 latch pins are connected together - pin 12?
  • All 15 clock pins are connected together - pin 13?
  • To “shunt?” the 8 bits down from the first register to the next and next, pin 18 (SER OUT) is connected to pin 3 (SER IN) of the next register, and so on
  • Common anodes (in my case) are connected directly to 24V
  • The arduino PWM signal is connected to all the output enable pins (G) - pin 9 of each register
  • The arduino sends out 15 bytes at a time which fill each of the 15 shift registers

That all looks correct.

cjcj:
So does this mean that 15 bytes of info are sent by the arduino ever microsecond or so, hence any change in 8-bit is displayed immediately in the 7 segment displays so 100 duty cycle?

No, your sketch only sends the data when you want to change something. So for example if you were displaying the time as hh:mm you would only need to update once per minute.

cjcj:
And does it also mean that the dimming all the displays is controlled by a PWM signal from the Arduino to pin 9 of every shift register which essentially essentially creates a sort of duty cycle/pulse width?

Yes, your sketch can set the level with analogWrite(), again, only when it needs to change.

cjcj:
Maybe a question for Bob - other than the 15 shift registers, 20 pin IC sockets and 0.1uF caps for each register, is there any other basic components that I need to get started for this test?

For your small 7-seg displays, probably be ok, maybe add a 10uF for each display. For your large displays, some much larger caps, maybe 1000uF per digit.

All devices receive clock and latch in parallel. 1st device gets Serial data from processor, it's Serial Out goes to Serial In on next chip. Example: http://www.crossroadsfencing.com/BobuinoRev17/ |500x252

All the 15 drain0's are connected together, and all 15 drain1's, are connected together etc, etc

Oh, that's wrong. Each drain is connected to a separate segment cathode.

PaulRB: You mean alice1101983? They run the TxHang shop.

Yes. What a coincidence. It was exactly the same person / company.

PaulRB: No, your sketch only sends the data when you want to change something. So for example if you were displaying the time as hh:mm you would only need to update once per minute

Yes, of course. That makes sense.

PaulRB: For your small 7-seg displays, probably be ok, maybe add a 10uF for each display. For your large displays, some much larger caps, maybe 1000uF per digit.

Is that right? I "thought" that each IC needs a 0.1uF capacitor as close to the Vcc as possible and ground in order to stop any resilient "noise".

CrossRoads: All devices receive clock and latch in parallel. 1st device gets Serial data from processor, it's Serial Out goes to Serial In on next chip. Example...

Yes, now that's starting to make sense. Your link to the sketch now also is making sense. So am I now understanding this correctly. Your post #30 that shows a circuit board, is essentially exactly what I need (expect I need an extra 3 shift registers, plus having to connect my PWM signal?

I "thought" that each IC needs a 0.1uF capacitor as close to the Vcc as possible and ground in order to stop any resilient "noise".

Correct, you need those too. The larger caps are to smooth the sudden demand spikes when large currents are switched, such as your led segments. You might get away with minimal or no caps for your small prototype, depending how good your power supply is and how far away the chips are from it. But with your large displays and the long power lines you will probably have in the final build of the project, lots of large caps spread around would be a very good idea.

I suppose then these are to replace the 0.1uF. So do I put them next to each shift register (15 in total), and maybe 35V, 1000uF?

I mean you need (or might need) both. Definitely a 0.1uF decoupling cap for each chip (accross 5V & ground), plus (maybe) a larger cap to smooth the high-current switching (accross 24V & ground - check cap's voltage rating is adequate). With your small displays, maybe not needed at all. For the large displays, maybe 1000uF per display is overkill. I'm not sure how to estimate that, maybe Bob has some advice.

CrossRoads: All devices receive clock and latch in parallel. 1st device gets Serial data from processor, it's Serial Out goes to Serial In on next chip.

Bob, So am I now understanding this correctly. Your post #30 that shows a circuit board, is essentially exactly what I need (expect I need an extra 3 shift registers, plus having to connect my PWM signal? And yes, any ideas on the number and placement of caps as suggested above?