input_pullup not listening

Status
Not open for further replies.

johnwlawrence88

New member
good evening

struggling with this one, I'm making a watch with my teensy 3.1 and i have three buttons all linked to GND and all have pinMode set to input_pullup

but occasionally i have found that the buttons fail to work but after half an hour or so they work again

so far here is the diagnostics i have carried out whilst the buttons were not responding:
printed the seconds from the real time clock to serial every second to confirm the teensy is still running. Worked fine
checked the voltage of the internal pullup wrt GND. 3.3v, when the button is pressed this goes down to 0.4v.
changed the code to use interrupts as i thought digitalRead on the pins was being missed if it was updating time when i pressed the button (probably running fast enough that this isn't the case but id rather use interrupts anyway)

this is an intermittent fault that seems to happen some time after powering it up for about 30 mins and then they respond again

heres my code:

Code:
#define dc 9
#define cs 7
#define rst 8
#define SD_CS 6
#define TIME_HEADER  "T"

#define leftButton 16
#define centreButton 19
#define rightButton 22

int leftBut;
int centreBut;
int rightBut;

unsigned int SWValue;
unsigned int SWMilli;
unsigned int SWSecond;
unsigned int SWMinute;
unsigned int SWHour;
unsigned long currentMillis;

int SWStatus;

// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF


#include <Adafruit_GFX.h>
#include <Adafruit_SSD1351.h>
#include <SPI.h>
#include <Time.h>


Adafruit_SSD1351 tft = Adafruit_SSD1351(cs, dc, rst);


float p = 3.1415926;


void fillpixelbypixel(uint16_t color) {
for (uint8_t x=0; x < tft.width(); x++) {
for (uint8_t y=0; y < tft.height(); y++) {
tft.drawPixel(x, y, color);
}
}
delay(100);
}


int Second = 0;
int Minute = 0;
int Hour = 0;
float sH;
float mH;
float hH;
int H;
int V;
int H2;
int V2;
int onTime = 10;
int displayOn = onTime;



void setup(void)
{
Serial.begin(9600);
Serial.print("hello!");
tft.begin();
tft.fillScreen(BLACK);
setSyncProvider(getTeensy3Time);

pinMode(leftButton, INPUT_PULLUP);
pinMode(centreButton, INPUT_PULLUP);
pinMode(rightButton, INPUT_PULLUP);


attachInterrupt(leftButton, debounceLeftInterrupt, FALLING);
attachInterrupt(centreButton, debounceCentreInterrupt, FALLING);
attachInterrupt(rightButton, debounceRightInterrupt, FALLING);


if (timeStatus()!= timeSet)
{
Serial.println("Unable to sync with the RTC");
}
else
{
Serial.println("RTC has set the system time");
}


}

void loop()
{
digitalClock();
}

time_t getTeensy3Time()
{
return Teensy3Clock.get();
}


void digitalClock()
{

for(;;)
{

if (centreBut==1)
{
  Serial.println("centreBut == 1");
  delay(200);
  centreBut=0;
  mainMenu();
}


if (Serial.available()) {
    time_t t = processSyncMessage();
    if (t != 0) {
      Teensy3Clock.set(t); // set the RTC
      setTime(t);
    }
  }

if (displayOn > 0)
{
  Serial.println("displayOn != 1");
  buttonMenu("0", " Menu ", "0", WHITE, BLACK);
    if (SWStatus == 2)
    {
      Serial.println("SWStatus ==2");
      tft.setCursor(15, 10);
      tft.setTextSize(2);
      tft.setTextColor(GREEN, BLACK);
      SWValue = millis() - currentMillis;
      SWHour = SWValue / 3600000;
      SWMinute = (SWValue - (SWHour*3600000)) / 60000;
      SWSecond = (SWValue - (SWHour*3600000) - (SWMinute*60000)) / 1000;
      if (SWHour < 10)
    {
      tft.print("0");
    }
    tft.print(SWHour);
    tft.print(":");
    if (SWMinute < 10)
    {
      tft.print("0");
    }
    tft.print(SWMinute);
    tft.print(":");
    if (SWSecond < 10)
    {
      tft.print("0");
    }
    tft.print(SWSecond);
    }
    
    if (SWStatus == 1 || SWStatus == 0)
    {
      
      tft.setCursor(35, 10);
      tft.setTextSize(2);
      tft.setTextColor(GREEN, BLACK);
      tft.print("       ");
    }
    tft.writeCommand(SSD1351_CMD_DISPLAYON);
}
//tft.writeCommand(SSD1351_CMD_DISPLAYON);
//Serial.println("DISPLAYON");

else
{
tft.writeCommand(SSD1351_CMD_DISPLAYOFF);
}

if (second() != Second)
{
//Serial.println("second() !- Second");
Second = second();
Minute = minute();
Hour = hour();
tft.setCursor(5,30);
tft.setTextSize(4);
tft.setTextColor(BLUE,BLACK);
int hourTens = Hour / 10;
tft.print(hourTens);
hourTens = hourTens * 10;
int hourUnits = Hour - hourTens;
tft.print(hourUnits);
tft.print(":");
int minuteTens = Minute / 10;
tft.print(minuteTens);
minuteTens = minuteTens * 10;
int minuteUnits = Minute - minuteTens;
tft.print(minuteUnits);
tft.setCursor(35,65);
tft.setTextColor(RED,BLACK);
tft.setTextSize(1);
tft.print(day());
tft.print(" ");
tft.print(month());
tft.print(" ");
tft.print(year());
displayOn--;
}

 
//if (hour() > 6 && hour() < 22)
//{
  if (Minute == 0 || Minute == 15 || Minute == 30 || Minute == 45)
  {
    //Serial.println("minute() == 0 || 15 || 30 || 45");
  displayOn = onTime;
  }
//}
}
}

unsigned long processSyncMessage() {
  unsigned long pctime = 0L;
  const unsigned long DEFAULT_TIME = 1357041600; // Jan 1 2013 

  if(Serial.find(TIME_HEADER)) {
     pctime = Serial.parseInt();
     return pctime;
     if( pctime < DEFAULT_TIME) { // check the value is a valid time (greater than Jan 1 2013)
       pctime = 0L; // return 0 to indicate that the time is not valid
     }
  }
  return pctime;
}

Code:
long debouncing_time = 200; //Debouncing Time in Milliseconds
volatile unsigned long last_micros;


void buttonMenu (char *left, char *centre, char *right, int fontColour, int backColour)
{
  tft.setTextColor(fontColour, backColour);
  tft.setTextSize(1);
  
  if (left != "0")
  {
  tft.drawRect(0, 83, 41, 11, fontColour);
  tft.setCursor(3, 85);
  tft.print(left);
  }
  
  if (centre != "0")
  {
  tft.drawRect(42, 83, 41, 11, fontColour);
  tft.setCursor(45, 85);
  tft.print(centre);
  }
  
  if (right != "0")
  {
  tft.drawRect(84, 83, 41, 11, fontColour);
  tft.setCursor(87, 85);
  tft.print(right);
  }
  
}

void debounceLeftInterrupt() {
  if((long)(micros() - last_micros) >= debouncing_time * 1000) {
    Serial.println("debounceLeftInterrupt");
    leftButISR();
    last_micros = micros();
  }
}
void debounceCentreInterrupt() {
  if((long)(micros() - last_micros) >= debouncing_time * 1000) {
    Serial.println("debounceCentreInterrupt");
    centreButISR();
    last_micros = micros();
  }
}
void debounceRightInterrupt() {
  if((long)(micros() - last_micros) >= debouncing_time * 1000) {
    Serial.println("debounceRightInterrupt");
    rightButISR();
    last_micros = micros();
  }
}

void leftButISR()
{
  cli();
  tft.writeCommand(SSD1351_CMD_DISPLAYON);
  Serial.println("DISPLAYON");
  if (displayOn > 0)
  {
    leftBut=1;
    Serial.println("leftBut=1");
  }
  displayOn = onTime;
  //sei();
}


void centreButISR()
{
    cli();
    tft.writeCommand(SSD1351_CMD_DISPLAYON);
    Serial.println("DISPLAYON");
    if (displayOn > 0)
    {
    centreBut=1;
    Serial.println("centreBut=1");
    }
    displayOn = onTime;
    //sei();
}


void rightButISR()
{
    cli();
    tft.writeCommand(SSD1351_CMD_DISPLAYON);
    Serial.println("DISPLAYON");
    if (displayOn > 0)
    {
      rightBut=1;
      Serial.println("rightBut=1");
    }
    displayOn = onTime;
    //sei();
}
 
A few newbie pointers...

need to change string to char...
if (left != "0")
vs
if (left != '0')

There's a Teensyduino library to debounce switches. The ISR technique you have should be replaced by calls to this library.
An ISR should not call a library nor print, etc. It must run just a few microseconds.

cli(); should not be in an ISR. Done by hardware
 
That's not your hardware/software issue though !

Why doesn't the voltage go to 0.00 when you close the switch ?

-- but your issue is really that your interrupt routines hang up when micros() recycles -- every 70 mins -- so micros()-last_micros becomes -2^32 (or something similar) just after the rollover.

So do something like:
if((long)((micros() - last_micros) % (2^32) >= debouncing_time * 1000) {
 
Can you try running File > Examples > Teensy > USB_Keyboard > Buttons ?

Does it also fail after 30 minutes?

Knowing if the failure happens on a well-tested example would really help narrow down whether the problem is likely in the hardware or the software.
 
Status
Not open for further replies.
Back
Top