Seeed-Studio / Grove_4Digital_Display

Display for digital tube
39 stars 30 forks source link

TM1637.h library displays incorrect characters after extended period of time #21

Open Vatch opened 2 years ago

Vatch commented 2 years ago

The project: I am using a TM1637 7seg display as a count down timer for a coin operated module. Basically you put a quarter into a coin acceptor module, it sends a pulse to the Arduino, that adds a set amount of time to the counter and the time left on the counter is displayed on the TM1637 7seg display. So long as there is time left on the counter a relay is triggered that powers an external device. I am using TM1637.h "Grove 4-Digit Display" library from Seeed Studio to control the display.

The problem: Everything works as intended until I leave the Arduino running for 2 hours or so. After running for a while the TM1637 display will display the top segment lit on all 4 character positions when it should just leave them blank. Upon inserting a coin the timer and relay works as it should and when its done counting down the display returns to the aforementioned state. Hitting reset or cycling power fixes this and after running for a while the display repeats the behavior.

I am fairly certain I have narrowed the problem down to the library itself as I have monitored pretty much all variables to look for something that may be rolling over after extended periods of time and I haven't found any culprits.

Are there any variables in the TM1637.h library that would be rolling over and causing it to display these odd characters rather than just being blank like it is supposed to?

My code:


#include <Arduino.h>
#include <EEPROM.h>
#include <TM1637.h>
// Seconds to add to timer per 25c
int QuarterTimeAdd=300;

//clock and data pins for display
int CLK = 3;
int DIO = 4;
// relay pin
int relayPin = 5;

//defining variables for display
TM1637 tm(CLK,DIO);

// variable use to measure the intervals inbetween impulses
volatile int i=0;
// Number of impulses detected
volatile int impulsCount=0;
// Time left to run motor in seconds
volatile int time_left=0;
//Minutes and seconds variables derived from time_left
volatile int minutes=0;
volatile int seconds=0;
//Minutes and seconds variables to display on timer
volatile int tensOfMin_left=0;
volatile int Min_left=0;
volatile int tensOfSec_left=0;
volatile int Sec_left=0;
//arduino timer storage variable
boolean toggle1 = 0;

void setup() {
 // Serial.begin(9600);
 // setting up timer1 on arduino for 1hz (every second)
 cli();//stop interrupts
 //set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  sei();//allow interrupts  

  // Interrupt connected to PIN D2 executing IncomingImpuls function when signal goes from HIGH to LOW
 attachInterrupt(digitalPinToInterrupt(2),incomingImpuls, FALLING);

 // setting up relayPin as output
  pinMode(relayPin, OUTPUT);

  //initalizing display
  tm.init();
  //set brightness; 0-7
  tm.set(7);
}

void incomingImpuls()
{
  cli();
  impulsCount=impulsCount+1;
  i=0;
  sei();
}

ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz subtracts 1 from time_left)
//generates pulse wave of frequency 1Hz/2 = 0.5kHz (takes two cycles for full wave- toggle high then toggle low)
  if (toggle1){
    if (time_left <= 0){}
    else{
    time_left = time_left - 1;
    toggle1 = 0;
    }
  }
  else{
    if (time_left <= 0){}
    else{
    toggle1 = 1;
    time_left = time_left - 1;
  }
  }
}  
void loop() {
//  Serial.println(time_left);
  //i ,intervul between pulses, is increased by 1 for each loop
  i=i+1;

// if coin counter detects quarter add 25 to time_left
 if (i>=30 and impulsCount==1){
   cli();
       if (time_left <=0){
      time_left = QuarterTimeAdd;
      }
      else{
    time_left=time_left+QuarterTimeAdd;
      }
    impulsCount=0;

    sei();
  }
//converting time_left in seconds to munites and seconds
seconds = time_left % 60;
minutes = time_left / 60;
//converting minutes and seconds to digits to be displayed
tensOfMin_left = minutes / 10;
Min_left = minutes % 10;
tensOfSec_left = seconds / 10;
Sec_left = seconds % 10;

//if time is <= 0 display 25CE else display time_left
// 7 segment displays these characters at these values 0-9=0-9 10-15=A-F 16=top segment blink 17=all segments stutter 18=pattern of filling in segments 19=top+topleft segments lit 20=all segments off
if(time_left<=0){
    tm.display(0,20);
  tm.display(1,20);
  tm.point(0);
  tm.display(2,20);
  tm.display(3,20 );
}
else{
    tm.display(0,tensOfMin_left);
  tm.display(1,Min_left);
  tm.point(1);
  tm.display(2,tensOfSec_left);
  tm.display(3,Sec_left);
}

// if time_left <=0 set relay pin to low else set it to high
if(time_left<=0){
  digitalWrite(relayPin,LOW);
  }
else{
  digitalWrite(relayPin,HIGH);
  }
// Serial.println(time_left);
}```
Combinacijus commented 2 years ago

Couldn't find anything obviously wrong in your code. I could guess it has small chance that somehow using interrupt and blocking them with cli() and sei() might interface with LCD communication if it's interrupted while sending data. But if it always happens after 2 hours it might not be it In a mean time I would suggest printing what variables are sent to the screen (if you haven't done so) and checking are they really valid:

  if (time_left <= 0) {
    tm.display(0, 20);
    tm.display(1, 20);
    tm.point(0);
    tm.display(2, 20);
    tm.display(3, 20);

    Serial.println("Display time <= 0");
    Serial.println(time_left);
  } else {
    tm.display(0, tensOfMin_left);
    tm.display(1, Min_left);
    tm.point(1);
    tm.display(2, tensOfSec_left);
    tm.display(3, Sec_left);

    Serial.println("Display time > 0");
    Serial.println(tensOfMin_left);
    Serial.println(Min_left);
    Serial.println(tensOfSec_left);
    Serial.println(Sec_left);
  }

P.S code is formated by putting it between ``` Your Code Here ```

Vatch commented 2 years ago

Couldn't find anything obviously wrong in your code. I could guess it has small chance that somehow using interrupt and blocking them with cli() and sei() might interface with LCD communication if it's interrupted while sending data. But if it always happens after 2 hours it might not be it In a mean time I would suggest printing what variables are sent to the screen (if you haven't done so) and checking are they really valid:

  if (time_left <= 0) {
    tm.display(0, 20);
    tm.display(1, 20);
    tm.point(0);
    tm.display(2, 20);
    tm.display(3, 20);

    Serial.println("Display time <= 0");
    Serial.println(time_left);
  } else {
    tm.display(0, tensOfMin_left);
    tm.display(1, Min_left);
    tm.point(1);
    tm.display(2, tensOfSec_left);
    tm.display(3, Sec_left);

    Serial.println("Display time > 0");
    Serial.println(tensOfMin_left);
    Serial.println(Min_left);
    Serial.println(tensOfSec_left);
    Serial.println(Sec_left);
  }

P.S code is formated by putting it between Your Code Here

I printed the value of time_left but I haven't yet printed the values sent to the screen. Ill test it out. Also thanks for the advice on formatting the post! I was struggling trying to get it to work