DCC++ Hardware - Throttles

KE4NYV Jan 25, 2016

  1. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Brilliant stuff Mike, thank you so much.

    Now working properly on Uno as well.

    Here's the Uno sketch for anyone interested.

    Regards

    Steve.

    Code:
    #include <Arduino.h>
    #include <SoftwareSerial.h>
    
    SoftwareSerial NexSerial(10, 11); // RX, TX on pins 10 and 11. Nextion TX->10  RX->11.
    
    const char ter [3] = {0xff, 0xff, 0xff};//Terminating characters
    int f;
    byte x;
    long lastMillis = 0;
    
    int loco [5] = {
      1024,
      17,
      2820,
      376,
      2016
    };
    
    uint32_t fnbtns [5] = {
      0b0001000100010110010001111110011,
      0b0010001101000100011101000110010,
      0b0000101100100010100101101001010,
      0b0011001110010100001001100011000,
      0b0000101101001001100010001001010
      };
    
    uint32_t test = 0b1101011001101001101001001101011;
    
    void setup() {
      Serial.begin(115200);
      NexSerial.begin(115200);//Make sure your display is set to this baud, or amend if you need it slower.
    
      for (byte j = 0; j < 32; j++) {//Tests the MCU to make sure the XOR function works properly.
        test = test ^ (1UL << j);
        Serial.println(test, BIN);
      }
    }
    
    void setFnButtons() {//Sends 29 strings to the Nextion to set the Function keys accordingly.
      for (int i = 0; i < 29; i ++) {
        int y = (fnbtns[f] >> i) & 1;// i = 0..28.  stores nth(i) bit of fnbtns[] in y.  y becomes 0 or 1.
    
        NexSerial.print("bt");//No library needed here !!!
        NexSerial.print(i);
        NexSerial.print(".val=");
        NexSerial.print(y);
        NexSerial.write(ter, 3);
      }
    }
    
    void setFnBit() {
      fnbtns [f] = fnbtns [f] ^ (1UL << x);
      Serial.println(x);
      if (x < 5) {
        sendFn0_4();
      } else if (x < 9) {
        sendFn5_8();
      } else if (x < 13) {
        sendFn9_12();
      } else if (x < 21) {
        sendFn13_20();
      } else {
        sendFn21_28();
      }
    }
    
    void sendFn0_4() {
      byte mask = 31;
      byte fn = fnbtns[f] & mask;
      Serial.print("Binary = ");
      Serial.println(fn, BIN);
      Serial.print("<f");
      Serial.print(loco[f]);
      Serial.print(" ");
      Serial.print(fn + 128);
      Serial.println(">");
      Serial.println();
    }
    
    void sendFn5_8() {
      int mask = 15;
      int fn = fnbtns[f] & mask << 5;
      fn = fn >> 5;
      Serial.print("Binary = ");
      Serial.println(fn, BIN);
      Serial.print("<f");
      Serial.print(loco[f]);
      Serial.print(" ");
      Serial.print(fn + 176);
      Serial.println(">");
      Serial.println();
    }
    
    void sendFn9_12() {
      int mask = 15;
      int fn = fnbtns[f] & mask << 9;
      fn = fn >> 9;
      Serial.print("Binary = ");
      Serial.println(fn, BIN);
      Serial.print("<f");
      Serial.print(loco[f]);
      Serial.print(" ");
      Serial.print(fn + 160);
      Serial.println(">");
      Serial.println();
    }
    
    void sendFn13_20() {
      uint32_t mask = 255;
      uint32_t fn = fnbtns[f] & mask << 13;
      fn = fn >> 13;
      Serial.print("Binary = ");
      Serial.println(fn, BIN);
      Serial.print("<f");
      Serial.print(loco[f]);
      Serial.print(" ");
      Serial.print("222 ");
      Serial.print(fn);
      Serial.println(">");
      Serial.println();
    }
    
    void sendFn21_28() {
      uint32_t mask = 255;
      uint32_t fn = fnbtns[f] & mask << 21;
      fn = fn >> 21;
      Serial.print("Binary = ");
      Serial.println(fn, BIN);
      Serial.print("<f");
      Serial.print(loco[f]);
      Serial.print(" ");
      Serial.print("223 ");
      Serial.print(fn);
      Serial.println(">");
      Serial.println();
      Serial.println();
    }
    
    void loop() {
    
      unsigned long currentMillis = millis();
    
      if (currentMillis - lastMillis > 2000) {
        lastMillis = currentMillis;
        f++;
        if (f == 5) f = 0;
        setFnButtons();
      }
    
      while (NexSerial.available()) {
        int func = NexSerial.parseInt() - 1;
        if (NexSerial.read() == '>') {
          x = func;
          setFnBit();
        }
      }
    }
     
    Last edited: Sep 3, 2016
    Scott Eric Catalano likes this.
  2. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    @ Dave Bodnar,

    Dave,

    I've just been looking through your latest throttle code iteration.
    And whilst I don't want to interfere with the good work that you're doing, if you would allow me,
    I could suggest some very minor tweaks, that could save over 400 bytes of SRAM. Freeing up around a third of what the sketch is
    using in it's current guise. As you know SRAM is very limited on the little arduino's and this would potentially give you a lot more
    space to develop things further.

    Steve.
     
    Scott Eric Catalano likes this.
  3. esfeld

    esfeld TrainBoard Member

    443
    382
    17
    Dave ..... A little confusion ... you are communicating in the Nextion throttle sketch @9600 does it matter if the sketch was uploaded to the Mini at 115200? All I get from the LCD is the Nextion home screen. I have double checked the Rx/Tx wiring ...... it would seem that the Mini is not communicating with the Nextion LCD.
    Steve F
     
    Scott Eric Catalano likes this.
  4. David Bodnar

    David Bodnar TrainBoard Member

    264
    481
    13
    Steve - suggestions always welcome -please keep in mind that the code is in VERY ROUGH DRAFT form - My goal right now is to get everything working - once that is done I go back and make it (hopefully) pretty and efficient.

    I have been joining programs (the new interrupt driven encoder routine is the latest) together and have not yet sat back to look it all over. That will come soon as all of the functions seem to be behaving!

    thanks in advance for any suggestions

    dave
     
    Scott Eric Catalano likes this.
  5. David Bodnar

    David Bodnar TrainBoard Member

    264
    481
    13
    Steve - I am talking to the Nextion display at 9600 (software serial) and using 115200 (hardware serial) to talk to the DCC++ controller.
    Not sure what you mean by uploaded to the mini at 115200?
    Are you using the same code as mine? Do you have software serial talking to the Nextion @ 9600?

    dave
     
    Scott Eric Catalano likes this.
  6. esfeld

    esfeld TrainBoard Member

    443
    382
    17
    Dave .... Do I have the concept wrong? I loaded your throttle sketch to the Arduino. I was under the impression after reading the sketch that it communicated everything to the Nextion. Are you indicating that the code is uploaded to the Nextion? "Do you have software serial talking to the Nextion @ 9600?" doesn't your code do this?
     
    Scott Eric Catalano likes this.
  7. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Slow down guys,

    Baud rates should match at either end and both are adjustable.
    I suggest you run things at maximum (115200) as it is on my display, I can show you how to do that.
    If you get problems then slow down some.

    Steve.
     
    Scott Eric Catalano likes this.
  8. David Bodnar

    David Bodnar TrainBoard Member

    264
    481
    13
    Steve - not sure we are on the same page.

    First you need to upload the Nextion screens to the display unit --(there is a file link on my web page for the HMI file (make sure you get the 2nd one, version 6) - that can be done either with a USB to Serial interface of by using a microSD card -

    that should give you the screens that you need and have the Nextion return the proper codes to the Arduino

    Once you have the three pages uploaded to the display the two should talk.

    I hope that helps -

    I may have time next week to make a video that shows more of how this all comes together - unfortunately I have not been able to do that yet and the resources on the Internet are a royal pain to decipher!

    dave
     
    Scott Eric Catalano likes this.
  9. esfeld

    esfeld TrainBoard Member

    443
    382
    17
    OK, got it, I thought the sketch formatted the screen on the LCD ....... Steve, do you have an HMI file for you multiple Function Key screens?
    Steve F
     
    Last edited: Sep 3, 2016
    Scott Eric Catalano likes this.
  10. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Dave,

    Is this routine getting incorporated into getActiveAddress (). ?

    Code:
    void getNumber() {   // note that the 2nd digit (after the 65) was changed from page 0 to page 1
      if (message.startsWith ("65 1 a")) {//1226 bytes the old way. Improvement #1 saves 208 bytes of SRAM to 1018 bytes compiled
        key = 0;
      }
      if (message.startsWith ("65 1 1")) {//This whole routine could be compressed as you're doing in getActiveAddress ()
        key = 1;
      }
      if (message.startsWith ("65 1 2")) {
        key = 2;
      }
      if (message.startsWith ("65 1 3")) {
        key = 3;
      }
      if (message.startsWith ("65 1 4")) {
        key = 4;
      }
      if (message.startsWith ("65 1 5")) {
        key = 5;
      }
      if (message.startsWith ("65 1 6")) {
        //Serial.println("six");
        key = 6;
      }
      if (message.startsWith ("65 1 7")) {
        key = 7;
      }
      if (message.startsWith ("65 1 8")) {
        key = 8;
      }
      if (message.startsWith ("65 1 9")) {
        key = 9;
      }
      if (message.startsWith ("65 1 b")) {
        key = 98;
      }
      if (message.startsWith ("65 1 c")) {
        key = 99;
      }
    }
    
    void updateDCC1() {
      ActiveAddress = 0;
      number =  LocoSpeed[ActiveAddress];
      dir = LocoDirection[ActiveAddress];
      //myNextion.sendCommand("n0.font=1");//Improvement # 2 Do this on the display. Saving 70 bytes of SRAM over the 3 routines
      //myNextion.sendCommand("n0.bco=65504");// change background color yellow
      //myNextion.sendCommand("n1.font=0");
      //myNextion.sendCommand("n1.bco=65535");// change background color white
      //myNextion.sendCommand("n2.font=0");
      //myNextion.sendCommand("n2.bco=65535");// change background color white
      updateDCCaddresses();
    }
    
    void updateDCC2() {
      ActiveAddress = 1;
      number =  LocoSpeed[ActiveAddress];
      dir = LocoDirection[ActiveAddress];
      //myNextion.sendCommand("n1.font=1");       // myNextion.setComponentValue("n1", LocoAddress[2]);
      //myNextion.sendCommand("n1.bco=65504");// change background color yellow
      //myNextion.sendCommand("n0.font=0");
      //myNextion.sendCommand("n0.bco=65535");// change background color white
      //myNextion.sendCommand("n2.font=0");
      //myNextion.sendCommand("n2.bco=65535");// change background color white
      updateDCCaddresses();
    
    }
    
    void updateDCC3() {
      ActiveAddress = 2;
      number =  LocoSpeed[ActiveAddress];
      dir = LocoDirection[ActiveAddress];
      //myNextion.sendCommand("n2.font=1");
      //myNextion.sendCommand("n2.bco=65504");// change background color yellow
      //myNextion.sendCommand("n1.font=0");
      //myNextion.sendCommand("n1.bco=65535");// change background color white
      //myNextion.sendCommand("n0.font=0");
      //myNextion.sendCommand("n0.bco=65535");// change background color white
      updateDCCaddresses();
    }
    
    
    
      if (key == -1)
      {
        key = 0;
        LocoFN0to4[ActiveAddress] = B00000000; //clear variables for which functions are set
        LocoFN5to8[ActiveAddress] = B00000000;//A neat little trick . You could set 0to4 as B10000000 and 5to8 as B10110000, the lower bits are still cleared for the actual Key data. 9to12 would be B10100000
        doDCCfunction04();
        doDCCfunction58();
        key = 0;
      }
    
    //Then.......
    
    void doDCCfunction04() {
      Serial.write("<f ");
      Serial.print(LocoAddress[ActiveAddress] );
      Serial.print(" ");
      //int fx = LocoFN0to4[ActiveAddress] + 128;//No need to do this
      Serial.print(LocoFN0to4[ActiveAddress] );//You could store the 128 as part of the binary as in B10000000
      Serial.print(" >");
    }
    void doDCCfunction58() {
      Serial.write("<f ");
      Serial.print(LocoAddress[ActiveAddress] );
      Serial.print(" ");
      //int fx = LocoFN5to8[ActiveAddress] + 176;//No need to do this
      Serial.print(LocoFN5to8[ActiveAddress] );//Again could store the 176 as part of the binary as in B10110000 only the lower 4 bits are key data. This only saves a few clock cycles though.
      Serial.print(" >");
    }
    
    //In void setup...
    
    //myNextion.sendCommand("n0.font=1");//Make this the default setting on the dispay saves 68 bytes.
      //myNextion.sendCommand("n0.bco=65504");// change background color yellow
      //myNextion.sendCommand("n1.font=0");
      //myNextion.sendCommand("n1.bco=65535");// change background color white
      //myNextion.sendCommand("n2.font=0");
      //myNextion.sendCommand("n2.bco=65535");// change background color white
    
    void getActiveAddress() {
      message = myNextion.listen(); //check for message
      if (message != "") {
        char mostSignificantDigit = message.charAt(5);// for function numbers
        String myString;
        myString = mostSignificantDigit;
        FNbutton = myString.toInt();
        FNbutton = FNbutton - 1;
        if (FNbutton == -1) {
          if (myString == "a") FNbutton = 9;
          if (myString == "b") FNbutton = 0;
        }
        if (FNbutton >= 0 && FNbutton <= 9) doFunction();//Again, every character lost by using message.startsWith gains another byte of SRAM. And uses less clock cycles.
        if (message.startsWith("65 2 e")) { // move to page 1
          getLocoAddress();  // get new DCC address #
        }
        if (message.startsWith("65 2 15")) { // DCC1 button page 2
          Serial.println("one"); //Selected DCC address #1 on page 2
            encoderPos=LocoSpeed[0];
          updateDCC1();
        }
        if (message.startsWith("65 2 16")) { // DCC1 button page 2
          Serial.println("two");//Selected DCC address #2 on page 2
            encoderPos=LocoSpeed[1];
          updateDCC2();
        }
        if (message.startsWith("65 2 17")){ // DCC1 button page 2
          Serial.println("three");//Selected DCC address #3 on page 2
            encoderPos=LocoSpeed[2];
          updateDCC3();
        }
      }
    }
    
    int doFunction() {
      key = FNbutton - 1; // convert from ascii value
      if (key <= 4) {
        if (bitRead(LocoFN0to4[ActiveAddress], key) == 0 ) {
          bitWrite(LocoFN0to4[ActiveAddress], key, 1);
        }
        else {
          if (bitRead(LocoFN0to4[ActiveAddress], key) == 1 ) {//This second check can go, just write the 0. Same again for the next block.
            bitWrite(LocoFN0to4[ActiveAddress], key, 0);
          }
        }
        doDCCfunction04();
      }
      if (key >= 5 && key <= 8) {
        key = key - 5;
        if (bitRead(LocoFN5to8[ActiveAddress], key) == 0 ) {
          bitWrite(LocoFN5to8[ActiveAddress], key, 1);
        }
        else {
          if (bitRead(LocoFN5to8[ActiveAddress], key) == 1 ) {
            bitWrite(LocoFN5to8[ActiveAddress], key, 0);
          }
        }
    
     
    Last edited: Sep 3, 2016
    Scott Eric Catalano likes this.
  11. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Well of course but
    a. It's not something you can convert to a .txt for posting.
    b. It's for the 3.5" Enhanced display which is higher resolution.
    c. I encourage everyone to have a go at making for themselves :)

    S.
     
    Scott Eric Catalano likes this.
  12. David Bodnar

    David Bodnar TrainBoard Member

    264
    481
    13
    Not sure I understand the question - it is being called from within the getLocoAddress function

    dave
     
    Scott Eric Catalano likes this.
  13. David Bodnar

    David Bodnar TrainBoard Member

    264
    481
    13
    Steve - the default speed on the Nextion is 9600 and on the DCC++ controller it is 115200 - to keep things simple I try to stick with the default speed.

    On the Nextion going from 9600 to 115200 would make little difference since it is only moving short text strings.

    dave
     
    Scott Eric Catalano likes this.
  14. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Hmm. That's debatable when you're doing stuff like my function key refresh routine. 29 strings get sent in very short order.

    See the above code post again. I've done an edit to show the improvements.

    S.

    Update: More stuff added to the above
     
    Last edited: Sep 3, 2016
    Scott Eric Catalano likes this.
  15. esfeld

    esfeld TrainBoard Member

    443
    382
    17
    UK Steve ...... I understand ........ since I am working on a 3.2" I will see if I can work it out myself ..... meanwhile Daves looks just fine and works well.
    Thank you
    Steve F
     
    Scott Eric Catalano likes this.
  16. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Great to hear you got Dave's working.
    Yes indeed, if I could get the file too you, you would find my layout does not fit so inevitably you'd have to do it all again.
    It's an odd bit of software but you'll get there I'm sure. Plus you have licence to do as you please, which is more fun.

    S.
     
    Scott Eric Catalano likes this.
  17. David Bodnar

    David Bodnar TrainBoard Member

    264
    481
    13
    Steve- sounds like you got it working - good deal!
    Please note that the Arduino code still has a long way to go - there are a number of minor bugs that I am working on

    dave
     
    Scott Eric Catalano likes this.
  18. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Out of interest, which method are you guys using to get the .tft file onto the display.

    I use the sd card method, very fast.

    S.
     
    Scott Eric Catalano likes this.
  19. David Bodnar

    David Bodnar TrainBoard Member

    264
    481
    13
    I have used the sd card and serial - both work, sd is much faster

    dave
     
    Scott Eric Catalano likes this.
  20. esfeld

    esfeld TrainBoard Member

    443
    382
    17
    SD card ..... just simpler and easier.
    Steve F
     
    Scott Eric Catalano likes this.

Share This Page