Trains.com

Subscriber & Member Login

Login, or register today to interact in our online community, comment on articles, receive our newsletter, manage your account online and more!

On the electronics front - servo controllers

1256 views
3 replies
1 rating 2 rating 3 rating 4 rating 5 rating
  • Member since
    February 2002
  • From: Reading, PA
  • 30,002 posts
On the electronics front - servo controllers
Posted by rrinker on Sunday, January 26, 2020 4:32 PM

 Since the basement is coming along at a rapid pace, I figured I better get my servo controllers finished so I have something to operate turnouts with. I've had the boards for the new design which uses just one relay, flipped at the center point of the servo movement for frog polarity control, for a while now. I just hadn't gotten around to modifying my code for the old board, as well as make up a test control panel with buttons and LEDs to actually test it  all out.

 So the past couple of weeks, I've been working on that. Assmbled one of the boards. Set up one of the buck modules for the proper voltage and soldered that on. Tested the voltages all over the board. Frounded the pin that drives the relays to verify my transistor circuit was good. SO far, so good. Only thing left was the code for the microcontroller.

So this week I got that sorted out. Programmed one and stuck it in, and it actually worked. I took an old ethernet cable and cut one end off to make a control cable, soldering on a pair of LEDs and a pair of pushbuttons. Servo moves, relay clicsk on or off at the mid point, lights change. Jumpered the centering jumper, both servos go to the center.

 Only one slight prblem, the servos tend to jump a few degrees clockwise every time power is cycled. None of this made sense. I even added more debugging to my code and verified the position never went out of range, and always went exactly to the endpoints I have defined. Just solved it - added an extra servo position write to the initialization, with a delay. They still jump slightly, but instantly return to the proper position. The glitch is always clockwise - so at minimum, they will jumpo to somethign higher than the 20 I have set, usually about 30, and then the init sets them back to 20. If the last position ebfore power off was at the high end, which I have set to 140, they may go to 150 and then jump back when the init routing runs. Such is how it is, it won't really be an issue in use.

 ANd no, keeping the servos unpowered untila fter initialization won't do anything. Before I added the position reset, if I power cycled the board with the servo disconnected, then connected it, it would jump to the more clockwise position. And yes, each servo has a dedicates 470uF cap on its power leads. I have some other servos to try, not all of these cheap 9G servos are the same. I also watched the output on my scope, no glitches, on power up or during movement. Just nicely increasing or decreasing width pulses.

                               --Randy

 

 


Modeling the Reading Railroad in the 1950's

 

Visit my web site at www.readingeastpenn.com for construction updates, DCC Info, and more.

  • Member since
    July 2009
  • From: lavale, md
  • 4,678 posts
Posted by gregc on Monday, January 27, 2020 9:55 AM

not obvious that there's a solution (have you seen these).

greg - Philadelphia & Reading / Reading

  • Member since
    February 2002
  • From: Reading, PA
  • 30,002 posts
Posted by rrinker on Monday, January 27, 2020 11:07 AM

 One of those in there is where I got the idea for the delay. I may need to extend it.

The funny thing is, fresh startup with a newly programmed chip (so it has to run the EEPROM setup routine and then simply defaults both servos to the low end, I'm using 20 to 140 since not all servos can actually go 0-180 and it's so far proven to be plenty of range to move Peco throwbars), it doesn't do it. If the servo was last at the 20 position, it powers on and stays there. It's only in subsequent power cycles that it does this, and all that does is read EEPROM to get the old position, does a Servo.write, and then a Servo.attach. The Servo commands are actually the same block of code regardless if the code had to initialize EEPROM or just read an existing saved position.

 I keep the servos detached when not moving so they are quiet and to reduce current draw. So after the write and attach, I had code to set up the indicators and the relays, then it does a servo.detach. This is where I put the delay, before the detach, to give the servo enough time to react, and it mostly worked, but rapid power cycling gets the servo to creep.

Servo power is isolated from the micro power - the buck module had s filter capacitor, then I have another 1000uF, then taps off ONLY to the servo power connectiosn, then a schottkey diode and additional filters to power the micro, which also has bypass caps right next to the chip.

The first hit on the google list mentions a rather complex system of using an extra IO pin to drive a mosfet and a much larger cap for each servo - while that might work, I don't have the spare IOs and the comemrcial servo drivers I used in the past don't need anything like this. I'm hoping a longer delay will give things more time to settle. It's only when powering up the boards - after that, I have been flipping servos back and forth and it always goes to the correct position and stays there. I also left it in the thrown position, both servos, because this is when the relay coils are energized, to see if the relay or the driver transistors would get warm, no problems there.

                                                --Randy 


Modeling the Reading Railroad in the 1950's

 

Visit my web site at www.readingeastpenn.com for construction updates, DCC Info, and more.

  • Member since
    February 2002
  • From: Reading, PA
  • 30,002 posts
Posted by rrinker on Friday, January 31, 2020 1:18 PM

 It actually works. I still have some refactoring of the code to do to totally clean it up, but there is now just enough startup delay to allow the servos to set themselves to the correct last known position as saved in the EEPROM. Posting here if anyone is interested. Remember, I am NOT selling anything, code is free and I'll freely give anyone the schematic and/or Gerbers for the boards. Or the source, if you use EasyEDA. An enterprising person who doesn't mind doing surface mount could make my board a lot smaller by making all the pullup and protection resistors, and debounce caps surface mount. 

  1. /*
  2.   Servo Turnout Control Module v2.1
  3.   Randy Rinker
  4.   Trainbytes Designs
  5.   This module controls two model railroad turnouts via servos
  6.   along with relays for frog polarity. Local pushbuttons as well
  7.   as remote control and locking are provided. Last position of
  8.   each turnout are saved and remembered at next power on.
  9. */
  10. // Include libraries
  11. #include <Metro.h>  //Include Metro library
  12. #include <Servo.h>  //Include Servo library
  13. #include <EEPROM.h> //Include EEPROM library
  14. // Define values used with EEPROM save and load
  15. #define VERSION "TCON21"
  16. #define CONFIG_START 1010   // 504 for units based on ATTiny 85
  17. #define MEM_MAX 1000        // 500 for units based on ATTiny 85
  18. // Define pin usage
  19. #define SW1NLED 0   // Switch 1 Normal LED on Pin D0
  20. #define SW1RLED 1   // Switch 1 Reverse LED on Pin D1
  21. #define SW2NLED 2   // Switch 2 Normal LED on Pin D2
  22. #define SW2RLED 3   // Switch 2 Reverse LED on Pin D3
  23. #define SW1LCK 4    // Switch 1 Local Lockout on Pin D4
  24. #define SW2LCK 5    // Switch 2 Local Lockout on Pin D5
  25. #define SW1STAT 6   // Switch 1 Status on Pin D6
  26. #define SW2STAT 7   // Switch 2 Status on Pin D7
  27. #define SW2FR 8     // Switch 2 Frog Relay on Pin D8
  28. #define SW1FR 9     // Switch 1 Frog Relay on Pin D9
  29. #define SW2SERVO 10 // Switch 2 Servo on Pin D10
  30. #define SW1SERVO 11 // Switch 1 Servo on Pin D11
  31. #define HBLED 12    // HB LED on Pin D12
  32. #define CENTER 13   // Servo Center Jumper on Pin D13
  33. #define SW1NB A0    // Switch 1 Normal Button on Pin A0
  34. #define SW1RB A1    // Switch 1 Reverse Button on Pin A1
  35. #define SW2NB A2    // Switch 2 Normal Button on Pin A2
  36. #define SW2RB A3    // Switch 2 Reverse Button on Pin A3
  37. #define SW1REM A4   // Switch 1 Remote Control input on Pin A4
  38. #define SW2REM A5   // Switch 2 Remote Control input on Pin A5
  39. //Define other system values
  40. #define TURNOUT1 1
  41. #define TURNOUT2 2
  42. #define NORMAL 0
  43. #define REVERSE 1
  44. // Create and initialize variables
  45. int hbstate = HIGH;   // Current state of HB LED
  46. int servo1max = 140;  // Servo1 max position
  47. int servo1min = 20;   // Servo1 min position
  48. int servo1mid = (servo1max - servo1min) / 2;  //Servo1 mid position for relay toggle
  49. int servo1pos = servo1min;  // MIN is normal, MAX is reverse
  50. int servo1dir = -1;   // -1 is normal, 1 is reverse
  51. int servo1step = 2;   // Servo1 step per loop
  52. int servo2max = 140;  // Servo2 max position
  53. int servo2min = 20;   // Servo2 min position
  54. int servo2mid = (servo2max - servo2min) / 2;  //Servo2 mid position for relay toggle
  55. int servo2pos = servo2min;  // MIN is normal, MAX is revese
  56. int servo2dir = -1;   // -1 is normal, 1 is reverse
  57. int servo2step = 2;   // Servo2 step per loop
  58. int sw1frstate = LOW;   // Switch 1 frog relay not energized = Normal
  59. int sw2frstate = LOW;   // Switch 2 frog relay not energized = Normal
  60. int sw1state = NORMAL;     // Switch 1 is Normal, Status Low
  61. int sw2state = NORMAL;     // Switch 2 is Normal, Status Low
  62. int sw1lockstate = HIGH;  // Switch 1 lock = HIGH, not locked, local control enabled
  63. int sw2lockstate = HIGH;  // Switch 2 lock = HIGH, not locked, local control enabled
  64. int sw1remstate = HIGH;   // Switch 1 remote state = HIGH, would be reverse if under remote control
  65. int sw2remstate = HIGH;   // Switch 2 remote state = HIGH, would be reverse if under remote control
  66. unsigned int memptr = 0;  // Pointer to EEPROM memory location
  67. byte savedpos = 0x00;     // 00 is both normal
  68. byte memctr = 0;          // Number of writes to a given memory location
  69. byte ptr_low = 0;         // Memory address for low byte
  70. byte ptr_high = 0;        // Memory address for high byte
  71. bool servo1move = false;  // Servo 1 in motion false = servo not moving
  72. bool servo2move = false;  // Servo 2 in motion false = servo not moving
  73. // Instantiate Metro objects for each loop
  74. Metro hbMetro = Metro(750);     // Flash Heartbeat LED every 750ms
  75. Metro nbMetro = Metro(90);      // Test Normal buttons every 90ms
  76. Metro rbMetro = Metro(90);      // Test Reverse buttons every 90ms
  77. Metro lckMetro = Metro(50);     // Test Local Lock inputs every 50ms
  78. Metro servo1Metro = Metro(50);  // Move Servo 1 every 50ms
  79. Metro servo2Metro = Metro(50);  // Move Servo 2 every 50ms
  80. Metro rcMetro = Metro(90);      // Check Remote Control inputs every 90ms
  81.   // Instantiate Servo objects for each server
  82. Servo Servo1;
  83. Servo Servo2;
  84. void setup()
  85. {
  86.   // Set IO pins
  87.   pinMode(HBLED, OUTPUT);
  88.   digitalWrite(HBLED, hbstate);
  89.   pinMode(SW1NB, INPUT);
  90.   pinMode(SW1RB, INPUT);
  91.   pinMode(SW2NB, INPUT);
  92.   pinMode(SW2RB, INPUT);
  93.   pinMode(SW1NLED, OUTPUT);
  94.   pinMode(SW1RLED, OUTPUT);
  95.   pinMode(SW2NLED, OUTPUT);
  96.   pinMode(SW2RLED, OUTPUT);
  97.   pinMode(SW1REM, INPUT);
  98.   pinMode(SW2REM, INPUT);
  99.   pinMode(CENTER, INPUT);
  100.   pinMode(SW1LCK, INPUT);
  101.   pinMode(SW2LCK, INPUT);
  102.   pinMode(SW1STAT, OUTPUT);
  103.   pinMode(SW2STAT, OUTPUT);
  104.   pinMode(SW1FR, OUTPUT);
  105.   pinMode(SW2FR, OUTPUT);
  106.   // Load config from EEPROM
  107.   if (!loadConfig()) {
  108.     saveConfig(); // overwrite with the default settings
  109.     EEPROM.write(memptr, savedpos);
  110.   }
  111.   // Initialize Servos
  112.   if (!digitalRead(CENTER)) { // If center jumper is on (low), center servos
  113.     // Set servos to center
  114.     Servo1.write(servo1mid);
  115.     Servo1.attach(SW1SERVO);
  116.     Servo2.write(servo2mid);
  117.     Servo2.attach(SW2SERVO);
  118.     while (1) {             // endless loop, flash position LEDs
  119.       digitalWrite(SW1NLED, 1);
  120.       digitalWrite(SW2NLED, 1);
  121.       digitalWrite(SW1RLED, 0);
  122.       digitalWrite(SW2RLED, 0);
  123.       delay(500);
  124.       digitalWrite(SW1NLED, 0);
  125.       digitalWrite(SW2NLED, 0);
  126.       digitalWrite(SW1RLED, 1);
  127.       digitalWrite(SW2RLED, 1);
  128.       delay(500);
  129.     }
  130.   }
  131.   else {                      //Otherwise just initialize
  132.     initpos();
  133.     servo1move = false;
  134.     servo2move = false;
  135.     Servo1.write(servo1pos);
  136.     Servo1.attach(SW1SERVO);
  137.     Servo2.write(servo2pos);
  138.     Servo2.attach(SW2SERVO);
  139.     updateRelays();
  140.     updateLEDs();
  141.     delay(500);
  142.     Servo1.detach();
  143.     Servo2.detach();
  144.   }
  145. }
  146. void loop()
  147. {
  148.   if (hbMetro.check() == 1) {   // Heartbeat LED
  149.     if (hbstate == HIGH)  hbstate = LOW;
  150.     else hbstate = HIGH;
  151.     digitalWrite(HBLED, hbstate);
  152.   }
  153.   if (nbMetro.check() == 1) {   // Manual normal button check
  154.     if (!digitalRead(SW1NB) && sw1lockstate) {
  155.       if (sw1state == REVERSE) {
  156.         servo1dir = -servo1dir;
  157.         servo1pos = servo1pos -  servo1step;
  158.         sw1state = NORMAL;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
  159.         servo1move = true;
  160.         Servo1.write(servo1pos);
  161.         Servo1.attach(SW1SERVO);
  162.       }
  163.     }
  164.     if (!digitalRead(SW2NB) && sw2lockstate) {
  165.       if (sw2state == REVERSE) {
  166.         servo2dir = -servo2dir;
  167.         servo2pos = servo2pos - servo2step;
  168.         sw2state = NORMAL;
  169.         servo2move = true;
  170.         Servo2.write(servo2pos);
  171.         Servo2.attach(SW2SERVO);
  172.       }
  173.     }
  174.     updateLEDs();
  175.   }
  176.   
  177.   if (rbMetro.check() == 1) {   // Manual reverse button check
  178.     if (!digitalRead(SW1RB) && sw1lockstate) {
  179.       if (sw1state == NORMAL) {
  180.         servo1dir = -servo1dir;
  181.         servo1pos = servo1pos +  servo1step;
  182.         sw1state = REVERSE;
  183.         servo1move = true;
  184.         Servo1.write(servo1pos);
  185.         Servo1.attach(SW1SERVO);
  186.       }
  187.     }
  188.     if (!digitalRead(SW2RB) && sw2lockstate) {
  189.       if (sw2state == NORMAL) {
  190.         servo2dir = -servo2dir;
  191.         servo2pos = servo2pos + servo2step;
  192.         sw2state = REVERSE;
  193.         servo2move = true;
  194.         Servo2.write(servo2pos);
  195.         Servo2.attach(SW2SERVO);
  196.       }
  197.     }
  198.     updateLEDs();
  199.   }
  200.   
  201.   if (servo1Metro.check() == 1) {   // Servo 1 movement control
  202.     // Move interval for Servo 1
  203.     if (servo1move) {
  204.       // Servo is moving)
  205.       // if we reached the end of travel
  206.       if ((servo1pos >= servo1max) && (sw1state == REVERSE)) {
  207.         // reverse
  208.         sw1state = REVERSE;
  209.         sw1frstate = REVERSE;
  210.         servo1pos = servo1max;
  211.         servo1move = false;
  212.         ServoEOT(TURNOUT1);
  213.       }
  214.       else if ((servo1pos <= servo1min) && (sw1state == NORMAL)) {
  215.         // normal
  216.         sw1state = NORMAL;
  217.         sw1frstate = NORMAL;
  218.         servo1pos = servo1min;
  219.         servo1move = false;
  220.         ServoEOT(TURNOUT1);
  221.       }
  222.       else {
  223.         // Just move the servo, we are in the middle
  224.         servo1pos = servo1pos + (servo1dir * servo1step);
  225.         Servo1.write(servo1pos);
  226.         // If past midpoint, going in either direction, change the polarity relay
  227.         if ((servo1dir == -1) && (servo1pos <= servo1mid) && (sw1frstate != sw1state)) {
  228.           sw1frstate = sw1state;
  229.         }
  230.         if ((servo1dir == 1) && (servo1pos >= servo1mid) && (sw1frstate != sw1state)) {
  231.           sw1frstate = sw1state;
  232.         }
  233.         updateRelays();
  234.       }
  235.     }
  236.   }
  237.   if (servo2Metro.check() == 1) {   // Servo 2 movement control
  238.     // Move interval for Servo 2
  239.     if (servo2move) {
  240.       // Servo is moving
  241.       // if we reached the end of travel
  242.       if ((servo2pos >= servo2max) && (sw2state == REVERSE)) {
  243.         // reverse
  244.         sw2state = REVERSE;
  245.         sw2frstate = REVERSE;
  246.         servo2pos = servo1max;
  247.         servo2move = false;
  248.         ServoEOT(TURNOUT2);
  249.       }
  250.       else if ((servo2pos <= servo2min) & (sw2state == NORMAL)) {
  251.         // normal
  252.         sw2state = NORMAL;
  253.         sw2frstate = NORMAL;
  254.         servo2pos = servo1min;
  255.         servo2move = false;
  256.         ServoEOT(TURNOUT2);
  257.       }
  258.       else {
  259.         // Just move the servo, we are in the middle
  260.         servo2pos = servo2pos + (servo2dir * servo2step);
  261.         Servo2.write(servo2pos);
  262.         // If past midpoint, going in either direction, change the polarity relay
  263.         if ((servo2dir == -1) && (servo2pos <= servo2mid) && (sw2frstate != sw2state)) {
  264.           sw2frstate = sw2state;
  265.         }
  266.         if ((servo2dir == 1) && (servo2pos >= servo2mid) && (sw2frstate != sw2state)) {
  267.           sw2frstate = sw2state;
  268.         }
  269.         updateRelays();
  270.       }
  271.     }
  272.   }
  273.   if (lckMetro.check() == 1) {    // Lock control check
  274.     if (digitalRead(SW1LCK)) {
  275.       sw1lockstate = HIGH;
  276.     }
  277.     else {
  278.       sw1lockstate = LOW;
  279.     }
  280.     if (digitalRead(SW2LCK)) {
  281.       sw2lockstate = HIGH;
  282.     }
  283.     else {
  284.       sw2lockstate = LOW;
  285.     }
  286.   }
  287.   if (rcMetro.check() == 1) {    // Manual control input check
  288.     if (digitalRead(SW1REM) && !sw1lockstate && !servo1move) {   // Remote high, locked low = normal
  289.       if (sw1state == NORMAL) {
  290.         servo1dir = -servo1dir;
  291.         servo1pos = servo1pos + servo1step;
  292.         sw1state = REVERSE;
  293.         servo1move = true;
  294.         Servo1.write(servo1pos);
  295.         Servo1.attach(SW1SERVO);
  296.       }
  297.     }
  298.     if (!digitalRead(SW1REM) && !sw1lockstate && !servo1move) {   // Remote low, locked low = reverse
  299.       if (sw1state == REVERSE) {
  300.         servo1dir = -servo1dir;
  301.         servo1pos = servo1pos - servo1step;
  302.         sw1state = NORMAL;
  303.         servo1move = true;
  304.         Servo1.write(servo1pos);
  305.         Servo1.attach(SW1SERVO);
  306.       }
  307.     }
  308.     if (digitalRead(SW2REM) && !sw2lockstate && !servo2move) {   // Remote high, locked low = normal
  309.       if (sw2state == NORMAL) {
  310.         servo2dir = -servo2dir;
  311.         servo2pos = servo2pos + servo2step;
  312.         sw2state = REVERSE;
  313.         servo2move = true;
  314.         Servo2.write(servo2pos);
  315.         Servo2.attach(SW2SERVO);
  316.       }
  317.     }
  318.     if (!digitalRead(SW2REM) && !sw2lockstate && !servo2move) {   // Remote low, locked low = reverse
  319.       if (sw2state == REVERSE) {
  320.         servo2dir = -servo2dir;
  321.         servo2pos = servo2pos - servo2step;
  322.         sw2state = REVERSE;
  323.         servo2move = true;
  324.         Servo2.write(servo2pos);
  325.         Servo2.attach(SW2SERVO);
  326.       }
  327.     }
  328.   }
  329. }
  330. void setsavepos() {
  331.   // Sets byte value for servo positions.
  332.   // Upper 4 bits for servo2, lower 4 bits for servo1
  333.   // 00 = both normal, 0F = 1 reverse, 2 normal
  334.   // F0 = 1 normal, 2 reverse, FF = both reverse
  335.   if (sw1state == NORMAL) {
  336.     // switch 1 normal
  337.     savedpos &= 0xf0;
  338.   }
  339.   if (sw1state == REVERSE) {
  340.     // switch 1 reverse
  341.     savedpos |= 0x0f;
  342.   }
  343.   if (sw2state == NORMAL) {
  344.     // switch 2 normal
  345.     savedpos &= 0x0f;
  346.   }
  347.   if (sw2state == REVERSE) {
  348.     // switch 2 reverse
  349.     savedpos |= 0xf0;
  350.   }
  351. }
  352. void initpos() {
  353.   savedpos = EEPROM.read(memptr);
  354.   switch (savedpos) {
  355.     case 0:
  356.       // 0 = both normal
  357.       servo1dir = -1;
  358.       servo1pos = servo1min;
  359.       sw1state = NORMAL;
  360.       sw1frstate = NORMAL;
  361.       servo2dir = -1;
  362.       servo2pos = servo2min;
  363.       sw2state = NORMAL;
  364.       sw2frstate = NORMAL;
  365.       break;
  366.     case 15:
  367.       // 15 = 1 reverse, 2 normal
  368.       servo1dir = 1;
  369.       servo1pos = servo1max;
  370.       sw1state = REVERSE;
  371.       sw1frstate = REVERSE;
  372.       servo2dir = -1;
  373.       servo2pos = servo2min;
  374.       sw2state = NORMAL;
  375.       sw2frstate = NORMAL;
  376.       break;
  377.     case 240:
  378.       //240 = 1 normal, 2 reverse
  379.       servo1dir = -1;
  380.       servo1pos = servo1min;
  381.       sw1state = NORMAL;
  382.       sw1frstate = NORMAL;
  383.       servo2dir = 1;
  384.       servo2pos = servo2max;
  385.       sw2state = REVERSE;
  386.       sw2frstate = REVERSE;
  387.       break;
  388.     case 255:
  389.       //255 = both reverse
  390.       servo1dir = 1;
  391.       servo1pos = servo1max;
  392.       sw1state = REVERSE;
  393.       sw1frstate = REVERSE;
  394.       servo2dir = 1;
  395.       sw2state = REVERSE;
  396.       sw2frstate = REVERSE;
  397.       servo2pos = servo2max;
  398.       break;
  399.     default:
  400.       // default to both normal
  401.       servo1dir = -1;
  402.       servo1pos = servo1min;
  403.       sw1state = NORMAL;
  404.       sw1frstate = NORMAL;
  405.       servo2dir = -1;
  406.       servo2pos = servo2min;
  407.       sw2state = NORMAL;
  408.       sw2frstate = NORMAL;
  409.   }
  410. }
  411. // ServoEOT function handles either servo reaching an endpoint
  412. // Pass integer parameter for which servo has reached EOT
  413. // Invalid servo number results in no action being taken
  414. void ServoEOT(int turnout) {
  415.   switch (turnout) {
  416.     case 1: 
  417.       Servo1.write(servo1pos);
  418.       Servo1.attach(SW1SERVO);
  419.       updateLEDs();
  420.       updateRelays();
  421.       setsavepos();
  422.       writepos();
  423.       Servo1.detach();
  424.       break;
  425.     case 2:
  426.       Servo2.write(servo2pos);
  427.       Servo2.attach(SW2SERVO);
  428.       updateLEDs();
  429.       updateRelays();
  430.       setsavepos();
  431.       writepos();
  432.       Servo2.detach();
  433.       break;
  434.   }
  435. }
  436. // FrogPolarity changes the polarity of the selected frog relay
  437. // Pass parameter for which servo has passed the center point
  438. // Invalid servo number results in no action taken
  439. void FrogPolarity(int turnout) {
  440.   switch (turnout) {
  441.     case 1: 
  442.       if (sw1frstate == NORMAL) sw1frstate = REVERSE;
  443.       else sw1frstate = NORMAL;
  444.       digitalWrite(SW1FR, sw1frstate);
  445.       break;
  446.     case 2:
  447.       if (sw2frstate == NORMAL) sw2frstate = REVERSE;
  448.       else sw2frstate = NORMAL;
  449.       digitalWrite(SW2FR, sw2frstate);
  450.       break;
  451.   } 
  452. }
  453. // UpdateLEDs updates the panel LEDs and status output
  454. // state variables are LOW for Normal and HIGH for reverse
  455. void updateLEDs() {
  456.   digitalWrite(SW1NLED, !sw1state);
  457.   digitalWrite(SW1RLED, sw1state);
  458.   digitalWrite(SW1STAT, sw1state);
  459.   digitalWrite(SW2NLED, !sw2state);
  460.   digitalWrite(SW2RLED, sw2state);
  461.   digitalWrite(SW2STAT, sw2state);
  462. }
  463. //UpdateRelays updates the frog relay settings
  464. void updateRelays() {
  465.   digitalWrite(SW1FR,sw1frstate);
  466.   digitalWrite(SW2FR,sw2frstate);
  467. }
  468. // EEPROM functions
  469. // writepos writes the current servo positions to EEPROM
  470. void writepos() {
  471.   ++memctr;
  472.   if (memctr == 0) {  //rollover, need to incrememnt pointer
  473.     memptr += 2;
  474.     if (memptr >= MEM_MAX) {  //pointer rollover, start back at 0
  475.       memptr = 0;             //memctr is already 0
  476.       EEPROM.write(CONFIG_START, 0);
  477.       EEPROM.write(CONFIG_START + 1, 0);
  478.     }
  479.     else {                    //save new pointer value
  480.       ptr_high = highByte(memptr);
  481.       ptr_low = lowByte(memptr);
  482.       EEPROM.write(CONFIG_START, ptr_high);
  483.       EEPROM.write(CONFIG_START + 1, ptr_low);
  484.     }
  485.   }
  486.   // Otherwise, current values are good
  487.   EEPROM.write(memptr, savedpos);
  488.   EEPROM.write(memptr + 1, memctr);
  489. }
  490. // loadConfig loads the saved values from EEPROM
  491. int loadConfig() {
  492.   // is it correct?
  493.   if (EEPROM.read(CONFIG_START + 2) == VERSION[0] &&
  494.       EEPROM.read(CONFIG_START + 3) == VERSION[1] &&
  495.       EEPROM.read(CONFIG_START + 4) == VERSION[2] &&
  496.       EEPROM.read(CONFIG_START + 5) == VERSION[3] &&
  497.       EEPROM.read(CONFIG_START + 6) == VERSION[4] &&
  498.       EEPROM.read(CONFIG_START + 7) == VERSION[5]) {
  499.     // load (overwrite) the address pointer
  500.     ptr_high = EEPROM.read(CONFIG_START);
  501.     ptr_low = EEPROM.read(CONFIG_START + 1);
  502.     memptr = (ptr_high * 256) + ptr_low;
  503.     for (unsigned int i = 0; i < sizeof(VERSION); i++) {
  504.       *((char*)&VERSION + i) = EEPROM.read(CONFIG_START + i + 2);
  505.     }
  506.     return 1; // return 1 if config loaded
  507.   }
  508.   return 0; // return 0 if config NOT loaded
  509. }
  510. // saveConfig saves initial configuration to EEPROM
  511. void saveConfig() {
  512.   EEPROM.write(CONFIG_START, ptr_high);
  513.   EEPROM.write(CONFIG_START + 1, ptr_low);
  514.   for (unsigned int i = 0; i < sizeof(VERSION); i++)
  515.     EEPROM.write(CONFIG_START + i + 2, *((char*)&VERSION + i));
  516. }

 

                   --Randy

 


Modeling the Reading Railroad in the 1950's

 

Visit my web site at www.readingeastpenn.com for construction updates, DCC Info, and more.

Subscriber & Member Login

Login, or register today to interact in our online community, comment on articles, receive our newsletter, manage your account online and more!

Users Online

There are no community member online

Search the Community

ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT
Model Railroader Newsletter See all
Sign up for our FREE e-newsletter and get model railroad news in your inbox!