A seven segment counter for Arduino
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
5.4 KiB

/*
* A seven segement display counter
*
* Counts the number of times a button is pressed and displays this number on a 7 segment display
*
* MIT License
*
* Copyright (c) 2018 Nicolas Massé
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* The button is connected to PIN 2.
*
* To prevent any rebound issue, filter the button signal with a low pass filter (R = 240 ohms, C = 6.8 micro farad)
*/
#define BUTTON_PIN 2
/*
* The seven segment display has a common cathode for each digit
*/
#define CATHODE_1000_PIN B00000001
#define CATHODE_100_PIN B00000010
#define CATHODE_10_PIN B00000100
#define CATHODE_1_PIN B00001000
// The splitter is the colon between the second and third digit
#define CATHODE_SPLITTER_PIN B00010000
/*
* All the cathodes are connected to PORTB's pins
*
*/
#define CATHODE_PORT PORTB
#define CATHODE_DDR DDRB
/*
* The anodes will light up a segment when it is LOW and the cathode is HIGH.
*
* The anode numbering refers to the standard numbering:
* https://en.wikipedia.org/wiki/Seven-segment_display
*/
#define ANODE_A_PIN B10000000
#define ANODE_B_PIN B01000000
#define ANODE_C_PIN B00100000
#define ANODE_D_PIN B00010000
#define ANODE_E_PIN B00001000
// Yes, there is a gap since pin 2 is used for the button
#define ANODE_F_PIN B00000010
#define ANODE_G_PIN B00000001
/*
* All the anodes are connected to PORTD's pins
*/
#define ANODE_PORT PORTD
#define ANODE_DDR DDRD
/*
* The number of milliseconds to wait in order to let the retinal persistence do its job.
* See https://en.wikipedia.org/wiki/Persistence_of_vision
*/
#define DELAY 5
/*
* Set this in order to see how the display multiplexing work
*/
//#define DEBUG
#ifdef DEBUG
#define DELAY_DEBUG delay(50);
#define DELAY 500
#else
#define DELAY_DEBUG
#endif
/*
* Lookup table to drive the anode pins according to a digit between 0 and 9
*/
byte digit[] = {
/* 0 */ ANODE_A_PIN|ANODE_B_PIN|ANODE_C_PIN|ANODE_D_PIN|ANODE_E_PIN|ANODE_F_PIN,
/* 1 */ ANODE_B_PIN|ANODE_C_PIN,
/* 2 */ ANODE_A_PIN|ANODE_B_PIN|ANODE_D_PIN|ANODE_E_PIN|ANODE_G_PIN,
/* 3 */ ANODE_A_PIN|ANODE_B_PIN|ANODE_C_PIN|ANODE_D_PIN|ANODE_G_PIN,
/* 4 */ ANODE_B_PIN|ANODE_C_PIN|ANODE_F_PIN|ANODE_G_PIN,
/* 5 */ ANODE_A_PIN|ANODE_C_PIN|ANODE_D_PIN|ANODE_F_PIN|ANODE_G_PIN,
/* 6 */ ANODE_A_PIN|ANODE_C_PIN|ANODE_D_PIN|ANODE_E_PIN|ANODE_F_PIN|ANODE_G_PIN,
/* 7 */ ANODE_A_PIN|ANODE_B_PIN|ANODE_C_PIN,
/* 8 */ ANODE_A_PIN|ANODE_B_PIN|ANODE_C_PIN|ANODE_D_PIN|ANODE_E_PIN|ANODE_F_PIN|ANODE_G_PIN,
/* 9 */ ANODE_A_PIN|ANODE_B_PIN|ANODE_C_PIN|ANODE_D_PIN|ANODE_F_PIN|ANODE_G_PIN
};
// All the cathodes
const byte cathodes = CATHODE_1000_PIN | CATHODE_100_PIN | CATHODE_10_PIN | CATHODE_1_PIN | CATHODE_SPLITTER_PIN;
// All the anodes
const byte anodes = ANODE_A_PIN|ANODE_B_PIN|ANODE_C_PIN|ANODE_D_PIN|ANODE_E_PIN|ANODE_F_PIN|ANODE_G_PIN;
void setup() {
// initialize cathodes pins as output with default to LOW
CATHODE_DDR |= cathodes;
CATHODE_PORT &= ~cathodes;
// initialize anodes pins as output with default to HIGH
ANODE_DDR |= anodes;
ANODE_PORT |= anodes;
// Enable the button and register an interrupt
pinMode(BUTTON_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), button_interrupt, RISING);
}
// the counter is later incremented by an interrupt
volatile byte counter[] = {0,0,0,0};
void button_interrupt() {
if (counter[0] >= 9) {
counter[0] = 0;
if (counter[1] >= 9) {
counter[1] = 0;
if (counter[2] >= 9) {
counter[2] = 0;
if (counter[3] >= 9) {
// Overflow
counter[3] = 0;
} else {
counter[3]++;
}
} else {
counter[2]++;
}
} else {
counter[1]++;
}
} else {
counter[0]++;
}
}
const byte digit_cathodes[] = { CATHODE_1_PIN, CATHODE_10_PIN, CATHODE_100_PIN, CATHODE_1000_PIN };
void loop() {
// Iterate over the four digits to display
for (byte c = 0; c < 4; c++) {
// Set all cathodes pins to LOW
CATHODE_PORT &= ~(CATHODE_1_PIN|CATHODE_10_PIN|CATHODE_100_PIN|CATHODE_1000_PIN);
DELAY_DEBUG
// Drive the matching anodes of the digit (a segment is enabled when the matching pin is LOW)
ANODE_PORT = ~digit[counter[c]];
DELAY_DEBUG
// Set the selected cathode pin to HIGH to display to digit
CATHODE_PORT |= digit_cathodes[c];
DELAY_DEBUG
// Let the persistence of vision do his job
delay(DELAY);
}
}