/*
d. bodnar revised 9-06-2016 V3.12
Steve's mod
*/
#include "Arduino.h"
#include <SoftwareSerial.h>
#include <Nextion.h>
#include<EEPROM.h>
SoftwareSerial nextion(4, 5);// Nextion TX to pin 4 and RX to pin 5 of Arduino
Nextion myNextion(nextion, 9600); //create a Nextion object named myNextion using the nextion serial port @ 9600bps
String message;
int debug = 1; // set to 1 to show debug info on serial port - may cause issues with DCC++ depending on what is sent
int ActiveAddress = 0; // make address1 active
int counter = 0;
byte Key;
char key ;
unsigned long currentTime;
unsigned long lastTime;
unsigned long DCCtime;
unsigned long DCCcurrentTime;
const int buttonPin = 8; // the number of the pushbutton pin on encoder
const int ledPin = 13; // the number of the LED pin
boolean encA;
boolean encB;
boolean lastA = false;
unsigned long number = 0;
int lowest = 0;
unsigned long highest = 120;//126;
long changeamnt = 1;
int jumpamnt = 10;
int scaled = 0;
int encoderChange = 0; // flag to show encoder changed
byte Fx = 0;
int maxLocos = 3;// number of loco addresses
int LocoDirection[3] = {1, 1, 1};
int LocoSpeed[3] = {0, 0, 0};
byte LocoFN0to4[3] = {128, 128, 128};
byte LocoFN5to8[3] = {176, 176, 176};
byte Locofn9to12[4];// 9-12 not yet implemented
int xxxxx = 0;
int old_speed = 0;
int ZeroSpeedFlag = 0;
int z = 0;
int powerTemp = 0;
int i = 0;
char VersionNum[] = "3.12";
int DCCflag = 0;
boolean ledPin_state;
unsigned long previousMillis = 0; // will store last time LED was updated
unsigned long currentMillis = millis();
const long interval = 300;
int saveAddress = 0;
int LocoAddress[4] = {000, 1830, 3, 456};
int FNbutton = 0;
volatile byte aFlag = 0;
volatile byte bFlag = 0;
volatile byte encoderPos = 0;
volatile byte oldEncPos = 0;
volatile byte reading = 0;
int old_pos = encoderPos;
int dir = 0; // direction
int buttonState = 0;
unsigned long interruptTime;
int FwdRev = 0; // 0 for backwards, 1 for forwards
static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
int directionFlag = 0;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
pinMode(buttonPin, INPUT_PULLUP);
attachInterrupt(0, PinA, RISING); //interrupt on PinA, rising edge signal & executing the "PinA" Interrupt Service Routine (below)
attachInterrupt(1, PinB, RISING); // same for B
pinMode(ledPin, OUTPUT);
Serial.begin (115200);
Serial.print("9-05-2016 version ");
for (int i = 0; i < 4; i++) {
Serial.print(VersionNum[i]);
}
Serial.print("<0>");// power off to DCC++ unit
digitalWrite(ledPin, HIGH); // Turn the LED on.
ledPin_state = digitalRead(ledPin); // Store initial LED state. HIGH when LED is on.
myNextion.init(); // send the initialization commands for Page 0
currentTime = millis();
lastTime = currentTime;
myNextion.sendCommand("page 0" );
myNextion.setComponentText("Version", "3.12");
Serial.println("Version 3.12");
delay(2000); //show title screen for minimum of 2 seconds
myNextion.sendCommand("page 2" );
dir = 1; //forward
//myNextion.setComponentText("forward", ">>>>");//Now done as default on display
//myNextion.setComponentText("reverse", " ");
getAddresses(); // read from EEPROM
//myNextion.sendCommand("n0.font=1");//Now done as default on display
//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();
makeFWD();
} // END SETUP
void loop() {
encoderInterrupt(); // check rotary encoder
DCCcurrentTime = millis(); //send DCC every 30000 ms
if (DCCcurrentTime - DCCtime >= 30000 | DCCflag == 1) {
DCCflag = 0;
DCCtime = DCCcurrentTime;
doDCC();
}
checkButton(); // check for change in direction
getActiveAddress(); // check for DCC address change
} // *** END LOOP ***
void encoderInterrupt() {
currentTime = millis();
if (oldEncPos != encoderPos) {
if ((currentTime - interruptTime) >= 100) {
}
else { // if turned rapidly increment another 4 (total of 5 per turn)
if (FwdRev == 0) {
if (encoderPos >= 4) {
encoderPos = encoderPos - 4;
}
}
else {
if (encoderPos <= 115) {
encoderPos = encoderPos + 4;
}
}
}
interruptTime = millis();
int x = old_pos - encoderPos;
//Serial.print(encoderPos);
//Serial.print("\t");
//Serial.println(FwdRev);
oldEncPos = encoderPos;
scaled = encoderPos * 100;
scaled = scaled / highest;
myNextion.setComponentValue("throttle", scaled);
myNextion.setComponentValue("throttleNum", encoderPos);
LocoSpeed[ActiveAddress] = encoderPos;
doDCC();
}
}
void checkButton() { // Checks button on encoder to change direction
buttonState = digitalRead(buttonPin);
directionFlag = 0;
currentMillis = millis();
if (buttonState == LOW) {
do {
if (millis() - currentMillis > 200) {
myNextion.setComponentValue("throttle", (millis() - currentMillis) / 10);
}
buttonState = digitalRead(buttonPin);
if (millis() - currentMillis >= 1000) {
// Serial.println("MORE THAN 1000 MILLIS");
// Serial.println("button held");
LocoSpeed[ActiveAddress] = 0;
encoderPos = 0;
myNextion.setComponentValue("throttle", 0);
myNextion.setComponentValue("throttleNum", 0);
directionFlag = 1;
}
}
while (buttonState == LOW);
if (directionFlag == 0) {
directionFlag = 0;
dir = !dir;
if (dir) {
digitalWrite(ledPin, HIGH);
makeFWD();
}
else {
digitalWrite(ledPin, LOW);
makeBKW();
}
currentMillis = millis();
LocoDirection[ActiveAddress] = dir;
doDCC();
}
}
}
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();
if (message.startsWith("65 2 e")) { // move to page 1
getLocoAddress(); // get new DCC address #
}
if (message.startsWith("AllStop")) { // DCC1 button page 2
Serial.println("STOP STOP STOP"); //Selected DCC address #1 on page 2
Serial.print("<0>");// power off to DCC++ unit
LocoSpeed[0] = 0;
LocoSpeed[1] = 0;
LocoSpeed[2] = 0;
encoderPos = 0;
myNextion.setComponentValue("throttle", 0);
myNextion.setComponentValue("throttleNum", 0);
dir = 1; //forward
makeFWD();
}
if (message.startsWith("l1")) { // DCC1 button page 2
Serial.println("one"); //Selected DCC address #1 on page 2
encoderPos = LocoSpeed[0];
updateDCC1();
}
if (message.startsWith("l2")) { // DCC1 button page 2
Serial.println("two");//Selected DCC address #2 on page 2
encoderPos = LocoSpeed[1];
updateDCC2();
}
if (message.startsWith("l3")) { // DCC1 button page 2
Serial.println("three");//Selected DCC address #3 on page 2
encoderPos = LocoSpeed[2];
updateDCC3();
}
}
}
//START DO FUNCTION BUTTONS
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 ) {
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);
//}
}
doDCCfunction58();
}
if (key == -1)
{
key = 0;
LocoFN0to4[ActiveAddress] = B10000000; //clear variables for which functions are set
LocoFN5to8[ActiveAddress] = B10110000;
doDCCfunction04();
doDCCfunction58();
key = 0;
}
key = 0;
String temp = "0000" + String(LocoFN0to4[ActiveAddress], BIN); // pad with leading zeros
int tlen = temp.length() - 5;
Serial.println("");
Serial.println(temp.substring(tlen));
String FN1 = temp.substring(tlen);
temp = "000" + String(LocoFN5to8[ActiveAddress], BIN);
tlen = temp.length() - 4;
FN1 = temp.substring(tlen) + " " + FN1;
myNextion.setComponentText("FunctionBinary", FN1);
}//END DO FUNCTION BUTTONS
void doDCC() {
Serial.print("<1>");
Serial.print("<t1 ");
Serial.print(LocoAddress[ActiveAddress] );//locoID);
Serial.print(" ");
Serial.print(LocoSpeed[ActiveAddress] );
Serial.print(" ");
Serial.print(LocoDirection[ActiveAddress] );
Serial.println(">");
number = LocoSpeed[ActiveAddress];
scaled = number * 100;
scaled = scaled / highest;
myNextion.setComponentValue("throttle", scaled);
myNextion.setComponentValue("throttleNum", number);
if (dir) {
makeFWD();
}
else {
makeBKW();
}
}
void doDCCfunction04() {
Serial.write("<f ");
Serial.print(LocoAddress[ActiveAddress] );
Serial.print(" ");
//int fx = LocoFN0to4[ActiveAddress] + 128;
Serial.print(LocoFN0to4[ActiveAddress]);
Serial.print(" >");
}
void doDCCfunction58() {
Serial.write("<f ");
Serial.print(LocoAddress[ActiveAddress] );
Serial.print(" ");
//int fx = LocoFN5to8[ActiveAddress] + 176;
Serial.print(LocoFN5to8[ActiveAddress]);
Serial.print(" >");
}
void getLocoAddress() {// get new DCC address # on Nextion page #1
myNextion.sendCommand("page 1" );
myNextion.setComponentValue("AddrNew", ActiveAddress + 1);
myNextion.setComponentValue("DCCnew", 0);
saveAddress = LocoAddress[ActiveAddress];
int total = 0;
counter = 0;
do {
do {
message = myNextion.listen(); //check for message
if (message != "") {
}
}
while (message == "");
getNumber();
if (key == 98 ) { //"done" button hit - less than 4 digits
break;// exit routine if # button pressed - ABORT new address
}
if (key == 99) {
break;
}
counter++;
int number = key;
total = total * 10 + number;
if (total == 0) { // print multiple zeros for leading zero number
for (int tempx = 1; tempx <= counter; tempx++) {
}
}
myNextion.setComponentValue("DCCnew", total);
myNextion.setComponentValue("j0", total);
}
while (counter <= 3); // collect exactly 4 digits
LocoAddress[ActiveAddress] = total;
total = 0;
counter = 0;
myNextion.sendCommand("page 2" );
if (key == 99) {
LocoAddress[ActiveAddress] = saveAddress;
}
switch (ActiveAddress) {
case 0:
updateDCC1();
break;
case 1:
updateDCC2();
break;
default:
updateDCC3();
}
saveAddresses();
}
void getAddresses() { // from EEPROM
int xxx = 0;
for (int xyz = 0; xyz <= maxLocos - 1; xyz++) {
LocoAddress[xyz] = EEPROM.read(xyz * 2) * 256;
LocoAddress[xyz] = LocoAddress[xyz] + EEPROM.read(xyz * 2 + 1);
if (LocoAddress[xyz] >= 10000) LocoAddress[xyz] = 3;
}
maxLocos = EEPROM.read(20);
if (maxLocos >= 4) maxLocos = 4;
}
void saveAddresses() { // TO EEPROM
int xxx = 0;
for (int xyz = 0; xyz <= maxLocos ; xyz++) {
xxx = LocoAddress[xyz] / 256;
EEPROM.write(xyz * 2, xxx);
xxx = LocoAddress[xyz] - (xxx * 256);
EEPROM.write(xyz * 2 + 1, xxx);
}
EEPROM.write(20, maxLocos);
}
// FROM NEXTION 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")) {
key = 0;
}
if (message.startsWith("65 1 1")) {
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 makeFWD() {
myNextion.setComponentText("forward", ">>>>");
myNextion.setComponentText("reverse", " ");
myNextion.setComponentValue("throttle", scaled);
myNextion.setComponentValue("throttleNum", number);
}
void makeBKW() {
myNextion.setComponentText("forward", " ");
myNextion.setComponentText("reverse", "<<<<");
myNextion.setComponentValue("throttle", scaled);
myNextion.setComponentValue("throttleNum", number);
}
void updateDCCaddresses() {
String stringOne = String(LocoAddress[0]);
String stringTwo = String(LocoAddress[1]);
String stringThree = String(LocoAddress[2]);
myNextion.setComponentText("bt0", stringOne);//myNextion.setComponentValue("n0", LocoAddress[0]); Hope this converts
myNextion.setComponentText("bt1", stringTwo);//myNextion.setComponentValue("n1", LocoAddress[1]);
myNextion.setComponentText("bt2", stringThree);//myNextion.setComponentValue("n2", LocoAddress[2]);
DCCflag = 1;
}
void updateDCC1() {
ActiveAddress = 0;
number = LocoSpeed[ActiveAddress];
dir = LocoDirection[ActiveAddress];
//myNextion.sendCommand("n0.font=1");//Done on display
//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");//Done on display // 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");//Done on display
//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();
}
void PinA() {
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
if (reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
if (encoderPos >= 1) {
encoderPos --;
}//decrement the encoder's position count
FwdRev = 0;
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
}
else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
sei(); //restart interrupts
}
void PinB() {
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
if (encoderPos <= 119) {
encoderPos ++;
} //increment the encoder's position count
FwdRev = 1;
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
}
else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
sei(); //restart interrupts
}
|