Hey guys
Beforehand: I did find a few threads related to projects using the MCP23017 I2C-demultiplexer but my main issue are my missing programming skills. I read everything I could find concerning similar projects but still am kinda lost when it comes to generating the actual code for this specific application. The main aim of this thread is to get suggestions for code I can use for this project.
The project
We´re going to build a scoreboard for a school gymnasium.
The board needs three functions:
-display time
-set/pause/reset a timer
-optical and acoustic feedback when timer is stopped or time is elapsed (there´s gonna be a buzzer and red and green indicator lights)
-display scores of each team (though that´s quite probably the easiest part to implement)
-do each of the aforementioned things via IR-remote (not focusing on that yet at current stage)
The brain is going to be an Arduino Uno which, via its I2C-Bus controls four MCP23017 demultiplexer ICs (each IC having 16 outputs and being controlled only via the SDA and SCL outputs of the Arduino on that so called "I2C-Bus"), which in turn control the separate segments of eight 7-segment-digits. Four of these are going to be for displaying the current time and using the timer functionality.
Two digits for the red team score, two digits for the blue team score.
The actual digits on the board are going to be size A3 (420x297 mm or 16,54x11,7 inches), use fourteen 10 mm diameter LEDS per segment and will have a dedicated control- and load-circuit and 24V, 100W power supply.
For testing the code though, I´m using a plastic breadboard and regular sized (about an inch in height) 7-segment-digits with 270 Ohm current limiting resistors.
I added a Fritzing illustration to make it easier to imagine what we´re actually talking about here.
That Fritzing layout is NOT exactly true to reality. For example I didn´t find an actual passive common cathode, 2-digit-7-segment block with 18 pins. The actual hardware are MAN 6740 and 270Ohm resistors. The generic Fritzing IC I used to represent the MCP23017 does NOT accurately reflect the pin layout on an actual MCP23017 - but for this purpose it doesn´t matter.
Keep in mind - there are going to be six more 7-segment-digit-blocks and three more MCP23017 connected to my breadboard soon. So the code would need to be able to correctly address all MCPs using their hardware adresses and the Adafruit library (open for other suggestions, using wire.h seems more difficult to me though at my skill level.
Also - the colour code on the 270 ohm resistors is off. Fritzing didn´t have 270 Ohm to be selected.
The code
So far - I managed to write code for a rudimentary timer function using only two digits.
I´m using the Adafruit MCP23017 library (GitHub - adafruit/Adafruit-MCP23017-Arduino-Library: Arduino Library for Adafruit MCP23017).
In the beginning of the code you can see that the outputs A0 - A7 (A0 is "0", A1 is "1",.. in the Adafruit library) of the MCP23017 are connected to segments A - G and dotpoint (D.P.1 "DP" in the code) of the first 7-segment-digit. The outputs B0 - B7 (B0 is "8", B1 is "9",.. in the Adafruit library) are connected to segments A - G and dotpoint (D.P.2 "DP1" in the code) of the second 7-segment-digit.
The function "void_display number" distributes whichever value is set in the void loop for "i" between the first and second 7-segment-digits, using a division by 10 and modulo and "void display_digit".
I used the relation of A0 being "0" and B0 being "8" to use an offset by 8 to use the code of "void display_digit" both for the first and second 7-segment-digits.
my problems (at least perceived):
-
missing experience coding, this is my first actual project coding something. I did learn basic Python programming and did programming examples at school but actually implementing sth like this in a language that´s also pretty unknown to me turns out to be tough. I´m lacking imagination in this department on how to structure code architecture.
-
in the current version of the code, the outputs A0 - A7 of the MCP are connected to the segments in a logical order (see above). Turns out though - when I wanna connect eight little 7-segment digits and four MCPs on breadboard it gets really messy and non-portable fast. So I decided to transfer the whole breadboard circuit to perforated PCB board instead. And there - it turns out the whole thing is tidier and easier to route if I don´t follow the logical order (see above). That means connect f.e. A0 to C2 (segment C, digit 2) instead of segment A of digit 1 (the whole pattern is described above), A1 to G2,... and so on.
That does make the installation tidier but messes up my nice offset function in my code... -
the hardware adresses of each MCP23017 are determined by biasing three pins (A0, A1, A2) either high or low. There´s a maximum of eight MCPs that can be controlled by one I2C-bus. Therefore there are eight possible hardware adresses (0x20-0x27, the three biasing pins constitute the three last bits in the binary representation of these eight possible adresses)
Therefore - each MCP23017 can be adressed via SDA and SCL, using it´s address.
In the Adafruit MCP23017 library, this is - as I understand it - implemented via "begin.I2C()" if you put a zero "0" in the brackets, the MCP with hardware address 0x20 will be adressed, if you put a "1" in there, the second MCP (address 0x21) will be adressed and so on..
Thing is - I couldn´t really find a good explanation of all the possibilites of the Adafruit library anywhere. There are things I don´t understand - for example: I can´t see the actual line "begin.I2C()" being used anywhere in my code (which is built on an example from Github) other than to trigger a serial output:
"if (!mcp.begin_I2C()) {Serial.println("Error.");
while (1);" (line 154 in the code)
It works anyways though
What´s whith the "while (1)" (line 156) here ? That doesn´t even make sense to me but I left it in there because I thought it plays a role.
- if I want to address the other two digits on my clock/timer display (mm:ss format) I definitely NEED to address them using
begin.I2C()
, not sure WHERE in the code I need to put that though when it´s not even present atm as far as I can see
So - right now I´m at a loss on how to structure the code to use the Adafruit library correctly and control all four MCP23017s.
- Later on - I´ll be dealing with threading in the necessary prompts from the IR receiver to prompt all those functionalities. Not even there yet...
ANY HELP is greatly appreciated!
CODE
#include <Adafruit_MCP23X17.h>
#define LED_PIN_A 0
#define LED_PIN_B 1 // MCP23XXX pin LED is attached to
#define LED_PIN_C 2
#define LED_PIN_D 3
#define LED_PIN_E 4
#define LED_PIN_F 5
#define LED_PIN_G 6
#define LED_PIN_DP 7
#define LED_PIN_A2 8
#define LED_PIN_B2 9 // MCP23XXX pin LED is attached to
#define LED_PIN_C2 10
#define LED_PIN_D2 11
#define LED_PIN_E2 12
#define LED_PIN_F2 13
#define LED_PIN_G2 14
#define LED_PIN_DP2 15
// uncomment appropriate line
// Adafruit_MCP23X08 mcp;
Adafruit_MCP23X17 mcp;
void clear_digit() {
mcp.digitalWrite(LED_PIN_A, LOW);
mcp.digitalWrite(LED_PIN_B, LOW);
mcp.digitalWrite(LED_PIN_C, LOW);
mcp.digitalWrite(LED_PIN_D, LOW);
mcp.digitalWrite(LED_PIN_E, LOW);
mcp.digitalWrite(LED_PIN_F, LOW);
mcp.digitalWrite(LED_PIN_G, LOW);
mcp.digitalWrite(LED_PIN_DP, LOW);
mcp.digitalWrite(LED_PIN_A2, LOW);
mcp.digitalWrite(LED_PIN_B2, LOW);
mcp.digitalWrite(LED_PIN_C2, LOW);
mcp.digitalWrite(LED_PIN_D2, LOW);
mcp.digitalWrite(LED_PIN_E2, LOW);
mcp.digitalWrite(LED_PIN_F2, LOW);
mcp.digitalWrite(LED_PIN_G2, LOW);
mcp.digitalWrite(LED_PIN_DP2, LOW);
}
void display_number(int number){
int left_digit;
int right_digit;
left_digit=number/10;
right_digit=number%10;
display_digit(left_digit,1);
display_digit(right_digit,0);
}
void display_digit(int digit,int left){
int offset;
if(left == 1)
{offset = 0;}
else{offset = 8;}
if(digit == 0) {
mcp.digitalWrite(LED_PIN_A+offset, HIGH);
mcp.digitalWrite(LED_PIN_B+offset, HIGH);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, HIGH);
mcp.digitalWrite(LED_PIN_E+offset, HIGH);
mcp.digitalWrite(LED_PIN_F+offset, HIGH);
mcp.digitalWrite(LED_PIN_G+offset, LOW);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 1) {
mcp.digitalWrite(LED_PIN_A+offset, LOW);
mcp.digitalWrite(LED_PIN_B+offset, HIGH);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, LOW);
mcp.digitalWrite(LED_PIN_E+offset, LOW);
mcp.digitalWrite(LED_PIN_F+offset, LOW);
mcp.digitalWrite(LED_PIN_G+offset, LOW);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 2) {
mcp.digitalWrite(LED_PIN_A+offset, HIGH);
mcp.digitalWrite(LED_PIN_B+offset, HIGH);
mcp.digitalWrite(LED_PIN_C+offset, LOW);
mcp.digitalWrite(LED_PIN_D+offset, HIGH);
mcp.digitalWrite(LED_PIN_E+offset, HIGH);
mcp.digitalWrite(LED_PIN_F+offset, LOW);
mcp.digitalWrite(LED_PIN_G+offset, HIGH);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 3) {
mcp.digitalWrite(LED_PIN_A+offset, HIGH);
mcp.digitalWrite(LED_PIN_B+offset, HIGH);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, HIGH);
mcp.digitalWrite(LED_PIN_E+offset, LOW);
mcp.digitalWrite(LED_PIN_F+offset, LOW);
mcp.digitalWrite(LED_PIN_G+offset, HIGH);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 4) {
mcp.digitalWrite(LED_PIN_A+offset, LOW);
mcp.digitalWrite(LED_PIN_B+offset, HIGH);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, LOW);
mcp.digitalWrite(LED_PIN_E+offset, LOW);
mcp.digitalWrite(LED_PIN_F+offset, HIGH);
mcp.digitalWrite(LED_PIN_G+offset, HIGH);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 5) {
mcp.digitalWrite(LED_PIN_A+offset, HIGH);
mcp.digitalWrite(LED_PIN_B+offset, LOW);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, HIGH);
mcp.digitalWrite(LED_PIN_E+offset, LOW);
mcp.digitalWrite(LED_PIN_F+offset, HIGH);
mcp.digitalWrite(LED_PIN_G+offset, HIGH);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 6) {
mcp.digitalWrite(LED_PIN_A+offset, HIGH);
mcp.digitalWrite(LED_PIN_B+offset, LOW);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, HIGH);
mcp.digitalWrite(LED_PIN_E+offset, HIGH);
mcp.digitalWrite(LED_PIN_F+offset, HIGH);
mcp.digitalWrite(LED_PIN_G+offset, HIGH);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 7) {
mcp.digitalWrite(LED_PIN_A+offset, HIGH);
mcp.digitalWrite(LED_PIN_B+offset, HIGH);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, LOW);
mcp.digitalWrite(LED_PIN_E+offset, LOW);
mcp.digitalWrite(LED_PIN_F+offset, LOW);
mcp.digitalWrite(LED_PIN_G+offset, LOW);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 8) {
mcp.digitalWrite(LED_PIN_A+offset, HIGH);
mcp.digitalWrite(LED_PIN_B+offset, HIGH);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, HIGH);
mcp.digitalWrite(LED_PIN_E+offset, HIGH);
mcp.digitalWrite(LED_PIN_F+offset, HIGH);
mcp.digitalWrite(LED_PIN_G+offset, HIGH);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
} else if (digit == 9) {
mcp.digitalWrite(LED_PIN_A+offset, HIGH);
mcp.digitalWrite(LED_PIN_B+offset, HIGH);
mcp.digitalWrite(LED_PIN_C+offset, HIGH);
mcp.digitalWrite(LED_PIN_D+offset, HIGH);
mcp.digitalWrite(LED_PIN_E+offset, LOW);
mcp.digitalWrite(LED_PIN_F+offset, HIGH);
mcp.digitalWrite(LED_PIN_G+offset, HIGH);
mcp.digitalWrite(LED_PIN_DP+offset, LOW);
}}
void setup() {
Serial.begin(9600);
//while (!Serial);
Serial.println("MCP23xxx Blink Test!");
// uncomment appropriate mcp.begin
if (!mcp.begin_I2C()) {
Serial.println("Error.");
while (1);
}
// configure pin for output
mcp.pinMode(LED_PIN_A, OUTPUT);
mcp.pinMode(LED_PIN_B, OUTPUT);
mcp.pinMode(LED_PIN_C, OUTPUT);
mcp.pinMode(LED_PIN_D, OUTPUT);
mcp.pinMode(LED_PIN_E, OUTPUT);
mcp.pinMode(LED_PIN_F, OUTPUT);
mcp.pinMode(LED_PIN_G, OUTPUT);
mcp.pinMode(LED_PIN_DP, OUTPUT);
mcp.pinMode(LED_PIN_A2, OUTPUT);
mcp.pinMode(LED_PIN_B2, OUTPUT);
mcp.pinMode(LED_PIN_C2, OUTPUT);
mcp.pinMode(LED_PIN_D2, OUTPUT);
mcp.pinMode(LED_PIN_E2, OUTPUT);
mcp.pinMode(LED_PIN_F2, OUTPUT);
mcp.pinMode(LED_PIN_G2, OUTPUT);
mcp.pinMode(LED_PIN_DP2, OUTPUT);
//Serial.println("Looping...");
}
void loop() {
int i = 0;
for (i=90; i>=0; i--) {
display_number(i);
delay(1000);}
}