Sparkfun 4 Digit Display - Button Counter

Thread Starter

Alex Jurtan

Joined Jul 14, 2015
14
Hi,
I have been trying to make a simple Pushbutton counter that adds up everytime a button is pressed.
I am using the SparkFun 7 Segment serial display and a simple push button. https://www.sparkfun.com/products/11442

I did not find anything similar in their example library, just tried to follow a tutorial online but it uses different hardware.
http://missionduke.com/wordpress/2011/05/arduino-button-press-counter/

The tutorial kinda works but the numbers appear randomly on the screen, meaning it does not count 0001,0002,0003,0004,0005... It counts 0100, 0002, 0300, 0004, 0500, ....
So it is a little bit confused.

If anyone can recommend a good example or an idea how to make it simply work. Appreciated a lot!!!
 

Thread Starter

Alex Jurtan

Joined Jul 14, 2015
14
Hi RRITESH,

I basically want to hook up the display and button to my arduino and have it working :)
On the arduino I have a stepper motor running that moves a mechanism and I want to count with a button how many times this mechanism moves.
I think using the pic16f877a is not really necessary, if I can make it work with the resources I have.

Thanks!
 

RRITESH KAKKAR

Joined Jun 29, 2010
2,829
Hi RRITESH,

I basically want to hook up the display and button to my arduino and have it working :)
On the arduino I have a stepper motor running that moves a mechanism and I want to count with a button how many times this mechanism moves.
I think using the pic16f877a is not really necessary, if I can make it work with the resources I have.

Thanks!
C:
#include <htc.h>
#include <stdio.h>
__CONFIG( BOREN_OFF & PWRTE_ON & WDTE_OFF & FOSC_HS);
//LVP_OFF&
#define _XTAL_FREQ 20000000

char data[13]={  0b01111110,0b00010010,0b10111100,0b10110110,0b11010010,0b11100110,0b11101110, 0b00110010,0XFF,0b11110110};
main()
    {
    TRISB = 0X00 ;
    TRISC = 0B00000011 ;
TRISA = 0xff ;
ADCON1=0b00000000;
ADCON0=0b10000001;//000 = channel 0, (RA0/AN0)
    ADIF=0;
    ADIE=1;
    PEIE=1;
unsigned int a;
unsigned int c;
unsigned char d1;
unsigned char d2;


unsigned int div;
unsigned int rem;

PORTB=0x00;
while(1){
//d2=eeprom_read(0x00);
//d1=eeprom_read(0x01);
//a=d2;
//a=a<<8;
//a=a+d1;
//c=a;




    //GIE=1;
 
    __delay_us(10);
GO_DONE=1;
    __delay_us(10);

//c=ADRES;

c=0b00000011;



//PORTC=0b10000000;
RC4=1;
RC3=1;
rem = c%10;
c=c/10;
PORTB=data[rem];

__delay_ms(20);
PORTB=0x00;
//PORTC=0b01000000;
RC4=1;
RC3=1;
rem=c%10;
PORTB=data[1];
__delay_ms(20);

PORTB=0x00;
/*
c=c/10;
PORTC=0b00100000;
rem=c%10;    
 
PORTB=data[rem];
__delay_ms(8);
PORTB=0x00;*/
    }
    }
 

/*
if(RC0==1){
__delay_ms(100);
a=a+1;

d1=a;
d2=a>>8;
eeprom_write(0x00, d2);
eeprom_write(0x01, d1);
if(a>999){
a=0;
}

}

  if(RC1==1){
__delay_ms(100);
a=a-1;
if(a>999){
a=0;
}
d1=a;
d2=a>>8;

eeprom_write(0x00, d2);
eeprom_write(0x01, d1);
}
*/
 
Last edited:

Thread Starter

Alex Jurtan

Joined Jul 14, 2015
14
Hi RRITESH,

Thank you for the explanation. I do understand how it counts up.
But I have no idea how to implement this in an arduino code and make it work with the display.

This is the code I have at the moment. I used the Stepper example file and added the code from the tutorial I did.
But as mentioned it is confused displaying it correctly.

C:
/*
Stepper Motor Control - one revolution

This program drives a unipolar or bipolar stepper motor.
The motor is attached to digital pins 8 - 11 of the Arduino.

The motor should revolve one revolution in one direction, then
one revolution in the other direction.


Created 11 Mar. 2007
Modified 30 Nov. 2009
by Tom Igoe

*/
#include <SoftwareSerial.h>  //for software serial communication
#include <Stepper.h>


#define txPin 5  //change to your serial port on Arduino board
#define rxPin 6  //not used but is required


SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
int buttonPressCount;

const int  buttonPin = 3;    //the pin that the pushbutton is attached to

int buttonPushCounter = 0;   //counter for the number of button presses
int buttonState = 0;         //current state of the button
int lastButtonState = 0;     //previous state of the button


const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
// for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

void setup() {
  // set the speed at 60 rpm:
  myStepper.setSpeed(225);
  pinMode(buttonPin, INPUT);  //initialize the button pin as a input
  // initialize the serial port:
  Serial.begin(9600);

   pinMode(txPin, OUTPUT);
//the following resets the board, changes the brightness to 100%, and sets the board to '0000':
mySerial.begin(9600);
mySerial.print(0x7A); //special character
mySerial.print(0x00); //set brightness to full
mySerial.print(0x76); //reset board
mySerial.print(0); //send '0' character
mySerial.print(0); //send '0' character
mySerial.print(0); //send '0' character
mySerial.print(0); //send '0' character
}

void loop() {
  // step one revolution  in one direction:
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);


buttonState = digitalRead(buttonPin);  //read the pushbutton input pin

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // went from off to on:
      buttonPushCounter++;
   
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter, DEC);
      updateDisplay(buttonPushCounter);  //function to update the display 'requires button press count'
   
   
    }

  }
  lastButtonState = buttonState;  // save the current state as the last state, for next time through the loop
}


void updateDisplay(int buttonPushCounter){
String intString = String(buttonPushCounter);  //changes integer to a string
char displayChars[4];  //create array to hold the four numbers
int stringLength = intString.length();  //get length of the string
//the following will determine if the button press count variable has 1, 2, 3, or 4 numbers in it
//and will fill the empty spaces with '0'. so if the button press count variable is '29' it will end up being '0029':
if(stringLength == 4){
  displayChars[0] = intString.charAt(0);
  displayChars[1] = intString.charAt(1);
  displayChars[2] = intString.charAt(2);
  displayChars[3] = intString.charAt(3);
}else if(stringLength == 3){
  displayChars[0] = 0;
  displayChars[1] = intString.charAt(0);
  displayChars[2] = intString.charAt(1);
  displayChars[3] = intString.charAt(2);
}else if(stringLength == 2){
  displayChars[0] = 0;
  displayChars[1] = 0;
  displayChars[2] = intString.charAt(0);
  displayChars[3] = intString.charAt(1);
}else if(stringLength == 1){
  displayChars[0] = 0;
  displayChars[1] = 0;
  displayChars[2] = 0;
  displayChars[3] = intString.charAt(0);
}
mySerial.print(0x76); //Reset board
mySerial.print(0x76); //Reset board
mySerial.print(displayChars[0]); //Send '0' character
mySerial.print(displayChars[1]); //Send '0' character
mySerial.print(displayChars[2]); //Send '0' character
mySerial.print(displayChars[3]); //Send '0' character

delay(100); //this will make it so you don't get double counts. you could also use this to avoid someone pressing the button repeatedly 'for fun!'

}
Mod edit: Added C to code tags
 
Last edited by a moderator:

djsfantasi

Joined Apr 11, 2010
9,155
It doesn't look like you are debouncing your button input. A push button actually goes high and low many times in the first milliseconds of a press.
You need to "debounce" the input. Here is a routine which uses interrupts to debounce a button. It is written in Arduino C++, but the logic might help you understand how to debouce an inout.
C:
// Button input related values
static const byte BUTTON_PIN = 2;
static const int  STATE_NORMAL = 0; // no button activity
static const int  STATE_SHORT  = 1; // short button press
static const int  STATE_LONG  = 2; // long button press
volatile int resultButton = 0; // global value set by checkButton()

//*****************************************************************
void setup() {
  Serial.begin(9600);

  // initialize input button pins
  Serial.println("Initializing Button pin");
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), checkButton, CHANGE);
  Serial.println("Button pin initialized");

}

//*****************************************************************
void loop() {
  static unsigned int buttonPushCounter=0;
  // if the user presses a button, ...
  if (((resultButton & STATE_SHORT) == STATE_SHORT ) ) {
  Serial.println("Button press detected");
  buttonPushCounter++;
  resultButton = STATE_NORMAL; // reset the button state
  }
}

//*****************************************************************
void checkButton() {
  /*
  * This function implements software debouncing for a two-state button.
  * It responds to a short press and a long press and identifies between
  * the two states. Your sketch can continue processing while the button
  * function is driven by pin changes.
  */

  const unsigned long DEBOUNCE_DELTA = 30ul; // debounce time
  static int lastButtonStatus = HIGH; // HIGH indicates the button is NOT pressed
  int buttonStatus;  // button atate Pressed/LOW; Open/HIGH
  static unsigned long shortTime = 0ul; // future times to determine is button has been pressed
  boolean Released = true, Transition = false; // various button states
  boolean timeoutShort = false, // flags for the state of the presses

  buttonStatus = digitalRead(BUTTON_PIN); // read the button state on the pin "BUTTON_PIN"
  timeoutShort = (millis() > shortTime); // calculate the current time states for the button presses

  if (buttonStatus != lastButtonStatus) { // reset the timeouts if the button state changed
  shortTime = millis() + DEBOUNCE_DELTA;
  }

  Transition = (buttonStatus != lastButtonStatus); // has the button chnged state
  Released = (Transition && (buttonStatus == HIGH)); // for input pullup circuit
  lastButtonStatus = buttonStatus; // save the button status

  if ( ! Transition) { //without a transition, there's no change in inout
  // if there has not been a transition, don't change the previoous result
  resultButton =  STATE_NORMAL | resultButton;
  return;
  }

  if (timeoutShort && Released) { // short timeout has occurred (and not long timeout) and button ws just released
  resultButton = STATE_SHORT | resultButton; // ensure the button result reflects a short press
  } else { // else there is no change in status, return the normal state
  resultButton = STATE_NORMAL | resultButton; // with no change in status, ensure no change in button status
  }
}
Mod edit: Added C to code tags
 
Last edited by a moderator:

RRITESH KAKKAR

Joined Jun 29, 2010
2,829
Hi RRITESH,

Thank you for the explanation. I do understand how it counts up.
But I have no idea how to implement this in an arduino code and make it work with the display.
Hi Alex Jurtan,
First learn the theory then implement it in digital micro.
I do understand how it counts up
See let take a variable that store our value you know char is 8bits an integers are 16bits.
so, if there is two digit then char is sufficient an if there is 3 or 4 digit then integers will be use.
so, let char a=0; // a=0 mean the data is initially zero.
if we will increment it then it will be something like this..
char a=0b00000000; // 0
char a=0b00000001;//1
char a=0b00000010;//2
char a=0b00000011;//3
....
..
.char a=0b00001000;//8
do you know 8 4 2 1 make bits in 4 bits data??
 

RRITESH KAKKAR

Joined Jun 29, 2010
2,829
But I have no idea how to implement this in an arduino code and make it work with the display.
I have not use arduino but the procedure will be same with different syntax.
first light the 7 segment display with simple delay an digital output like show/ispaly 0 1 2 3...
then we will move forward.
 

Thread Starter

Alex Jurtan

Joined Jul 14, 2015
14
Hi, Ok I have been reading and trying some things and managed now to have a debounced button that counts the display up 1 every time its pushed. This works perfectly. My next step is now to have a Stepper motor running at the same. I have been trying to make it work with attachinterrupt. But no luck. Does anyone know a way how to have the stepper running continuously while the button can count up numbers?
Thanks!

Counter code
C:
#include <SoftwareSerial.h>

// These are the Arduino pins required to create a software seiral
//  instance. We'll actually only use the TX pin.
const int softwareTx = 8;
const int softwareRx = 7;

const int buttonPin = 2;
int buttonState;
int lastButtonState = LOW;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers



SoftwareSerial s7s(softwareRx, softwareTx);

unsigned int counter = 0;  // This variable will count up to 65k
char tempString[10];  // Will be used with sprintf to create strings

void setup(){

  pinMode(buttonPin, INPUT);
  // Must begin s7s software serial at the correct baud rate.
  //  The default of the s7s is 9600.
  s7s.begin(9600);
clearDisplay();

}

void loop(){
  // Magical sprintf creates a string for us to send to the s7s.
  //  The %4d option creates a 4-digit integer.
  sprintf(tempString, "%4d", counter);

  // This will output the tempString to the S7S
  s7s.print(tempString);
  setDecimals(0b00001000);  // Sets digit 3 decimal on


int reading = digitalRead(buttonPin);

// If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        counter++;
      }
    }

}
lastButtonState = reading;
}


// Send the clear display command (0x76)
//  This will clear the display and reset the cursor
void clearDisplay()
{
  s7s.write(0x76);  // Clear display command
}


// Turn on any, none, or all of the decimals.
//  The six lowest bits in the decimals parameter sets a decimal
//  (or colon, or apostrophe) on or off. A 1 indicates on, 0 off.
//  [MSB] (X)(X)(Apos)(Colon)(Digit 4)(Digit 3)(Digit2)(Digit1)
void setDecimals(byte decimals)
{
  s7s.write(0x77);
  s7s.write(decimals);
}

Attachinterrupt Code
(This code does not work. On the first button push it counts up 1 and then doesn't react anymore.)
C:
#include <SoftwareSerial.h>

// These are the Arduino pins required to create a software seiral
//  instance. We'll actually only use the TX pin.
const int softwareTx = 8;
const int softwareRx = 7;



const int buttonPin = 0;
int buttonState;
int lastButtonState = LOW;

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers




SoftwareSerial s7s(softwareRx, softwareTx);

unsigned int counter = 0;  // This variable will count up to 65k
char tempString[10];  // Will be used with sprintf to create strings

void setup(){
  pinMode(buttonPin, INPUT);
  attachInterrupt(buttonPin, count, RISING);
  s7s.begin(9600);
clearDisplay();

}

void loop(){
  // Magical sprintf creates a string for us to send to the s7s.
  //  The %4d option creates a 4-digit integer.
  sprintf(tempString, "%4d", counter);

  // This will output the tempString to the S7S
  s7s.print(tempString);
  setDecimals(0b00001000);  // Sets digit 3 decimal on



}

// Send the clear display command (0x76)
//  This will clear the display and reset the cursor
void clearDisplay()
{
  s7s.write(0x76);  // Clear display command
}


// Turn on any, none, or all of the decimals.
//  The six lowest bits in the decimals parameter sets a decimal
//  (or colon, or apostrophe) on or off. A 1 indicates on, 0 off.
//  [MSB] (X)(X)(Apos)(Colon)(Digit 4)(Digit 3)(Digit2)(Digit1)
void setDecimals(byte decimals)
{
  s7s.write(0x77);
  s7s.write(decimals);
}


void count() {

int reading = digitalRead(buttonPin);

// If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        counter++;
      }
    }

}
lastButtonState = reading;
}
Mod edit: Added C to code tags
 
Last edited by a moderator:

djsfantasi

Joined Apr 11, 2010
9,155
I have some comments with regard to your attachInterrupt code. Which model Arduino are you using? I suspect that it is the Arduino Uno, given that you only have one hardware serial interface. Many models, including the Uno, can not use digital pin 0 for interrupts. If its not a Micro, Leonardo, Zero or Duo, you need to use a different pin for your button. Pins 2 & 3 are common. Check out the Arduino reference page for attachInterrupt().
 
Top