//by Hui Lian
//2 & half Digits Seven-Segment LED Display Timer & ScoreBoard with Buttons
//Team A's score on the Left digit1, Team B's score on the Right digit2, up to 19,dots on top left hand side are 10's
//In Score Mode:Button1(A):Team A +/-1, Button2(B):Team B +/-1,Button3(C):Clear both when pressed longer than set time,BTN3DownTime
//Button4(D): combined with button1 & 2, pressed -1, not pressed +1
//In Timer Mode(Starting Mode):Button1:Time +1, Button2:Time -1,Button3:Set default(preset) time,when
//pressed longer than set time,BTN3DownTime
//Button4:toggle between Score Mode & Timer Mode, when pressed longer than BTN4DownTime
//When pretime is elapsed,remaingTime 0, system gets into timerMode and alarm comes on
//Pressing any key to stop alarm, remaining Time stays at 0
// Common Anode digit1 pin 3,8
// Common Anode digit2 pin 3,8
//Normal 7-segment Displays
// G F C1 A B G F C2 A B
// | | | | | | | | | | -> pins and segments they control
// ----------- -----------
// | A | | A |
// F| |B F| |B
// |----G----| |----G----|
// E| |C E| |C
// | D | | D |
// -----------#DP -----------#DP
// | | | | | | | | | | -> pins and segments they control
// E D C1 C DP E D C2 C DP
//Real 7-segment Displays Orientation of this project
// DP C C1 D E DP C C2 D E
// | | | | | | | | | | -> pins and segments they control
//#DP----------- #DP-----------
// | A | | A | Both Digits have been turned upside down to
// F| |B F| |B make dots as 'tens', to display the same results
// |----G----| |----G----| connect output wires in the following way:(Nano Pin to 7-Display pin):
// E| |C E| |C A to D, B to E, C to F, G to G & #DP to #DP
// | D | | D |
// ----------- -----------
// | | | | | | | | | | -> pins and segments they control
// B A C1 F G B A C2 F G
// Segments that make each number when lit:
// 0 => -FEDCBA
// 1 => ----BC-
// 2 => G-ED-BA
// 3 => G--DCBA
// 4 => GF--CB-
// 5 => GF-DC-A
// 6 => GFEDC-A
// 7 => ----CBA
// 8 => GFEDCBA
// 9 => GF-DCBA
// Arduino digital pins used to light up
// corresponding segments on the LED display
#define A 2
#define B 3
#define C 4
#define D 5
#define E 6
#define F 7
#define G 8
#define DP 9
//Pushbuttons connected to pins A0,A1,A2 & A3
//In Score Mode:
//BTN1:Left display score1 +/-1,BTN2:Right display score2 +/-1
//BTN3:Clear both displays
//BTN4:when being held down to decrement by 1 with button1 or 2,can not press too long,which will toggle Modes
//In timer Mode:
//BTN1 time+1,BTN2 time-1,BTN3:preset time to set to default
//Long press BTN4 to toggle between Score Mode & timer Mode
#define BTN1 A0 //button1 or A on Remote Controller
#define BTN2 A1 //button2 or B on Remote Controller
#define BTN3 A2 //button3 or C on Remote Controller
#define BTN4 A3 //button4 or D on Remote Controller
// Pins driving common anodes
#define CA1 10
#define CA2 11
//Pin for Buzzer
#define BUZ1 12
//on board LED to indicate Mode, On:Timer Mode; Off:Score Mode
#define LEDPin 13
// Pins for A B C D E F G,DP in sequence
const int segs[8] = { A, B, C, D, E, F, G,DP};
//Segments that make each number or letter: 0,1,2,3,4,5,6,7,8,9
//A,b,c,d,E,F,G,H,i,j,K,L,M,n,o,P,q,r,S,t,u,V,W,X,Y,Z,Space" "
//in the format of [0b DP G F E D C B A] for each number, "0" segment on,"1" segment off
const byte numbers[37] = {0b11000000, 0b11111001, 0b10100100, 0b10110000, 0b10011001, 0b10010010,
0b10000010, 0b11111000, 0b10000000, 0b10010000,//0 to 9
0b10001000, 0b10000011, 0b10100111, 0b10100001, 0b10000110, 0b10001110, 0b11000010,//A-g
0b10001011, 0b11111011, 0b11110011, 0b10000101, 0b11100111, 0b10101010, 0b10101011,//h-n
0b10100011, 0b10001100, 0b10011000, 0b10101111, 0b10010010, 0b10000111, 0b11100011,//o-u
0b10010101, 0b11100010, 0b10110110, 0b10010001, 0b10100100, 0b11111111};//w-z, space " "
const int defTime=60; //default or preset time: 60 minutes
const int long MsecInMin=60000; //milliseconds in a minute
const int delAtime1=1200; //delay Alarm time1
const int delAtime2=2400; //delay Alarm time2
const int cycAcount1=40; //cycle1 of alarm,40
const int cycAcount2=20; //cycle2 of alarm,20
const int delDigitOn=5; //delay digit On
const int delABouncing=20; //Anti-Bouncing delay
int score1=0;
int score2=0;
int digit1 = 0; //digit1 & 2 are display digits, either socres or remaining time
int digit1DPadj=0; //to control DP on digit1
int digit2 = 0;
int digit2DPadj=0; //to control DP on digit2
int remainingTime=defTime;
int LastBTN1State=0; //to detect rising edge,compare BTNxState with LastBTNxState,x:1,2,3 or 4
int LastBTN2State=0;
int LastBTN3State=0;
int LastBTN4State=0;
int BTN1State=0; //current buttonx state, x:1,2,3 or 4
int BTN2State=0;
int BTN3State=0;
int BTN4State=0;
int loopCount=0; //to make remaingTime flash,using loopCount,0-9:On;10-19:Off
unsigned long BTN3StartTime =0; //timer starting time for button3
unsigned long BTN4StartTime =0; //timer starting time for button4
const int BTN3DownTime=1000; //to prevent accidently clear scores or preset time,the button has to be long pressed
const int BTN4DownTime=2000; //to prevent accidently changing modes (differ from short press in score Mode to -1),long pressed
boolean timerMode=true; //starting with timer Mode to set/adjust time
boolean alarmOn=false; //only becomes on after remainingTime decremented to 0 by timer
boolean modeChanged=false; //becomes true after mode swtiching to stop mode switching muliple times with one press
void setup() {
pinMode(A, OUTPUT);
pinMode(B, OUTPUT);
pinMode(C, OUTPUT);
pinMode(D, OUTPUT);
pinMode(E, OUTPUT);
pinMode(F, OUTPUT);
pinMode(G, OUTPUT);
pinMode(DP, OUTPUT);
pinMode(BTN1, INPUT);
pinMode(BTN2, INPUT);
pinMode(BTN3, INPUT);
pinMode(BTN4, INPUT);
pinMode(CA1, OUTPUT);
pinMode(CA2, OUTPUT);
pinMode(BUZ1, OUTPUT);
pinMode(LEDPin, OUTPUT);
//Displays "A" for team A on the Left digit (digit1)
//"B" for team B on the right digit (digit2)
//twice to make sure teams,players...etc informed
for (int i = 0; i <= 35; i++) {//to display a full set of chars,set i=0
lightDigit2(numbers[i]); //numbers[0] for "0",numbers[35] for "Z",numbers[36] for space " "
delay(300);
lightDigit2(numbers[36]); //display space " " or blank
delay(100);
}
//display A & b, twice for each 7-segment display
lightDigit1(numbers[10]); //display "A"
delay(1000);
lightDigit2(numbers[11]);//display "b"
delay(1000);
lightDigit1(numbers[10]);//display "A"
delay(1000);
lightDigit2(numbers[11]);//display "b"
delay(1000);
//turn on On-board LED,if in timerMode
if (timerMode) {
digitalWrite(LEDPin, HIGH);
}
}
void loop() {
loopCount++; //loop count, used to control flashing time in timer Mode
loopCount %=20; //maximum is 19
//reamingTime count down every minute, and activate alarmOn if reaching 0
static unsigned long timeStart=millis();
if ((millis()-timeStart>=MsecInMin) && (remainingTime>0)) {
remainingTime=remainingTime-1;
//Only remainTime becomes 0 here, alarm will be swtiched on
if (remainingTime==0) {
alarmOn=true;
}
timeStart+=MsecInMin;
}
//switch to timerMode before sounding alarm to show remainin time is 0
if (alarmOn) {
timerMode=true;
//cycle Alarm Counts were 100 & 50
//switching on buzzer in 2 different frequencies
for (int i=0;i<=cycAcount1;i++) {
digitalWrite(BUZ1, HIGH);
delayMicroseconds(delAtime1);
digitalWrite(BUZ1, LOW);
delayMicroseconds(delAtime1);
}
for (int i=0;i<=cycAcount2;i++) {
digitalWrite(BUZ1, HIGH);
delayMicroseconds(delAtime2);
digitalWrite(BUZ1, LOW);
delayMicroseconds(delAtime2);
}
}
// check button4, as button4 will decide to +1 or -1 the score in score Mode
BTN4State = digitalRead(BTN4);
// check button1 (Team A), if there is a rising edge,score1:+1 if BTN4 not pressed,-1 if pressed
//in timer Mode:time +1, if time<limit(199) else make time to 0
BTN1State = digitalRead(BTN1);
if (BTN1State != LastBTN1State && BTN1State==HIGH) {//BTN1 rising edge
if (alarmOn) {alarmOn=false;} //switch off alarm
else {//only when alarm is off, the BTN1 rising will be able to increase remainging Time
if (timerMode) {//in timer Mode,increase remaining time
remainingTime++;
remainingTime %=200;
}
else {//in Score Mode,adjust score1
if (BTN4State==LOW) {//BTN4 not pressed,score1+1,but less than 20
score1++;
score1 %= 20;
delay(1);
}
else {//BTN4 pressed, score1-1,but no less than 0
if (score1>0){
score1=score1-1;
delay(1);
}
}
}
}
}
LastBTN1State=BTN1State; //for rising edge detecting purpose
// check button2 (Team B), if there is a rising edge,change score2:+1 if BTN4 not pressed,-1 if BTN4 pressed
//in timer Mode: time -1 if time>0
BTN2State = digitalRead(BTN2);
if (BTN2State != LastBTN2State && BTN2State==HIGH) {//BTN2 rising edge
alarmOn=false; //switch off alarm
if (timerMode) {
if (remainingTime>0) {
remainingTime=remainingTime-1;
}
}
else {
if (BTN4State==LOW) {
score2++;
score2 %= 20;
delay(1);
}
else {
if (score2>0){
score2=score2-1;
delay(1);
}
}
}
}
LastBTN2State=BTN2State; //for rising edge detecting purpose
// check button3
//if there is a rising edge: set BTN3 start time, falling edge BTN3 end time
//if the duration > the set time, BTN3DownTime, Clear both scores in score Mode
//if the duration > the set time, BTN3DownTime, make time to preset value in timer Mode
BTN3State = digitalRead(BTN3);
if (BTN3State != LastBTN3State) {
if (BTN3State==HIGH) {//BTN3 rising edge
alarmOn=false; //switch off alarm
BTN3StartTime = millis();
// BTN3EndTime = BTN3StartTime;
}
else {
// BTN3EndTime = millis();
}
}
if (((millis()-BTN3StartTime)>BTN3DownTime) && BTN3State==HIGH) {
if (timerMode) {//time is up,and BTN3 still on
remainingTime=defTime; //timer Mode,set to preset or default time
}
else {//Score Mode,clear both scores
score1=0;
score2=0;
}
delay(1);
}
LastBTN3State=BTN3State; //for rising edge detecting purpose
// check button4
//if there is a rising edge: set BTN4 start time, falling edge BTN4 end time
//if the duration is greater than the set time, BTN4DownTime, toggle between ScoreMode & timerMode
BTN4State = digitalRead(BTN4);
if (BTN4State != LastBTN4State) {
if (BTN4State==HIGH) {//BTN4 rising edge
alarmOn=false; //alarm might be on, switch off it
BTN4StartTime = millis(); //start BTN4-pressed time
}
else {}
}
//condition right below here could only happen
//after a rising edge detected
if ((millis()-BTN4StartTime)>BTN4DownTime) {
if (BTN4State==HIGH) {//BTN4 Pressed and stays on
if (modeChanged==false) {//only 1st time BTN4 Pressed over the set time, change mode
if (timerMode) {timerMode=false; //switch to Score Mode
digitalWrite(LEDPin, LOW); //turn LED on board off
}
else {timerMode=true; //switch to timer Mode
digitalWrite(LEDPin, HIGH); //light LED on board on
}
modeChanged=true; //switched modes,before BTN4 released,mode switching prohibited
}
else {
}
delay(1);
}
else {modeChanged=false;
}
}
LastBTN4State=BTN4State; //for rising edge detecting purpose
delay(delABouncing); //Anti-Bouncing delay for anyone of the 4 buttons
// display remaining Time(timer Mode) or Scores (Score Mode)
if (timerMode) {digit1=remainingTime/10;} //in timer Mode,digit1 displays first 1 digits of remainging Time
else {digit1=score1;} //in Score Mode, digit1 shows score1
//if digit1>9, set most signifisant bit of numbers[digit1%10] to 0 by deducating 0b10000000
//which will light DP to display 'tens' as 1
digit1DPadj=0b00000000; //digit1 from 0 to 19,if over 10,DP of digit1 lid,otherwide off
if (digit1>9) {digit1DPadj=0b10000000;}
//loopCount has only 0 to 19,in timer Mode 10 cycles displays time, 10 cycles
//displays space or blank, this makes the time flash to distinguish from scores
if (loopCount>9 && timerMode) {lightDigit1(numbers[36]); //in timer Mode,displays space " " or blank
}
else {lightDigit1(numbers[digit1%10]-digit1DPadj); //displays first 2 digits of time/score
}
delay(delDigitOn);
if (timerMode) {digit2=remainingTime % 10;} //in timer Mode,displays '1s" of remaining Time
else {digit2=score2;} //in Score Mode,display score2
digit2DPadj=0b00000000; //digit2 from 0 to 19,if over 10,DP of digit2 lid,otherwide off
if (digit2>9) {digit2DPadj=0b10000000;}
if (loopCount>9 && timerMode) {lightDigit2(numbers[36]); //in timer Mode,displays space " " or blank
}
else {lightDigit2(numbers[digit2%10]-digit2DPadj);//displays first 2 digits of time/score
}
delay(delDigitOn);
// }
}
//Light Digit1
void lightDigit1(byte number) {
//digitalWrite(CA1, LOW); //shut down digit2 to prevent it from flickering
digitalWrite(CA2, LOW); //if not shut down, segments changed to those for digit1
lightSegments(number); //will show on digit2 for a short time, making it flickering
digitalWrite(CA1, HIGH);
}
//Light Digit2
void lightDigit2(byte number) {
digitalWrite(CA1, LOW); //shut down digit1 to prevent it from flickering
//digitalWrite(CA2, LOW); //if not shut down, segments changed to those for digit2
lightSegments(number); //will show on digit1 for a short time, making it flickering
digitalWrite(CA2, HIGH);
}
//Light segments,A to G & DP according to given number's binary bits
void lightSegments(byte number) {
for (int i = 0; i < 8; i++) {
int bit = bitRead(number, i);
digitalWrite(segs[i], bit);
}
}