Optimized use of 7-Segment display without separate controller

I'm fairly new to microcontrollers, especially programming, but have some experience in Java coding (took a couple classes. I like to think I have a slight grasp on what I'm doing) and I am currently attempting to build a small counter using a Teensy LC, and while working on the display portion, I am wondering if there is an easier way to write the display logic.

I have a 2-digit 10 pin 7-segment display connected to pins 0-9 with 0 and 1 being the ground on the display, and I am wondering a shorter way to write the display code:

void display1() {
    digitalWrite(pinbot, LOW);
    digitalWrite(pindec, LOW);
    digitalWrite(pinbl, LOW);
    digitalWrite(pinbr, LOW);
    digitalWrite(pintop, LOW);
    digitalWrite(pintr, LOW);
    digitalWrite(pinmid, LOW);
    digitalWrite(pintl, LOW);
    digitalWrite(gnd1, HIGH);
    digitalWrite(gnd2, LOW);
    delay(10);
    digitalWrite(pinbot, LOW);
    digitalWrite(pindec, LOW);
    digitalWrite(pinbl, LOW);
    digitalWrite(pinbr, HIGH);
    digitalWrite(pintop, LOW);
    digitalWrite(pintr, HIGH);
    digitalWrite(pinmid, LOW);
    digitalWrite(pintl, LOW);
    digitalWrite(gnd1, LOW);
    digitalWrite(gnd2, HIGH);
    delay(10);
}

I'd imagine there's a way to write it 20 times instead of 100, but I can't think of a way to do that, since everything but the ground is shared. I'm aware a MAX7221 would be the best way to do this, but I would prefer a code method, preferably a shorter one that what I've found.

    digitalWrite(pinbot, LOW);
    digitalWrite(pindec, LOW);
    digitalWrite(pinbl, LOW);
    digitalWrite(pinbr, HIGH);
    digitalWrite(pintop, LOW);
    digitalWrite(pintr, HIGH);
    digitalWrite(pinmid, LOW);
    digitalWrite(pintl, LOW);
    digitalWrite(gnd1, LOW);
    digitalWrite(gnd2, HIGH);

What, exactly, does that code do? Put the code in a function with an appropriate name, and call the function, instead of writing the code again later where you need that functionality.

Have you looked at any of the 7-segment Arduino code? I suggest you do, it's all there :D

If you say that pin 0 and pin 1 are ‘ground’ then you have a 2 digit common cathode type display where 8 pins (anodes) represent the seven segments A-G and the decimal point. The remaining 2 are the cathodes, one for each of the digits.
You have to multiplex this. Set up the anodes (that is segments A-G and DP) for the digit 1, then ground the cathode for digit 1 to illuminate it. Milli seconds later, do the same for digit 2. Repeat the whole thing ad infinitum.

Paul: That code is the digit display code, in that case it's for "11". It is it's own function, that's just the only part of the code I figured important. The question I was intending to ask was about a shorter way to write the function than doing all 100 numbers a 2 digit display can show.

6v6: Yes, that's exactly what the code I have up there does, it will display "11" on the display.

sept: I'm not sure why I hadn't thought about doing that, thank you for the tip though, I found a library, specifically this one which works beautifully.

For reference, here's the full code (it's not very long)

#include "SevSeg.h"
int gnd1 = 0;
int gnd2 = 1;
int pinbot = 2;
int pindec = 3;
int pinbl = 4;
int pinbr = 5;
int pintop = 6;
int pintr = 7;
int pinmid = 8;
int pintl = 9;
int pinBut1 = 10;
int pinBut2 = 11;
int pinBut3 = 12;
int counter = 0;
int setcounter = 18;
SevSeg sevsegdisplay;

void setup() {
pinMode(pinBut1, INPUT);
pinMode(pinBut2, INPUT);
pinMode(pinBut3, INPUT);
byte numDigits = 2;
byte digitPins[] = { gnd1, gnd2 };
byte segmentPins[] = { pintop, pintr, pinbr, pinbot, pinbl, pintl, pinmid, pindec };
sevsegdisplay.begin(COMMON_CATHODE, numDigits, digitPins, segmentPins);
}

void loop() {
  if (digitalRead(pinBut1) == HIGH) {
    counter = counter - 1;
  }
  if (digitalRead(pinBut2) == HIGH) {
    counter = counter + 1; 
  }
  if (digitalRead(pinBut3) == HIGH) {
    counter = setcounter;
  }
  sevsegdisplay.setNumber(counter,0);
  sevsegdisplay.refreshDisplay();
  sevsegdisplay.setBrightness(75);
  delay(10);
}

Now I'm having issues with the numbers themselves, but the display works fine which was my main issue.

Many thanks for the assist

Another tip, use arrays. So drop all the gnd1, pinbot etc. Just put the numbers in the digitPins[] and segmentPins[] arrays. Saves you a lot of typing. And just add comments if you want to. But instead of botpin etc I would use the pin numbers an/or the names that are more common (digit0-digit1, segmentA-segmentG)

And you only need to call setBrightness() once (aka in setup).

sierravictoralpha: Now I'm having issues with the numbers themselves, but the display works fine which was my main issue.

Let me guess, the increase / decrease fast? Use state change ;) And remove the delay() Or grab another library like Bounce2 :D

septillion: Another tip, use arrays. So drop all the gnd1, pinbot etc. Just put the numbers in the digitPins[] and segmentPins[] arrays. Saves you a lot of typing. And just add comments if you want to. But instead of botpin etc I would use the pin numbers an/or the names that are more common (digit0-digit1, segmentA-segmentG)

And you only need to call setBrightness() once (aka in setup). Let me guess, the increase / decrease fast? Use state change ;) And remove the delay() Or grab another library like Bounce2 :D

Variables are just leftovers, the SevSeg actually does the array, and it throws warnings about having the variables, but I'm not to worried about it if it's not going to cause issue, and I'll just remove them after I get the rest sorted out.

As far as the delay, I just have that because the code I was based off off had it, I'm not totally sure what use it would have served, just figured it could be important.

For state change, I would think that it would look something like this in the loop block, however it just counts up really fast, regardless if the counter++ is in the if or the else block.

void loop() {  
  button1State = digitalRead(pinBut1);
  if (button1State != lastButton1State) {
    if (button1State == HIGH) {
      button1PushCounter++;
      //counter = counter + 1; //causes fast counting up
    }
      else {
        //counter = counter + 1;  //causes fast counting up
      }
  }
  lastButton1State = button1State;
  sevsegdisplay.setNumber(counter,0);
  sevsegdisplay.refreshDisplay();
}

The idea is to have it count up when button 1 is pressed, which is what I'm just focusing on making work right now. I"ll keep playing with it, see what I find, but advice is more than welcome.

7-segment displays have a standard layout for the segment naming... that may help you express your segment states better. abcdefg and dp Note that all seven and the dp (8 bits) will fit nicely into a byte/char

Now go back as mentioned above, and create a constant array of bytes (0-9) if you only want digits, or add extra chars for extra 'digits'.

These become your complete display characters for any digit or number combination. very compact and fast, simple to maintain and debug at the beginning.

this has all been said above, but clarifies that you need to understand what you're doing, and the tools you're using before getting buried iwasted overkill,

sierravictoralpha: and I'll just remove them after I get the rest sorted out.

That's the unversed order ;) Because of the weird construction it's easier for you to get into problems ;)

And as far as the code, I don't see a big flaw except no debouncing. I do hope you have a pull up/down resistor somewhere? Easiest is to use the internal pull up resistor. But really, make it easy and grab Bounce. Then all you need to do is

button.update();
if(button.fell()){
  counter++;
}

lastchancename: Now go back as mentioned above, and create a constant array of bytes (0-9) if you only want digits, or add extra chars for extra 'digits'.

That's all done in the library. No need to reinvent the wheel unless you are really curious what happens. But then you should actually also look at what digitalWrite() does, and pinMode(), and the Arduino IDE in general... Otherwise it's just the fun of encapsulation and libraries :D

septillion:
That’s the unversed order :wink: Because of the weird construction it’s easier for you to get into problems :wink:

And as far as the code, I don’t see a big flaw except no debouncing. I do hope you have a pull up/down resistor somewhere? Easiest is to use the internal pull up resistor. But really, make it easy and grab Bounce. Then all you need to do is

button.update();

if(button.fell()){
  counter++;
}



That's all done in the library. No need to reinvent the wheel unless you are really curious what happens. But then you should actually also look at what digitalWrite() does, and pinMode(), and the Arduino IDE in general... Otherwise it's just the fun of encapsulation and libraries :D

Thank you for the advice, I loaded the Bounce2 library, and with that bit you gave me, I’ve got it working wonderfully!

Here’s the code if anyone wants to see and has any more advice for me. My next plan is to make it blink at zero and maybe even use an IR detector LED as a switch if it doesn’t prove too hard.

#include <Bounce2.h>
#include "SevSeg.h"
int counter = 0;
int setcounter = 18;
SevSeg sevsegdisplay;
Bounce button1 = Bounce();
Bounce button2 = Bounce();
Bounce button3 = Bounce();


void setup() {
pinMode(0, INPUT);
pinMode(1, INPUT);
pinMode(2, INPUT);
byte numDigits = 2;
byte digitPins[] = { 7, 12 };
byte segmentPins[] = { 5, 6, 11, 8, 10, 4, 3, 9 };
sevsegdisplay.begin(COMMON_CATHODE, numDigits, digitPins, segmentPins);
sevsegdisplay.setBrightness(75);
button1.attach(0);
button1.interval(5);
button2.attach(1);
button2.interval(5);
button3.attach(2);
button3.interval(5);
}

void loop() {
  button1.update();
  if(button1.fell()){
    counter++;
  }
  button2.update();
  if(button2.fell()){
    counter--;
  }
  button3.update();
  if(button3.fell()){
    counter = setcounter;
  }
    sevsegdisplay.setNumber(counter,0);
    sevsegdisplay.refreshDisplay();

}

@UnoWatt, luckily that part is already gone :smiley: But unfortunately the SevSeg library itself is blocking :confused: It starts to itch to fork it and change it :smiley:

@sierravictoralpha, few tips:

  • Watch your indentation.
  • Again, arrays :wink:
  • And all pin declaration should be on top, not in setup.

Modified it a bit

#include <Bounce2.h>
#include "SevSeg.h"
int counter = 0;
int setcounter = 18;

//display part
const byte DisplayBrightness = 75;
const byte NumDigits = 2;
const byte DigitPins[] = {7, 12};
const byte SegmentPins[] = {5, 6, 11, 8, 10, 4, 3, 9};
SevSeg sevsegdisplay;

//button part
const byte ButtonPins[] = {0, 1, 2};
const byte ButtonDebounceTime = 5;
Bounce buttons[sizeof(ButtonPins)];


void setup() {
  //setup display
  sevsegdisplay.begin(COMMON_CATHODE, NumDigits, DigitPins, SegmentPins);
  sevsegdisplay.setBrightness(DisplayBrightness);

  //setup buttons
  for(byte i = 0; i < sizeof(ButtonPins); i++){
    //No need to call pinMode yourself this way :D
    buttons[i].attach(ButtonPins[i], INPUT);
    buttons[i].interval(ButtonDebounceTime);
  }
}

void loop() {
  for(byte i = 0; i < sizeof(ButtonPins); i++){
    buttons[i].update();
  }
  
  if(buttons[0].fell()){
    counter++;
  }
  if(buttons[1].fell()){
    counter--;
  }
  if(buttons[2].fell()){
    counter = setcounter;
  }
  
  sevsegdisplay.setNumber(counter, 0);
  
  sevsegdisplay.refreshDisplay();
}

Oh! I hadn't really connected what you guys meant about using arrays for the pins, that makes a lot more sense, thank you!

As far as variables that aren't in arrays, is there a real difference between using an int as opposed to a byte? Or is it just organization? I ask because most things I've seen just use integers

I ask because most things I’ve seen just use integers

Most things are wrong.
A byte is the smallest accessed amount of memory. It can hold from 0 to 255.
Pin numbers go from 0 to 83 or so on a 2560 board with all pins broken out, and just 69 on the Arduino Mega.
Does that need an int? No, just a byte.

Similarly, many variables only need a byte for storage.

There are only 2048 bytes of SRAM in a UNO, practice good programming techniques and conserve them, be in good shape for that time when you need a large amount of variables, or a big array, or to receive & save a lot of serial data, etc.