/*
d. bodnar revised 6-16-2016
Sketch different de souris_encodeur20 pour la simulation
*/
#include "Arduino.h"
int buttonPin = A3; // button on rotary
static int pinA = 2; // Rotary Encoder
static int pinB = 3; // Rotary Encoder
volatile byte aFlag = 0;
volatile byte bFlag = 0;
volatile byte encoderPos = 0;
volatile byte oldEncPos = 0;
volatile byte reading = 0;
int buttonState = 0;
int encoderChange = 0; // flag to show encoder changed
#include<EEPROM.h>
char key ;
int maxLocos = 4;// number of loco addresses
int LocoAddress[4] = {1830, 3, 999, 4444};
int LocoDirection[4] = {1, 1, 1, 1};
int LocoSpeed[4] = {0, 0, 0, 0};
byte LocoFN0to4[4];
byte LocoFN5to8[4];
int counter = 0;
int counter2 = 0;
int adc_key_in = 500; // 0 pour souris_encodeur20
byte drap_acc = 0;
int Acc = 0;
int SAcc = 0;
byte etat_c = 0;
int ZeroSpeedFlag = 0;
int ActiveAddress = 0; // make address1 active
#include <LiquidCrystal.h>
const int rs = 10, en = 11, d4 = 12, d5 = 13, d6 = A0, d7 = A1;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
char VersionNum[] = "2.6a"; ///////////////////////// //////////////////////VERSION HERE///////
#include <Keypad.h>
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {A4, A2, 4, 5}; //{8,7,6,5 }; //connect to the row pinouts of the keypad
byte colPins[COLS] = {6, 7, 8, 9}; // {11,10,9}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
int debug = 0; // set to 1 to show debug info on serial port - may cause issues with DCC++ depending on what is sent
void setup() {
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); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
attachInterrupt(1, PinB, RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
lcd.begin (16, 2); // LCD is 16 characters x 2 lines
lcd.home (); // go home
Serial.begin (115200);
getAddresses(); // read eeprom
lcd.setCursor(0, 0);
lcd.print("Hold button to");
lcd.setCursor(0, 1);
lcd.print("vary MaxLocos ");
lcd.print(maxLocos);
delay(1000);
buttonState = digitalRead(buttonPin);
if (buttonState == LOW) {
getNumberOfLocos();}
lcd.clear();
lcd.print("DCC++ Throttle");
lcd.setCursor(0, 1);
lcd.print("6-11-16 v");
for (int i = 0; i < 4; i++) {
lcd.print(VersionNum[i]);}
Serial.print("6-11-2016 version ");
for (int i = 0; i < 4; i++) {
Serial.print(VersionNum[i]);
}
if (debug == 1) Serial.println("");
Serial.print("<0>");// power off to DCC++ unit
delay(1500);
lcd.clear();
doMainLCD();
} // END SETUP
void getNumberOfLocos() {
//maxLocos = 4;// number of loco addresses
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Loco # now = ");
lcd.print(maxLocos);
lcd.setCursor(0, 1);
lcd.print("new # (1-4) ");
do {
key = keypad.getKey();
if (debug == 1) Serial.print("key = ");
if (debug == 1) Serial.println(key);
key = key - 48 - 1; // convert from ascii value
if (key == 1 || key == 2 || key == 3 || key == 4) { // 1-4
maxLocos = key + 1;
if (debug == 1) Serial.print("new maxLocos = ");
if (debug == 1) Serial.println(maxLocos);
lcd.print(maxLocos);
delay(1400);
saveAddresses();
break;
}
} while (key != 1 || key != 2 || key != 3 || key != 4);
}
void loop() {
adc_key_in = analogRead(5);
key = keypad.getKey();
if ((key == '*') && (drap_acc == 0)) { // *
all2ZeroSpeeed();
getLocoAddress();
key = 0;}
if ((key == 'D') && (drap_acc ==0)) { // D = arret centrale
Serial.print("<0>");
lcd.setCursor (13, 1);
lcd.print("OFF");
key = 0;
etat_c = 0;}
if ((key == 'C') && (drap_acc ==0)){ // C = marche centrale
Serial.print("<1>");
lcd.setCursor (13, 1);
lcd.print("ON ");
key = 0;
etat_c = 1;}
if ((adc_key_in == 1023) && (drap_acc == 1)){ //if ((adc_key_in < 250) && (drap_acc == 1)){ (pour souris_encodeur20)
lcd.clear();
drap_acc = 0;
doMainLCD();}
if (adc_key_in == 0){ //if (adc_key_in < 50){ (pour souris_encodeur20)
getAccAddress();
drap_acc = 1;
// lcd.setCursor (13, 1);
// if (etat_c == 0)lcd.print("OFF");
// else lcd.print("ON ");
}
if (key == 'A' && drap_acc == 1) { // A = accessoire activer
Serial.print("<a ");
Serial.print(Acc);
Serial.print(" ");
Serial.print(SAcc);
Serial.print(" 1>");
lcd.setCursor (5, 1);
lcd.print("Activer ");
key = 0;}
if (key == 'B' && drap_acc == 1) { // B = accessoire déactiver
Serial.print("<a ");
Serial.print(Acc);
Serial.print(" ");
Serial.print(SAcc);
Serial.print(" 0>");
lcd.setCursor (5, 1);
lcd.print("Deactiver");
key = 0;}
//NEW ROUTINE USING ROTARY ENCODER FOR SPEED AND BUTTON ON IT FOR DIRECTION
if (drap_acc == 0) {
getEncoder();
if (encoderChange == 1) {
encoderChange = 0;
LocoSpeed[ActiveAddress] = encoderPos;
doDCC();
doMainLCD();}
}
buttonState = digitalRead(buttonPin);
if ((buttonState == LOW) && (drap_acc == 0)) {
delay(50);
buttonState = digitalRead(buttonPin); // check a 2nd time to be sure
if (buttonState == LOW) {// check a 2nd time to be sure
LocoDirection[ActiveAddress] = !LocoDirection[ActiveAddress];
doDCC();
doMainLCD();
do { // routine to stay here till button released & not toggle direction
buttonState = digitalRead(buttonPin);
} while (buttonState == LOW);
}
}
if ((key == '#') && (drap_acc == 0)) { // #
ActiveAddress++;
if (ActiveAddress >= maxLocos) ActiveAddress = 0;
doMainLCD();
delay(200);
key = 0;
encoderPos = LocoSpeed[ActiveAddress];
doDCC();}
if (key != '*' && key != '#' && key >= '0' && (key != 'A' && drap_acc ==0)&& (key != 'B' && drap_acc == 0)) {
doFunction();}
} //END LOOP
void getEncoder() {
if (oldEncPos != encoderPos) {
encoderPos = constrain(encoderPos, 0, 126);
oldEncPos = encoderPos;
encoderChange = 1; // flag to show a change took place
}
}//END GET ENCODER ROUTINE
//START DO FUNCTION BUTTONS
int doFunction() {
key = key - 48 ; // convert from ascii value
if (debug == 1) Serial.print("got a keypad button ");
if (debug == 1) Serial.println(key, DEC);
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();
Serial.print(LocoFN0to4[ActiveAddress], BIN);
if (debug == 1) Serial.println(" LocoFN0to4[ActiveAddress] d ");
if (debug == 1) Serial.print(LocoFN0to4[ActiveAddress], DEC);
if (debug == 1) Serial.println(" LocoFN0to4[ActiveAddress]");
}
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 (debug == 1) Serial.print(LocoFN5to8[ActiveAddress], BIN);
if (debug == 1) Serial.println(" LocoFN5to8[ActiveAddress] d ");
if (debug == 1) Serial.print(LocoFN5to8[ActiveAddress], DEC);
if (debug == 1) Serial.println(" LocoFN5to8[ActiveAddress]");
}
if (key == -1){
lcd.setCursor (14, 1); // go to end of 2nd line
lcd.print(key, DEC);
key = 0;
LocoFN0to4[ActiveAddress] = B00000000; //clear variables for which functions are set
LocoFN5to8[ActiveAddress] = B00000000;
doDCCfunction04();
doDCCfunction58();
delay(500);
key = 0;}
key = 0;
doMainLCD();}//END DO FUNCTION BUTTONS
void showFirstLine() {
if (debug == 1) Serial.println(" ");
lcd.setCursor(0, 0);
lcd.print(" ");// clear
lcd.setCursor(0, 0);
lcd.print("L");
lcd.print(ActiveAddress + 1);
lcd.print(" = ");
lcd.print(LocoAddress[ActiveAddress]);
for (int zzz = 0; zzz <= 3; zzz++) {
if (debug == 1) Serial.print("add # ");
if (debug == 1) Serial.print(zzz + 1);
if (debug == 1) Serial.print(" ");
if (debug == 1) Serial.println(LocoAddress[zzz]);}
}
void getLocoAddress() {
int saveAddress = LocoAddress[ActiveAddress];
Serial.print("<0>");// power off to DCC++ unit
int total = 0;
counter = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Set Dcc Addr # ");
lcd.print(ActiveAddress + 1);
if (debug == 1) Serial.println(" @ top");
do {
key = keypad.getKey();
if (key == '#' | key == '*' | key == 'A' | key == 'B' | key == 'C' | key == 'D') { //abort when either is hit
break;// exit routine if # button pressed - ABORT new address
}
if (key) {
counter++;
int number = key - 48;
total = total * 10 + number;
if (debug == 1) Serial.print("TOTAL = ");
if (debug == 1) Serial.println(total);
lcd.setCursor(0, 1);
if (total == 0) { // print multiple zeros for leading zero number
for (int tempx = 1; tempx <= counter; tempx++) {
lcd.print("0");}
}
else lcd.print(total);
if (debug == 1) Serial.print("Counter = ");
if (debug == 1) Serial.print(counter);
if (debug == 1) Serial.print(" key = ");
if (debug == 1) Serial.print(key);
if (debug == 1) Serial.print(" val = ");
if (debug == 1) Serial.println(number);
}
}
while (counter <= 3); // collect exactly 4 digits
LocoAddress[ActiveAddress] = total;
saveAddresses();
lcd.clear();
doMainLCD();
}
void getAccAddress() {
int total2 = 0;
counter2 = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Adr. Accessoire ");
do {
key = keypad.getKey();
if (key >= 48 && key <= 57) {
counter2++;
int number2 = key - 48;
total2 = total2 * 10 + number2;
lcd.setCursor(0, 1);
if (total2 == 0) {
for (int tempx2 = 1; tempx2 <= counter2; tempx2++) {
lcd.print("0");}
}
else lcd.print(total2);
}
}
while (counter2 <= 3);
Acc = ((total2+3)/4);
SAcc = ((total2+3)%4);
lcd.setCursor (5, 1);
lcd.print("Deactiver");}
void doDCC() {
if (debug == 1) Serial.println(LocoDirection[ActiveAddress] );
Serial.print("<t1 ");
Serial.print(LocoAddress[ActiveAddress] );//locoID);
Serial.print(" ");
Serial.print(LocoSpeed[ActiveAddress] );
Serial.print(" ");
Serial.print(LocoDirection[ActiveAddress] );
Serial.println(">");}
void doDCCfunction04() {
Serial.write("<f ");
Serial.print(LocoAddress[ActiveAddress] );
Serial.print(" ");
int fx = LocoFN0to4[ActiveAddress] + 128;
Serial.print(fx);
Serial.print(" >");}
void doDCCfunction58() {
Serial.write("<f ");
Serial.print(LocoAddress[ActiveAddress] );
Serial.print(" ");
int fx = LocoFN5to8[ActiveAddress] + 176;
Serial.print(fx);
Serial.print(" >");}
void all2ZeroSpeeed() { // set flag to 1 to stop, set to 0 to restore
for (int tempx = 0; tempx <= maxLocos; tempx++) {
Serial.print("<t1 ");
Serial.print(LocoAddress[tempx] );//locoID);
Serial.print(" ");
if (ZeroSpeedFlag == 1) {
Serial.print(0);//LocoSpeed[0] );
}
else Serial.print(LocoSpeed[0] );
Serial.print(" ");
Serial.print(LocoDirection[1] );
Serial.write(">");
}
}
void getAddresses() {
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;
if (debug == 1) Serial.println(" ");
if (debug == 1) Serial.print("loco = ");
if (debug == 1) Serial.print(LocoAddress[xyz]);
if (debug == 1) Serial.print(" address# = ");
if (debug == 1) Serial.print(xyz + 1);}
if (debug == 1) Serial.println(" ");
maxLocos = EEPROM.read(20);
if (debug == 1) Serial.print("EEPROM maxLocos = ");
if (debug == 1) Serial.println(maxLocos);
if (maxLocos >= 4) maxLocos = 4;
}
void saveAddresses() {
int xxx = 0;
for (int xyz = 0; xyz <= maxLocos - 1; xyz++) {
xxx = LocoAddress[xyz] / 256;
if (debug == 1) Serial.println(" ");
if (debug == 1) Serial.print("loco = ");
if (debug == 1) Serial.print(LocoAddress[xyz]);
if (debug == 1) Serial.print(" address# = ");
if (debug == 1) Serial.print(xyz);
if (debug == 1) Serial.print(" msb ");
if (debug == 1) Serial.print(xxx);
if (debug == 1) Serial.print(" writing to ");
if (debug == 1) Serial.print(xyz * 2);
if (debug == 1) Serial.print(" and ");
if (debug == 1) Serial.print(xyz * 2 + 1);
EEPROM.write(xyz * 2, xxx);
xxx = LocoAddress[xyz] - (xxx * 256);
if (debug == 1) Serial.print(" lsb ");
if (debug == 1) Serial.print(xxx);
EEPROM.write(xyz * 2 + 1, xxx);
}
EEPROM.write(20, maxLocos);
}
void doMainLCD() {
lcd.setCursor(0, 0);
lcd.print("S=");
lcd.print(LocoSpeed[ActiveAddress], DEC);
lcd.print(" ");
lcd.setCursor(5 , 0);
if (LocoDirection[ActiveAddress] == 1 ) {
lcd.print(" > ");}
else {
lcd.print(" < ");}
lcd.setCursor(8, 0);
lcd.print("L=");
if (LocoAddress[ActiveAddress] <= 9) {
lcd.print("0"); // add leading zero for single digit addresses
}
lcd.print(LocoAddress[ActiveAddress] , DEC);
lcd.print(" ");
lcd.setCursor(14, 0);
lcd.print("#");
lcd.setCursor (15, 0); // go to end of 1st line
lcd.print(ActiveAddress + 1);
lcd.setCursor(5, 1); // start of 2nd line
String temp = "0000" + String(LocoFN0to4[ActiveAddress], BIN); // pad with leading zeros
int tlen = temp.length() - 5;
lcd.print(temp.substring(tlen));
temp = "000" + String(LocoFN5to8[ActiveAddress], BIN);
tlen = temp.length() - 4;
lcd.setCursor(0, 1); // start of 2nd line
lcd.print(temp.substring(tlen));
lcd.setCursor (13, 1);
if (etat_c == 0)lcd.print("OFF");
else lcd.print("ON ");
}
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 != 0)encoderPos --; //decrement the encoder's position count
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
encoderPos ++; //increment the encoder's position count
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
}