Hi everyone, I'm totally new to any kind of forum posting. If there's anything not up to regulation, please let me know! I'm trying to learn but it's not always the easiest.
After using an Arduino board for my engineering class, I wanted to tackle my own project. Namely, a countdown timer with six seven segment displays that shows the remaining months, days, and hours set by the user via push-buttons. The actual countdown would then be controlled by an RTC module (I read somewhere that the Arduino's internal timer is not accurate for extended time periods). I assumed this would be a relatively simple project but wow was I wrong. All of my work so far has been through online simulators like TinkerCAD and Wowki. I wanted to have some kind of baseline before buying components. I assume a project like this would not require a board bigger than an UNO correct? (Please let me know if this is wrong)
After testing it out with only two seven segment displays, I ran into a couple of issues. I very quickly realized I needed a SIPO shift register in order to limit the amount of pins used. I started off by using the very common 74HC595. I quickly realized from other forums that this IC has a max current of 35mA. From a quick Google browse, I discovered that each segment of the displays uses about 15mA at half of max capacity. So even if every one of the 6 displays had it's own shift register, the current drawn by the displays would be way past the max of the 35mA limit.
I looked into multiplexing in order to half the current drawn. For the project I could buy 3 pairs of 2 displays which are already multiplexed. However, this obviously still exceeds the max current per shift register. I looked into shift registers which can handle a higher current load (like the TPIC6B595) but if I'm reading the datasheet correctly, they can only sink current. This, however, was an issue for the multiplexed displays since the shift registers required both the ability to source and sink current.
TLDR; All in all, from my limited knowledge and testing, it seems like I can't multiplex and have the shift registers working properly. The goal is to have 3 independent multiplexed pairs of two 7 segment displays seeing as this halves my current usage. However, I can't seem to figure it out.
My two questions are this: 1.) what is the best way to go about using six of these displays? 2.) Will a project like this need an external power source?
Below are two test circuits I built to try and understand. These circuits simply allow the user to enter up to 60 seconds and then proceeds to count down after the start button is pressed.
1.) 2 separate non-multiplexed displays (draws too much current for the 74HC595 and could be multiplexed to reduce current I think)
const int COUNT_BUTTON_PIN = 13;
const int START_BUTTON_PIN = 12;
const int DS_pin = 4;
const int latch_pin = 3;
const int clock_pin = 2;
const long TIME_PRESSED_BUTTON = 500; // indicates the delay needed to increase count
long lastTimeChecked = 0;
int total_count = 0;
int first_disp = 0;
int second_disp = 0;
int dat_arr[10] = {B10000001, B11001111, B10010010, B10000110,
B11001100, B10100100, B10100000, B10001111,
B10000000, B10000100}; // binary for 0-9
void setup() {
pinMode(DS_pin, OUTPUT);
pinMode(latch_pin, OUTPUT);
pinMode(clock_pin, OUTPUT);
pinMode(COUNT_BUTTON_PIN, INPUT);
pinMode(START_BUTTON_PIN, INPUT);
}
void loop() {
count_increase();
if (digitalRead(START_BUTTON_PIN) == HIGH){
start_timer(total_count);
total_count = 0;
}
}
void start_timer(int seconds){
// separate input into first and second digit
first_disp = seconds/10;
second_disp = seconds%10;
// countdown timer loop
while (not((first_disp == 0) && (second_disp == 0))){
display_digits(first_disp, second_disp);
delay(1000);
if (second_disp == 0){
first_disp--;
second_disp = 9;
}
else{
second_disp--;
}
}
display_digits(first_disp, second_disp);
}
void display_digits(int first, int second){
// writes to displays
digitalWrite(latch_pin,LOW);
shiftOut(DS_pin, clock_pin, LSBFIRST, dat_arr[second]);
shiftOut(DS_pin, clock_pin, LSBFIRST, dat_arr[first]);
digitalWrite(latch_pin, HIGH);
}
void count_increase(){
// Handles increasing of count through push button
while (digitalRead(COUNT_BUTTON_PIN) == HIGH){
if (millis() - lastTimeChecked > TIME_PRESSED_BUTTON){
lastTimeChecked = millis();
if (total_count >= 60){
total_count = 0;
}
else{
total_count++;
}
first_disp = total_count/10;
second_disp = total_count%10;
display_digits(first_disp, second_disp);
}
}
lastTimeChecked = 0;
}
2.) 1 2 digit multiplexed display (still draws too much current for the 74HC595 but can't be swapped for a TPIC6B595 because it needs to both source and sink (right?). The library used, SevSegShift, also doesn't seem to allow multiple separate displays. Is this correct?)
#include "SevSegShift.h"
#define SHIFT_PIN_DS 8
#define SHIFT_PIN_STCP 7
#define SHIFT_PIN_SHCP 6
#define TIME_PRESSED_BUTTON 200
#define COUNT_BUTTON_PIN 13
#define START_BUTTON_PIN 12
long lastTimeChecked = 0;
long timer = 0;
int total_count = 0;
bool timer_finished = false;
SevSegShift sevseg(SHIFT_PIN_DS, SHIFT_PIN_SHCP, SHIFT_PIN_STCP); // Instantiate a seven segment controller object
void setup() {
byte numDigits = 2;
byte digitPins[] = {8+2, 8+5}; // of ShiftRegister(s) | 8+x (2nd Register)
byte segmentPins[] = {8+3, 8+7, 4, 6, 7, 8+4, 3, 5}; // of Shiftregister(s) | 8+x (2nd Register)
bool resistorsOnSegments = false; // 'false' means resistors are on digit pins
byte hardwareConfig = COMMON_ANODE; // See README.md for options
bool updateWithDelays = false; // Default 'false' is Recommended
bool leadingZeros = true; // Use 'true' if you'd like to keep the leading zeros
bool disableDecPoint = true; // Use 'true' if your decimal point doesn't exist or isn't connected
sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments,
updateWithDelays, leadingZeros, disableDecPoint);
sevseg.setBrightness(90);
}
void loop() {
count_increase();
if (digitalRead(START_BUTTON_PIN) == HIGH){
start_timer();
timer_finished = false;
}
sevseg.refreshDisplay();
}
void start_timer(){
// countdown timer loop
sevseg.setNumber(total_count, 0);
timer = millis();
while (not(timer_finished)){
if (millis() - timer >= 1000){
timer = millis();
if (total_count == 0){
timer_finished = true;
}
else{
total_count--;
sevseg.setNumber(total_count, 0);
}
}
sevseg.refreshDisplay();
}
}
void count_increase(){
while (digitalRead(COUNT_BUTTON_PIN) == HIGH){
if (millis() - lastTimeChecked >= TIME_PRESSED_BUTTON){
lastTimeChecked = millis();
if (total_count >= 60){
total_count = 0;
}
else{
total_count++;
}
}
sevseg.setNumber(total_count, 0);
sevseg.refreshDisplay();
}
lastTimeChecked = 0;
}
I realize buttons have bounce but I didn't feel the need to include this as it is a relatively simple fix from what I've seen.
All in all, I know it's a lot but I wanted to be sure to include everything that could possibly be needed. If there's anything missing, please let me know and I'll update it as soon as possible! If there's anything about the project, regardless of the two questions, that could use tweaking, I would love to hear it! I'm learning as I go.
Thank you so much for your time!