1

I am writing a speedo/odometer program which was all working beautifully until I introduced an LCD screen and code for the LCD.

The screen works on power up, displays the distance recorded on an SD card, toggles from miles to km on the press of a button, but no longer runs my calculate method when invoked. The method has stopped working, or at least it's not updating with the latest information anymore when the method instructs it to. Any help would be greatly appreciated.

In case it matters, I am powering the project from an HTC one M8. Maybe it's lack of juice that is causing the issue, or just bad programming?

My code:

#include <Arduino.h>
#include <SPI.h>
#include <SD.h>;
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

int InterruptPin = 2;
//int PowerPin = 3;
int ButtonPin = 4;
int SDPin = 7;





volatile long km = 0; // SAVE
volatile float kmTemp = 0; // SAVE
volatile int kmrevs = 0; // SAVE
volatile long miles = 0; // SAVE
volatile float milesTemp = 0; // SAVE
volatile int milesrevs = 0; // SAVE

volatile int kph = 0;
volatile int mph = 0;
volatile unsigned long start = 0;
volatile unsigned long stop = 0;
volatile float secs = 0;
volatile float speed = 0;
volatile float temp = 0;

volatile int buttonState = 0;
volatile int lastButtonState = 0;
volatile boolean riding = false;

File myFile;

LiquidCrystal_I2C lcd(0x27, 16, 2); 




void calculate(){
    riding = true;

    // KPH SPEED CALCULATOR
    stop = millis() - start;
    start = millis();
    temp = (float)stop;
    secs = temp / 1000;
    speed = 1.854 / secs;
    speed = speed * 3.6;
    kph = speed;


    // MPH SPEED CONVERTOR
    float x = kph * 0.6214;
    mph = x;


    // KM DISTANCE CALCULATOR
    kmrevs++;
    if (kmrevs == 540){
        km++;
        kmrevs = 0;
        kmTemp = kmTemp + 0.00116;
    }
    if (kmTemp >= 1.0){
        km++;
        kmTemp = kmTemp - 1.0;
    }


    // MILES DISTANCE CALCULATOR
    milesrevs++;
    if (milesrevs == 868){
        miles++;
        milesrevs = 0;
        milesTemp = milesTemp +0.072;
    }
    if (milesTemp >= 1.0){
        miles++;
        milesTemp = milesTemp - 1.0;
    }


    // PRINT DATA TO LCD & SERIAL
    buttonState = digitalRead(ButtonPin);
    if (buttonState == HIGH){
        lastButtonState = buttonState; 
        Serial.print(kph);
        Serial.print("kph  ");

        Serial.print(km);
        Serial.print("km  (");
        Serial.print(kmTemp, 6);
        Serial.println(")  ");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(kph);
        lcd.print("kph");
        lcd.setCursor(0,1);
        lcd.print(km);
        lcd.print("km");
    }
    if (buttonState == LOW){
       lastButtonState = buttonState; 
        Serial.print(mph);
        Serial.print("mph  ");

        Serial.print(miles);
        Serial.print("miles  (");
        Serial.print(milesTemp, 6);
        Serial.println(")");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(mph);
        lcd.print("mph");
        lcd.setCursor(0,1);
        lcd.print(miles);
        lcd.print("miles");
    }


    // SAVE DATA TO SD CARD
    SD.remove("test.txt");
myFile = SD.open("test.txt", FILE_WRITE);
    if (myFile) {
        myFile.print(km);
        myFile.print(" ");//
        myFile.print(kmTemp, 6);
        myFile.print(" ");//
        myFile.print(kmrevs);
        myFile.print(" ");//
        myFile.print(miles);
        myFile.print(" ");//
        myFile.print(milesTemp, 6);
        myFile.print(" ");//
        myFile.print(milesrevs);
        myFile.close();
    }
    else {
        // SD SAVE ERROR
        Serial.println("Save Error");
    }
}





void setup(){
    pinMode(ButtonPin, INPUT_PULLUP);
    pinMode(InterruptPin, INPUT);


    // POWER LCD SCREEN
    //lcd.begin(16,2);
    lcd.init();
    lcd.backlight();


    // LAUNCH SERIAL CONNECTION
    Serial.begin(9600);


    // LOAD DATA FROM SD CARD
    SD.begin(7);
    myFile = SD.open("test.txt", FILE_READ);
    if (myFile) {
       while (myFile.available()) {

       km = myFile.parseInt();
       kmTemp = myFile.parseFloat();
       kmrevs = myFile.parseInt();
       miles = myFile.parseInt();
       milesTemp=myFile.parseFloat();
       milesrevs = myFile.parseInt();

       }
    myFile.close();
    }
    else {
        Serial.println("Read Error");
    }


    // ATTACH INTERRUPTS
     attachInterrupt(digitalPinToInterrupt(2), calculate, RISING);


    // LOAD START SERIAL & LCD SPEED
    buttonState = digitalRead(ButtonPin);
    if (buttonState == LOW){
        // MPH DISPLAYED
        lastButtonState = buttonState;
        Serial.print("0mph  ");

        Serial.print(miles);
        Serial.print("miles  (");
        Serial.print(milesTemp, 6);
        Serial.println(")");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(mph);
        lcd.print("mph");
        lcd.setCursor(0,1);
        lcd.print(miles);
        lcd.print("miles");
    }
    if (buttonState == HIGH){
        // KPH DISPLAYED
        lastButtonState = buttonState;
        Serial.print("0kph  ");

        Serial.print(km);
        Serial.print("km  (");
        Serial.print(kmTemp, 6);
        Serial.println(")  ");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(kph);
        lcd.print("kph");
        lcd.setCursor(0,1);
        lcd.print(km);
        lcd.print("km");
    }
}





void loop(){
    buttonState = digitalRead(ButtonPin);

    // ZERO SPEED ON SLOW ROTATION
    if (riding == true){
    long period = millis() - start;
    if (period == 4150){
    if (buttonState == LOW){
        // MPH DISPLAYED
        lastButtonState = buttonState;
        Serial.print("0mph  ");

        Serial.print(miles);
        Serial.print("miles  (");
        Serial.print(milesTemp, 6);
        Serial.println(")");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(mph);
        lcd.print("mph");
        lcd.setCursor(0,1);
        lcd.print(miles);
        lcd.print("miles");
    }
    if (buttonState == HIGH){
        // KPH DISPLAYED
        lastButtonState = buttonState;
        Serial.print("0kph  ");

        Serial.print(km);
        Serial.print("km  (");
        Serial.print(kmTemp, 6);
        Serial.println(")  ");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(kph);
        lcd.print("kph");
        lcd.setCursor(0,1);
        lcd.print(km);
        lcd.print("km");
    }
    }
    }


    // CHANGE READING WHEN PRESSED
    if (buttonState != lastButtonState){
        long period = millis() - start; 
        if (buttonState == HIGH && period < 4150){
        // KPH DISPLAYED
        lastButtonState = buttonState;
        Serial.print(kph);
        Serial.print("kph  ");

        Serial.print(km);
        Serial.print("km  (");
        Serial.print(kmTemp, 6);
        Serial.println(")  ");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(kph);
        lcd.print("kph");
        lcd.setCursor(0,1);
        lcd.print(km);
        lcd.print("km");
        }
        if (buttonState == HIGH && period > 4150){
        // KPH DISPLAYED
        lastButtonState = buttonState;
        Serial.print("0kph  ");

        Serial.print(km);
        Serial.print("km  (");
        Serial.print(kmTemp, 6);
        Serial.println(")  ");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(kph);
        lcd.print("kph");
        lcd.setCursor(0,1);
        lcd.print(km);
        lcd.print("km");
    }
    if (buttonState == LOW && period < 4150){
        // MPH DISPLAYED
        lastButtonState = buttonState;
        Serial.print(mph);
        Serial.print("mph  ");

        Serial.print(miles);
        Serial.print("miles  (");
        Serial.print(milesTemp, 6);
        Serial.println(")");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(mph);
        lcd.print("mph");
        lcd.setCursor(0,1);
        lcd.print(miles);
        lcd.print("miles");
    }
    if (buttonState == LOW && period > 4150){
        // MPH DISPLAYED
        lastButtonState = buttonState;
        Serial.print("0mph  ");

        Serial.print(miles);
        Serial.print("miles  (");
        Serial.print(milesTemp, 6);
        Serial.println(")");

        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(mph);
        lcd.print("mph");
        lcd.setCursor(0,1);
        lcd.print(miles);
        lcd.print("miles");
    }
    }
}
  • 1
    Its usually a bad idea to do so much in an ISR (interrupt service routine) Those other functions you call from in there may need interrupts to be enabled to operate properly. You should do as little as possible in there (maybe just update the tick count) then do all your other processing in another function called from the main loop. – Chad G May 8 '18 at 20:23
  • using your current configuration, you may miss some ticks, even if it was working, as updating the LCD,printing all that information, and saving it to an SD card probably takes longer then the time in between ticks. It would be much better to write to the SD card is larger 'chunks' of data, to eliminate the overhead of opening and closing the file everytime. – Chad G May 8 '18 at 20:32
  • You are using millis, doing serial prints and SPI transfers inside an ISR, all of which are red flags. I'd re-program it to just switch a boolean variable and push the needed data into globalal variables; then process the values and save them in loop. See arduino.stackexchange.com/questions/22212/… and arduino.stackexchange.com/questions/30968/… – Maximilian Gerhardt May 8 '18 at 20:50
  • Clearly, it looks as though everyone agrees that the problem probably lies in the lengthy ISR....I do remember reading that once upon a time. I think I may reprogram it along the lines you guys have said. I would have been removing all the print() statements anyway as its only for testing, but looks like I'd have a problem regardless. Further, you said to save to SD in bigger chunks......do you mean something like whack all the values into one variable and save that, rather than making 6 tasks? – user4163554 May 9 '18 at 6:42
1

Thanks guys, taking the labour out of the ISR has solved the problem perfectly. Unfortunately, the advice wasn't given as an answer so I'm unable to credit you for it, but appreciate the solutions given. Thanks.

  • Looks like I can't accept my answer either! .....can someone throw a few words in an answer do that I can accept. Cheers. – user4163554 May 9 '18 at 9:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.