1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

(solved)Serial communication+button menu on LCD

Discussion in 'Arduino' started by fezder, Feb 28, 2016.

  1. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    This is teensy 3.2 so perhaps wrong place?
    Right, so I'm making an car computer (I know, there are pre-made and cheaper models out there) by using sparkfun's obd-uart board, teensy 3.2 and i2c 16x2 lcd. Idea is simple: Send AT commands to obd and display result (converted/calculated) on screen, while also updating. The problem currently is that even with that one Serial print,menu system doesn't update conveniently quick & doesn't update, seems it only sends one serial string data in current code. What I'd like it to do, is that it constantly updates screen, and menu could be changed.
    Code I'm currently working on:
    obd-uart board:
    https://www.sparkfun.com/products/9555
    I've managed to get couple live information as real-life data, but there are many stuff hidden in that sketch....
    Ask if there is anything confusing!
    Code (C):

    int const UpButton = 2;
    int const DownButton = 3;
    int UpButtonState;
    int LastUpButtonState;
    int DownButtonState;
    int LastDownButtonState;
    int counter;
    char rxData[20];
    char rxIndex = 0;
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
    String a;

    // Set the LCD address to 0x27 for a 16 chars and 2 line display
    LiquidCrystal_I2C lcd(0x27, 16, 2);

    void setup()
    {
      pinMode (UpButton, INPUT);
      pinMode (DownButton, INPUT);
      lcd.begin();
      lcd.backlight();
      Serial1.begin(9600);
      //ODB_init();


    }

    void loop()
    {
      menuselect();
    }

    void menuselect()
    {
      UpButtonState = digitalRead (UpButton);
      if (UpButtonState != LastUpButtonState)
      {
      lcd.clear();
      if (UpButtonState == HIGH)
      {
      counter++;
      }
      LastUpButtonState = UpButtonState;
      }
      if (counter > 9)
      { (counter = 1);
      }

      DownButtonState = digitalRead (DownButton);
      if (DownButtonState != LastDownButtonState)
      {
      lcd.clear();
      if (DownButtonState == HIGH)
      {
      counter--;
      }
      LastDownButtonState = DownButtonState;
      }
      if (counter == 0)
      {
      (counter = 9);
      }



      switch (counter)  //switch what is displayed depending on number of counter
      {
      case 1:  //speed
      lcd.setCursor(0, 0);
      lcd.print("KM/h:");
      lcd.setCursor(5,0);
      Serial1.print("H");  //just for testing, but even this causes momentary freeze
      a = Serial1.readString(); // read the incoming data as string
      lcd.print(a);
      lcd.setCursor(0, 1);
      lcd.print("<-Clear  RPM->");
      break;
      case 2:  //RPM
      lcd.setCursor(0, 0);
      lcd.print("RPM:");
      lcd.setCursor(0, 1);
      lcd.print("<-Speed  Cool.->");
      break;
      case 3:  //coolant
      lcd.setCursor(0, 0);
      lcd.print("`c");
      lcd.setCursor(0, 1);
      lcd.print("<-RPM  Intake->");
      break;
      case 4:
      lcd.setCursor(0, 0);
      lcd.print("`c");
      lcd.setCursor(0, 1);  //Intake
      lcd.print("<-Coolant  MAF->");
      break;
      case 5:
      lcd.setCursor(0, 0);
      lcd.print("g/sec:");
      lcd.setCursor(0, 1);  //MAF
      lcd.print("<-Intake Pedal->");
      break;
      case 6:
      lcd.setCursor(0, 0);
      lcd.print("%:");
      lcd.setCursor(0, 1);  //Pedal
      lcd.print("<-MAF  Stress->");
      break;
      case 7:
      lcd.setCursor(0, 0);
      lcd.print("%:");
      lcd.setCursor(0, 1);  //Stress
      lcd.print("<-Pedal  RunT.->");
      break;
      case 8:
      lcd.setCursor(0, 0);
      lcd.print("T:");
      lcd.setCursor(0, 1);  //Run Time
      lcd.print("<-Stress Clear->");
      break;
      case 9:
      lcd.setCursor(0, 0);
      lcd.print("Clear codes?");
      lcd.setCursor(0, 1);  //clear
      lcd.print("<-RunT.  Speed->");
      break;
      }
    }

    /*void ODB_init(void)
    {
      //Wait for a little while before sending the reset command to the OBD-II-UART
      delay(2000);
      //Reset the OBD-II-UART
      Serial1.print("ATZ\r");
      //Wait for a bit before starting to send commands after the reset.
      delay(2000);
      OBD_read();
      Serial1.print("ATE0\r");
      OBD_read();
      Serial1.flush();
    }

    void OBD_read(void)
    {
      char c;
      do {
      if (Serial1.available() > 0)
      {
      c = Serial1.read();
      //lcd.print(c);
      if ((c != '>') && (c != '\r') && (c != '\n')) //Keep these out of our buffer
      {
      rxData[rxIndex++] = c; //Add whatever we receive to the buffer
      }
      }
      } while (c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
      rxData[rxIndex++] = '\0';//Converts the array into a string
      rxIndex = 0; //Set this to 0 so next time we call the read we get a "clean buffer"
    }


    int getSpeed(void)
    {
      //Query the OBD-II-UART for the Vehicle rpm
      Serial1.flush();
      Serial1.print("0111\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }*/

     
     
  2. djsfantasi

    djsfantasi Member

    Joined:
    Mar 15, 2011
    Messages:
    161
    Likes:
    21
    Location:
    Metro Boston
    It would be nice if the code was indented to show the code blocks. If you are using the Arduino IDE, go to Tools | Autoformat and it will be done for you.

    Usually when performing a serial read, you check first to see if there are any characters available. The code might be hanging waiting for input that's not coming.
     
    • Informative Informative x 1
  3. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Hmm, I did autoformat. Hanging could bc cause, as when i keep button pressed, then I can change menu while serial read, but not if I press quickly.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland

    here's original code I found which I'm trying to change to my purposes:
    Code (c):


    //Define Serial Ports so I remember which is which
    #include <SoftwareSerial.h>

    //Create an instance of the new soft serial library to control the serial LCD
    //Note, digital pin 3 of the Arduino should be connected to Rx of the serial LCD.

    SoftwareSerial lcd(2,3);


    //Set up ring buffer
    char rxData[20];
    char rxIndex=0;

    void setup()
    {
       lcd.begin(9600);
       Serial.begin(9600);

      //Clear the old data from the LCD.
      lcd.write(254);
      lcd.write(1);
      lcd.print("Temp: ");
      lcd.write(254);
      lcd.write(128+64);
      lcd.print("RPM: ");
     
      ODB_init();
    }

    void loop()
    {


      //Delete any data that may be left over in the serial port.
      Serial.flush();
      //Move the serial cursor to the position where we want the RPM data.
      lcd.print(" ");
      lcd.write(254);
      lcd.write(128 + 69);
      lcd.print(getRPM()); //Print the int returned from getRPM
     
      Serial.flush();
     
      lcd.print(" ");
      lcd.write(254);
      lcd.write(128 + 6);
      lcd.print(getTemp()); //Print the int returned from getTemp
      lcd.print(" C");
     
      delay(200);//wait .5 seconds and grab another reading
     

     
     
     
    }

    void ODB_init(void)
    {
      //Wait for a little while before sending the reset command to the OBD-II-UART
      delay(2000);
      //Reset the OBD-II-UART
      Serial.print("ATZ\r");
      //Wait for a bit before starting to send commands after the reset.
      delay(2000);
      OBD_read();
      Serial.print("ATE0\r");
      OBD_read();
      Serial.flush();  
    }

    int getRPM(void)
    {
      //Query the OBD-II-UART for the Vehicle rpm
      Serial.flush();
      Serial.print("010C\r");
      OBD_read();

      return ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;
    }

    int getTemp(void)
    {
      //Query the OBD-II-UART for the Engine Coolant Temp
      Serial.flush();
      Serial.print("0105\r");
      OBD_read();

      return strtol(&rxData[6],0,16)-40;
    }


    void OBD_read(void)
    {
      char c;
      do{
        if(Serial.available() > 0)
        {
          c = Serial.read();
          //lcd.print(c);
          if((c!= '>') && (c!='\r') && (c!='\n')) //Keep these out of our buffer
          {
            rxData[rxIndex++] = c; //Add whatever we receive to the buffer
          }  
         }    
      }while(c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
      rxData[rxIndex++] = '\0';//Converts the array into a string
      rxIndex=0; //Set this to 0 so next time we call the read we get a "clean buffer"
    }
     
     
  6. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Is there way to make timeout or similar to prevent? I was thinking like this:
    Code (c):

    if(Serial.available() > 0)
    {
    //do stuff
    }
    else
    {
    lcd.setCursor(0,0);
    lcd.print("ERROR");
    }
     
  7. djsfantasi

    djsfantasi Member

    Joined:
    Mar 15, 2011
    Messages:
    161
    Likes:
    21
    Location:
    Metro Boston
    There is a way to check for a timeout during inout. Here is a code bit assuming a timeout of 500ms. Note that this is serial processing; other coding skeletons can be made to allow other processing to occur while waiting for input, but I decided to show this simple example first. Depending on what you want to do in process input, the "break" statement may not be necessary.
    Code (text):


      // It is also possible to code so that other processing
      // can be performed while waiting for input.
      // This is a simple example of an input timeout.

      unsigned long timeout = 0;
      unsigned long waitfor = 500;

      timeout = millis() + waitfor;
      while (timeout > millis()) {
        if (Serial.available()) {
          // process input
          break;
        }
      }
      if (millis() > timeout) {
        // timeout occurred; error?
        // process timeout
      }
      // do more stuff

     
     
  8. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Thanks fantasi, that codes looks simple enought....I made scrolling menu system, so at least partially code works (not yet including your timeout):
    Code (c):

    int const UpButton = 2;
    int const DownButton = 3;
    int UpButtonState;
    int LastUpButtonState;
    int DownButtonState;
    int LastDownButtonState;
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
    LiquidCrystal_I2C lcd(0x27, 16, 2);

    //Set up ring buffer
    char rxData[20];
    char rxIndex = 0;
    String a;
    volatile int counter;
    int t = 1000;
    void setup()
    {

      lcd.begin();
      lcd.backlight();
      Serial.begin(9600);
      ODB_init();
    }

    void loop()
    {




      delay(t);


      lcd.clear();  //speed
      lcd.setCursor(0, 0);
      lcd.print("KM/h:");
      lcd.setCursor(0, 1);
      lcd.print("<-Clear  RPM->");
      lcd.setCursor(5, 0);
      lcd.print(getSpeed());
      delay(t);


      lcd.clear();  //RPM
      lcd.setCursor(0, 0);
      lcd.print("RPM:");
      lcd.setCursor(0, 1);
      lcd.print("<-Speed  Cool.->");
      lcd.setCursor(5, 0);
      lcd.print(getRPM());
      delay(t);


      lcd.clear();  //coolant
      lcd.setCursor(0, 0);
      lcd.print("`c");
      lcd.setCursor(0, 1);
      lcd.print("<-RPM  Intake->");
      lcd.setCursor(5, 0);
      lcd.print(getTemp());
      delay(t);


      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("`c");
      lcd.setCursor(0, 1);  //Intake
      lcd.print("<-Coolant  MAF->");
      lcd.setCursor(5, 0);
      lcd.print(getIntake());
      delay(t);


      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("g/sec:");
      lcd.setCursor(0, 1);  //MAF
      lcd.print("<-Intake Pedal->");
      lcd.setCursor(5, 0);
      lcd.print(getMAF());
      delay(t);


      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("%:");
      lcd.setCursor(0, 1);  //Pedal
      lcd.print("<-MAF  Stress->");
      lcd.setCursor(5, 0);
      lcd.print(getThrottle());
      delay(t);


      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("%:");
      lcd.setCursor(0, 1);  //Stress
      lcd.print("<-Pedal  RunT.->");
      lcd.setCursor(5, 0);
      lcd.print(getStress());
      delay(t);


      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("T:");
      lcd.setCursor(0, 1);  //Run Time
      lcd.print("<-Stress Clear->");
      lcd.setCursor(5, 0);
      lcd.print(getRuntime());
      delay(t);


      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Clear codes?");
      lcd.setCursor(0, 1);  //clear
      lcd.print("<-RunT.  Speed->");

      delay(t);

    }




    void ODB_init(void)
    {
      //Wait for a little while before sending the reset command to the OBD-II-UART
      delay(2000);
      //Reset the OBD-II-UART
      Serial.print("ATZ\r");
      //Wait for a bit before starting to send commands after the reset.
      delay(2000);
      OBD_read();
      Serial.print("ATE0\r");
      OBD_read();
      Serial.flush();
    }

    int getStress(void)
    {
      Serial.flush();
      Serial.print("0104\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }

    int getTemp(void)  //coolant temperature
    {
      Serial.flush();
      Serial.print("0105\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) - 40;
    }

    int getRPM(void)  //RPM
    {
      Serial.flush();
      Serial.print("010C\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16)) / 4;
    }


    int getSpeed(void)  //speed km/h
    {
      Serial.flush();
      Serial.print("010D\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16);
    }

    int getIntake(void)  //intake air temperature
    {
      Serial.flush();
      Serial.print("010F\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) - 40;
    }

    int getMAF(void)  //MAf rate, g/sec
    {
      Serial.flush();
      Serial.print("0110\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16)) / 100;
    }


    int getThrottle(void)  //throttle, %
    {
      Serial.flush();
      Serial.print("0111\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }

    int getRuntime(void)  //Run time
    {
      Serial.print("011F\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16));
    }


    void OBD_read(void)
    {
      char c;
      do {
      if (Serial.available() > 0)
      {
      c = Serial.read();
      //lcd.print(c);
      if ((c != '>') && (c != '\r') && (c != '\n')) //Keep these out of our buffer
      {
      rxData[rxIndex++] = c; //Add whatever we receive to the buffer
      }
      }
      } while (c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
      rxData[rxIndex++] = '\0';//Converts the array into a string
      rxIndex = 0; //Set this to 0 so next time we call the read we get a "clean buffer"
    }
     
     
  9. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Hmm, buddy suggested that every bit of needed information is gathered inside loop in variables, and then menu controls what are shown, opinions?

    ^or then this was that what you meant by what I mean? That sounded confusing.....
     
  10. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    I got it working! will post code later when I get couple small details done, but the idea is that in loop() is menu system that loops all the time, but hardware interrupt controls what menu is used! I read that interrupts can cause serial data to be missed, but since it's constantly re-called, it doesn't matter
     
  11. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Here we go: improvements welcome
    Code (c):

    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
    LiquidCrystal_I2C lcd(0x27, 16, 2);
    char rxData[20];
    char rxIndex = 0;
    String a;
    volatile int counter = 1;
    void setup()
    {
      lcd.begin();
      lcd.backlight();
      //Serial.begin(9600);
      //ODB_init();
      pinMode(2, INPUT);
      pinMode(3, INPUT);
      attachInterrupt(digitalPinToInterrupt(2), MenuUp, RISING);
      attachInterrupt(digitalPinToInterrupt(3), MenuDown, RISING);
    }


    void MenuUp() {
      counter++;
      if (counter > 9)
      {
      counter = 1;
      }
    }


    void MenuDown() {
      counter--;
      if (counter == 0)
      {
      counter = 9;
      }
    }

    void loop()
    {

    delay(1000);
      lcd.clear();

      switch (counter)
      {

      case 1:

      lcd.setCursor(0, 0);
      lcd.print("KM/h:");
      lcd.setCursor(0, 1);
      lcd.print("<-Clear  RPM->");
      lcd.setCursor(5, 0);
     // lcd.print(getSpeed());

      break;

      case 2:
      lcd.setCursor(0, 0);
      lcd.print("RPM:");
      lcd.setCursor(0, 1);
      lcd.print("<-Speed  Cool.->");
      lcd.setCursor(5, 0);
      //lcd.print(getRPM());
      break;

      case 3:

      lcd.setCursor(0, 0);
      lcd.print("`c");
      lcd.setCursor(0, 1);
      lcd.print("<-RPM  Intake->");
      lcd.setCursor(5, 0);
     // lcd.print(getTemp());
      break;

      case 4:
      lcd.setCursor(0, 0);
      lcd.print("`c");
      lcd.setCursor(0, 1);  //Intake
      lcd.print("<-Coolant  MAF->");
      lcd.setCursor(5, 0);
      //lcd.print(getIntake());
      break;

      case 5:

      lcd.setCursor(0, 0);
      lcd.print("g/sec:");
      lcd.setCursor(0, 1);  //MAF
      lcd.print("<-Intake Pedal->");
      lcd.setCursor(5, 0);
     // lcd.print(getMAF());
      break;

      case 6:

      lcd.setCursor(0, 0);
      lcd.print("%:");
      lcd.setCursor(0, 1);  //Pedal
      lcd.print("<-MAF  Stress->");
      lcd.setCursor(5, 0);
     // lcd.print(getThrottle());
      break;

      case 7:
      lcd.setCursor(0, 0);
      lcd.print("%:");
      lcd.setCursor(0, 1);  //Stress
      lcd.print("<-Pedal  RunT.->");
      lcd.setCursor(5, 0);
      //lcd.print(getStress());
      break;

      case 8:
      lcd.setCursor(0, 0);
      lcd.print("T:");
      lcd.setCursor(0, 1);  //Run Time
      lcd.print("<-Stress Clear->");
      lcd.setCursor(5, 0);
      //lcd.print(getRuntime());
      break;

      case 9:
      lcd.setCursor(0, 0);
      lcd.print("Clear codes?");
      lcd.setCursor(0, 1);  //clear
      lcd.print("<-RunT.  Speed->");
      break;
      }

    }




    void ODB_init(void)
    {
      //Wait for a little while before sending the reset command to the OBD-II-UART
      delay(2000);
      //Reset the OBD-II-UART
      Serial.print("ATZ\r");
      //Wait for a bit before starting to send commands after the reset.
      delay(2000);
      OBD_read();
      Serial.print("ATE0\r");
      OBD_read();
      Serial.flush();
    }

    int getStress(void)  //Stress
    {
      Serial.flush();
      Serial.print("0104\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }

    int getTemp(void)  //coolant temperature
    {
      Serial.flush();
      Serial.print("0105\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) - 40;
    }

    int getRPM(void)  //RPM
    {
      Serial.flush();
      Serial.print("010C\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16)) / 4;
    }


    int getSpeed(void)  //speed km/h
    {
      Serial.flush();
      Serial.print("010D\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16);
    }

    int getIntake(void)  //intake air temperature
    {
      Serial.flush();
      Serial.print("010F\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) - 40;
    }

    int getMAF(void)  //MAF rate, g/sec
    {
      Serial.flush();
      Serial.print("0110\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16)) / 100;
    }


    int getThrottle(void)  //throttle, %
    {
      Serial.flush();
      Serial.print("0111\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }

    int getRuntime(void)  //Run time
    {
      Serial.print("011F\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16));
    }


    void OBD_read(void)
    {
      char c;
      do {
      if (Serial.available() > 0)
      {
      c = Serial.read();
      //lcd.print(c);
      if ((c != '>') && (c != '\r') && (c != '\n')) //Keep these out of our buffer
      {
      rxData[rxIndex++] = c; //Add whatever we receive to the buffer
      }
      }
      } while (c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
      rxData[rxIndex++] = '\0';//Converts the array into a string
      rxIndex = 0; //Set this to 0 so next time we call the read we get a "clean buffer"
    }
     
     
  12. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Better code coming u, got rid of interrupts so they don't interrupt Serial reading and cause hanging in case of missed ending characters. And I ended using OLED.
     
  13. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    OK, now I got another problem: use of 7 segment, 4 digit display. I can't figure out how to combine shift registers with hardware serial, or then I again think too complicated....
    following code works well even with potentiomere is i take val from:
    Code (c):

    val=analogRead(A0);
     
    wthout flicker at all. tested with even as low time interval between digits as 1ms, so drive circuit works as intended.
    but, when I toss serial (hardware) in soup, things get messy; only last digit stays on brighter, and rest only flickers, should I use interrupt timer, and if, for segments or serial reading? And I read that interrupts confuse/cause dataloss on serial. I bother with menu later. BTW, I ended using non-interrupt code with booleans for menu system earler, but I decide to make 7 segment & bar graph display instead of OLED; I leave OLED for FFT for audio. I have feeling that this issue is due that because both reading as well as controlling of 7 segments are in loop(), but then again, they were also in LCD and OLED variations
    Code (c):

    int dataPin = 2;  //Define which pins will be used for the Shift Register control
    int latchPin = 3;
    int clockPin = 4;
    int ones = 5;
    int tens = 6;
    int hundreds = 7;
    int thousands = 8;
    unsigned long previousMillis = 0;  // will store last time LED was updated
    const long interval = 1000;  // interval at which to blink (milliseconds)
    int val = 0;
    byte m = 1;
    int t = 1000;
    char rxData[20];
    char rxIndex = 0;
    boolean newData = false;
    void setup()
    {
      Serial.begin(9600);
      ODB_init();
      pinMode(dataPin, OUTPUT);  //Configure each IO Pin
      pinMode(latchPin, OUTPUT);
      pinMode(clockPin, OUTPUT);
      pinMode(ones, OUTPUT);
      pinMode(tens, OUTPUT);
      pinMode(hundreds, OUTPUT);
      pinMode(thousands, OUTPUT);
    }




    void loop()  //G  F  E  D  C  B  A
    {
      val = getThrottle();
      clearSegments();
      digitalWrite(ones, LOW);
      digitalWrite(latchPin, LOW);  //Pull latch LOW to start sending data
      pickNumber((val / m / 1) % 10);  //ones
      digitalWrite(latchPin, HIGH);  //Pull latch HIGH to stop sending data
      digitalWrite(ones, HIGH);
      delayMicroseconds(t);

      clearSegments();
      digitalWrite(tens, LOW);
      digitalWrite(latchPin, LOW);  //Pull latch LOW to start sending data
      pickNumber((val / m / 10) % 10);  //tens
      digitalWrite(latchPin, HIGH);  //Pull latch HIGH to stop sending data
      digitalWrite(tens, HIGH);
      delayMicroseconds(t);

      clearSegments();
      digitalWrite(hundreds, LOW);
      digitalWrite(latchPin, LOW);  //Pull latch LOW to start sending data
      pickNumber((val / m / 100) % 10);  //hundreds
      digitalWrite(latchPin, HIGH);  //Pull latch HIGH to stop sending data
      digitalWrite(hundreds, HIGH);
      delayMicroseconds(t);

      clearSegments();
      digitalWrite(thousands, LOW);
      digitalWrite(latchPin, LOW);  //Pull latch LOW to start sending data
      pickNumber((val / m / 1000) % 10);  //thousands
      digitalWrite(latchPin, HIGH);  //Pull latch HIGH to stop sending data
      digitalWrite(thousands, HIGH);
      delayMicroseconds(t);
    }

    void ODB_init(void)
    {
      //Wait for a little while before sending the reset command to the OBD-II-UART
      delay(2000);
      //Reset the OBD-II-UART
      Serial.print("ATZ\r");
      //Wait for a bit before starting to send commands after the reset.
      delay(2000);
      OBD_read();
      Serial.print("ATE0\r");
      OBD_read();
    }



    void OBD_read(void)
    {
      char c;
      do {
      if (Serial.available() > 0)
      {
      c = Serial.read();
      //display.print(c);
      if ((c != '>') && (c != '\r') && (c != '\n')) //Keep these out of our buffer
      {
      rxData[rxIndex++] = c; //Add whatever we receive to the buffer
      }
      }
      } while (c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
      rxData[rxIndex++] = '\0';//Converts the array into a string
      rxIndex = 0;
      // newData = true;  //set flag for newdata

    }


    int getThrottle(void)  //throttle, %
    {
      Serial.print("0111\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }


    void clearSegments()
    {
      digitalWrite(ones, LOW);
      digitalWrite(tens, LOW);
      digitalWrite(hundreds, LOW);
      digitalWrite(thousands, LOW);
    }


    void pickNumber( int count)  //pick numbers from array, at start of whole code
    {
      switch (count)
      {
      case 1: shiftOut(dataPin, clockPin, MSBFIRST, B00001100); break;  //1
      case 2: shiftOut(dataPin, clockPin, MSBFIRST, B10110110); break;  //2
      case 3: shiftOut(dataPin, clockPin, MSBFIRST, B10011110); break;  //3
      case 4: shiftOut(dataPin, clockPin, MSBFIRST, B11001100); break;  //4
      case 5: shiftOut(dataPin, clockPin, MSBFIRST, B11011010); break;  //5
      case 6: shiftOut(dataPin, clockPin, MSBFIRST, B11111010); break;  //6
      case 7: shiftOut(dataPin, clockPin, MSBFIRST, B00001110); break;  //7
      case 8: shiftOut(dataPin, clockPin, MSBFIRST, B11111110); break;  //8
      case 9: shiftOut(dataPin, clockPin, MSBFIRST, B11011110); break;  //9
      //case 10: shiftOut(dataPin, clockPin, MSBFIRST, B01111110); break;  //9
      default: shiftOut(dataPin, clockPin, MSBFIRST, B01111110); break;  //0
      }
    }
     
     
  14. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Any ideas? Seems interrupts are no-go as even adding nointerrupts-interrupts in obd_read section causes code to hang.....is it posssible to make stuff during serial read?
    Dr_Doggy , you got any ideas?
    This code I have working with OLED:, but even this hangs/waits during serial read but won't matter that much as OLED doesn't wipe during waiting period, but shift registers do.....
    Code (c):

    #include <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>

    #define OLED_RESET 4
    Adafruit_SSD1306 display(OLED_RESET);




    char rxData[20];
    char rxIndex = 0;
    int UpSwitch = 2;
    int DownSwitch = 3;

    byte UpSwitchReading = 0;
    byte DownSwitchReading = 0;

    byte UpcurrentState = 0;
    byte DowncurrentState = 0;

    byte UppreviousState = 0;
    byte  DownpreviousState = 0;
    byte refresh = 2;
    byte counter = 1;
    bool newData = false;
    bool UpSwitchPressed = false;  //initially Switches hasn't been pressed
    bool DownSwitchPressed = false;  //initially Switches hasn't been pressed
    bool SwitchPressed = false;  //initially Switches hasn't been pressed
    int Speed;
    int Temp;
    int RPM;
    int mappedRPM;
    int Intake;
    int Throttle;
    int Stress;

    void setup()
    {
      display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
      display.setTextSize(1);
      display.setTextColor(WHITE);
      Serial.begin(9600);
      ODB_init();
      pinMode(UpSwitch, INPUT);
      pinMode(DownSwitch, INPUT);
      digitalWrite(UpSwitch, HIGH);
      digitalWrite(DownSwitch, HIGH);
    }

    void loop()
    {


      UpSwitchReading = digitalRead(UpSwitch);
      if (UpSwitchReading == LOW)
      {
      UpcurrentState = 1;
      }
      else
      {
      UpcurrentState = 0;
      UpSwitchPressed == false;
      }
      if (UpcurrentState !=  UppreviousState)
      {
      if (UpcurrentState == 1)
      {
      counter++;
      UpSwitchPressed == true;

      if (counter > 8)
      {
      counter = 1;
      }
      }
      }
      UppreviousState = UpcurrentState;




      DownSwitchReading = digitalRead(DownSwitch);
      if (DownSwitchReading == LOW)
      {
      DowncurrentState = 1;
      }
      else
      {
      DowncurrentState = 0;
      DownSwitchPressed == false;
      }
      if (DowncurrentState !=  DownpreviousState)
      {
      if (DowncurrentState == 1)
      {
      counter--;
      DownSwitchPressed == true;
      if (counter == 0)
      {
      counter = 8;
      }
      }
      }
      DownpreviousState = DowncurrentState;



      if (newData == true  && (UpSwitchPressed == false || DownSwitchPressed == false)) //if there is new data gathered, and neither or either-or switches pressed?
      {
      newData = false;
      switch (counter)  //choose correct menu depending on counter value set by pushbuttons
      {

      case 1:
      Speed = getSpeed();
      display.setCursor(0, 0);
      display.print(F("KM/h:"));
      display.setCursor(0, 24);
      display.print(F("<-Clear  RPM->"));
      display.setCursor(32, 0);
      display.print(Speed);
      display.drawRect(0, 8, 127, 8, WHITE);
      display.fillRect(0, 8, Speed, 8, WHITE);
      display.display();
      display.clearDisplay();
      break;

      case 2:
      RPM = getRPM();
      mappedRPM = map(RPM, 0, 8000, 0, 100);
      display.setCursor(0, 0);
      display.print(F("RPM:"));
      display.setCursor(0, 24);
      display.print(F("<-Speed  Cool.->"));
      display.setCursor(24, 0);
      display.print(RPM);
      display.drawRect(0, 8, 100, 8, WHITE);
      display.fillRect(0, 8, mappedRPM, 8, WHITE);
      display.display();
      display.clearDisplay();
      break;

      case 3:
      Temp = getTemp();
      display.setCursor(0, 0);
      display.print(F("c:"));
      display.setCursor(0, 24);
      display.print(F("<-RPM  Intake->"));
      display.setCursor(16, 0);
      display.print(Temp);
      display.drawRect(0, 8, 127, 8, WHITE);
      display.fillRect(0, 8, Temp, 8, WHITE);
      display.display();
      display.clearDisplay();
      break;

      case 4:
      Intake = getIntake();
      display.setCursor(0, 0);
      display.print(F("c:"));
      display.setCursor(0, 24);  //Intake
      display.print(F("<-Coolant  MAF->"));
      display.setCursor(16, 0);
      display.print(Intake);
      display.drawRect(0, 8, 127, 8, WHITE);
      display.fillRect(0, 8, Intake, 8, WHITE);
      display.display();
      display.clearDisplay();
      break;

      case 5:
      display.setCursor(0, 0);
      display.print(F("g/sec:"));
      display.setCursor(0, 24);  //MAF
      display.print(F("<-Intake Pedal->"));
      display.setCursor(40, 0);
      display.print(getMAF());
      display.display();
      display.clearDisplay();
      break;

      case 6:
      Throttle = getThrottle();
      display.setCursor(0, 0);
      display.print(F("%:"));
      display.setCursor(0, 24);  //Pedal
      display.print(F("<-MAF Stress->"));
      display.setCursor(16, 0);
      display.print(Throttle);
      display.drawRect(0, 8, 100, 8, WHITE);
      display.fillRect(0, 8, Throttle, 8, WHITE);
      display.display();
      display.clearDisplay();
      break;

      case 7:
      Stress = getStress();
      display.setCursor(0, 0);
      display.print(F("%:"));
      display.setCursor(0, 24);  //Stress
      display.print(F("<-Pedal  RunT.->"));
      display.setCursor(16, 0);
      display.print(Stress);
      display.drawRect(0, 8, 100, 8, WHITE);
      display.fillRect(0, 8, Stress, 8, WHITE);
      display.display();
      display.clearDisplay();
      break;

      case 8:
      display.setCursor(0, 0);
      display.print(F("T:"));
      display.setCursor(0, 24);  //Run Time
      display.print(F("<-Stress Clear->"));
      display.setCursor(16, 0);
      display.print(getRuntime());
      display.display();
      display.clearDisplay();
      break;
      }
      }
    }






    void ODB_init(void)
    {
      //Wait for a little while before sending the reset command to the OBD-II-UART
      delay(2000);
      //Reset the OBD-II-UART
      Serial.print("ATZ\r");
      //Wait for a bit before starting to send commands after the reset.
      delay(2000);
      OBD_read();
      Serial.print("ATE0\r");
      OBD_read();
    }

    int getStress(void)  //Stress
    {
      Serial.print("0104\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }

    int getTemp(void)  //coolant temperature
    {
      Serial.print("0105\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) - 40;
    }

    int getRPM(void)  //RPM
    {
      Serial.print("010C\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16)) / 4;
    }


    int getSpeed(void)  //speed km/h
    {
      Serial.print("010D\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16);
    }

    int getIntake(void)  //intake air temperature
    {
      Serial.print("010F\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) - 40;
    }

    int getMAF(void)  //MAF rate, g/sec
    {
      Serial.print("0110\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16)) / 100;
    }


    int getThrottle(void)  //throttle, %
    {
      Serial.print("0111\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }

    int getRuntime(void)  //Run time
    {
      Serial.print("011F\r");
      OBD_read();
      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16));
    }


    void OBD_read(void)
    {
      char c;
      do {
      if (Serial.available() > 0)
      {
      c = Serial.read();
      //display.print(c);
      if ((c != '>') && (c != '\r') && (c != '\n')) //Keep these out of our buffer
      {
      rxData[rxIndex++] = c; //Add whatever we receive to the buffer
      }
      }
      } while (c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
      rxData[rxIndex++] = '\0';//Converts the array into a string
      rxIndex = 0;
      newData = true;  //set flag for newdata
    }
     
     
  15. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Dr_Doggy , guess what? I think your matrix code earlier is the solution, I managed to get data on that! :p I'll post code in a few!
     
  16. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Code (c):

    #include "FontMap.h"
    int dataPin = 2; // ic: 14, ser_in Define which pins will be used for the Shift Register control
    int latchPin = 3; // ic:12 silkscreen numbers!
    int clockPin = 4;

    char rxData[20];
    char rxIndex = 0;
    unsigned char displayPointer = 0; // for interrupt use...
    unsigned char buffer1[32]; // buffer for screen
    unsigned char backbuffer[32]; // Spare screen for drawing on
    unsigned char power[8] = {128, 64, 32, 16, 8, 4, 2, 1};
    int val;

    ISR(TIMER1_COMPA_vect) // timer compare interrupt service routine, called every now and then, outside of loop
    {
      if (TIFR2) // Make sure its the timer interrupt.
      {
      setcolumn(displayPointer);  //column scanning
      setdata(buffer1[displayPointer]);
      PORTD = (1 << PORTD3);
      PORTD = (0 << PORTD3);

      //digitalWrite(latchPin ,HIGH);
      //digitalWrite(latchPin , LOW ); // STORECLOCK

      if (++displayPointer == 32)
      { displayPointer = 0;
      } // 32 LED row sections in total
      }
      TIFR2 = 0; // Clear timer 2 interrupt flag
    }

    void setcolumn(unsigned char col)  //loop that takes care of column scanning
    {
      signed char pos;
      for (pos = 32; pos > -1; pos--)
      {
      if (col == pos)
      {
      PORTD = (1 << PORTD2);
      //digitalWrite(dataPin ,HIGH);
      }
      else
      {
      PORTD = (0 << PORTD2);
      //digitalWrite(dataPin ,LOW);
      } // PIN1 DATA pin
      //PORTD=(1<<PORTD4);
      //PORTD=(0<<PORTD4);

      digitalWrite(clockPin , HIGH);
      digitalWrite(clockPin , LOW);
      }
    }



    void setdata(unsigned char dat) {
      unsigned char pos;
      for (pos = 0; pos < 8; pos++)
      {
      if (dat & 128)
      {
      dat -= 128;
      PORTD = (1 << PORTD2);
      //digitalWrite(dataPin ,HIGH);
      }
      else
      {
      PORTD = (0 << PORTD2);
      }
      //digitalWrite(dataPin ,LOW);} // PIN1 DATA pin
      dat = dat * 2;
      digitalWrite(clockPin , HIGH);
      digitalWrite(clockPin , LOW);
      }
    }
    void clr() //clear
    {
      int addr;
      for (addr = 0; addr < 32; addr++) // Empty display buffer
      backbuffer[addr] = 0;
    }

    void Blit() //transfers data between display buffer to screen buffer
    {
      int addr = 0;
      noInterrupts(); // disable all interrupts during setup
      for (addr = 0; addr < 32; addr ++)
      {
      buffer1[addr] = backbuffer[addr]; // put all data from display buffer
      } // to screen buffer
      interrupts(); // enable all interrupts
    }

    void pixel(signed char x, signed char y, int cond)
    {
      unsigned char pix, msk;
      if (x < 0 || y < 0) return; // outside drawing limits negative
      if (x > 31 || y > 7) return; // outside drawing limits positive
      pix = power[y];
      msk = backbuffer[x]; // get exsisting data


      if (cond == 2)
      pix ^= msk; // XOR data to screen
      if (cond == 1)
      {
      pix = ~pix;
      pix &= msk; // AND data to screen
      }
      if (cond == 0)
      pix |= msk; // OR data to screen
      backbuffer[x] = pix; // apply changes
    }

    void charput(unsigned char ch, signed char x, signed char y)
    {
      signed char x1, y1;
      unsigned char disp;
      unsigned char disp2;
      for ( x1 = 0; x1 < 8; x1++) // eight rows
      {
      disp = font[x1 + (ch * 8)];
      for (y1 = 0; y1 < 8; y1++) // eight pixels
      {
      disp2 = disp & power[y1];
      if (disp2 > 0)
      {
      pixel(x + x1, y + y1, 0); // OR the pixel to the display buffer
      }
      }

      }
    }

    void strput(const char* ch, signed char x, signed char y)
    {
      int addr;
      while (*ch )
      {
      charput(*ch++, x, y); // write a string to the display buffer
      x += 7;
      }
    }



    void setup() //setup runs once
    {
      Serial.begin(9600);
      ODB_init();

      signed char cntr;
      noInterrupts(); // disable all interrupts during setup
      DDRD = DDRD | B11111100; //port registers used to set pin directions
      TCCR1A = 0;
      TCCR1B = 0;
      TCNT1 = 0;
      OCR1A = 31; // compare match register 16MHz/256/2Hz -----------------------------------> delay time (lcd flicker/brightness)
      TCCR1B |= (1 << WGM12); // CTC mode, free-running, clear on match
      TCCR1B |= (0 << CS10); // 256 prescaler
      TCCR1B |= (0 << CS11); // 256 prescaler
      TCCR1B |= (1 << CS12); // 256 prescaler
      TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
      interrupts(); // enable all interrupts

    } // End main

    void loop() //just sitting here
    {

      int val = getThrottle();

      clr();
      charput(((val / 1) % 10), 24, 0);
      charput(((val / 10) % 10), 16, 0);
      charput(((val / 100) % 10), 8, 0);
      charput(((val / 1000) % 10), 0, 0);
      Blit();
    }

    void ODB_init(void)  //inital setup for OBD
    {
      delay(2000);  //Wait for a little while before sending the reset command to the OBD-II-UART
      Serial.print("ATZ\r");  //Reset the OBD-II-UART
      delay(2000);  //Wait for a bit before starting to send commands after the reset.
      OBD_read();
      Serial.print("ATE0\r");  //echo off
      OBD_read();
    }

    void OBD_read(void)
    {
      char c;
      do {
      if (Serial.available() > 0)
      {
      c = Serial.read();
      if ((c != '>') && (c != '\r') && (c != '\n')) //Keep these out of our buffer
      {
      rxData[rxIndex++] = c; //Add whatever we receive to the buffer
      }
      }
      } while (c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
      rxData[rxIndex++] = '\0';//Converts the array into a string
      rxIndex = 0;
      // newData = true;  //set flag for newdata
    }


    int getThrottle(void)  //throttle, %
    {
      Serial.print("0111\r");
      OBD_read();
      return strtol(&rxData[6], 0, 16) * 100 / 255;
    }
     
     

Share This Page