Jump to content
 

FoxUnpopuli

Members
  • Posts

    250
  • Joined

  • Last visited

Everything posted by FoxUnpopuli

  1. Randall and Hopkirk Deceased - the Reeves/Mortimer one. I remember it being pretty good... but I wonder if it would hold out. Some top 90s/00s American Cheese: Seven Days Andromeda (for those diehard Kevin Sorbo fans - now back on Amazon Prime, I think.) And now, rare and hard to find, but much better quality (and ill deserving of cancellation as Karl Urban is awesome): Almost Human
  2. I tried the download link, but it tells me it does not exist. Is the file still available?
  3. Now I'm not being disparaging* but I do wonder why people choose to model modern times because of this. On the flipside, I do wonder what would have happened if modern efficiency practices would have been put in place in the late 1920s - i.e. all the big-4 would have got together and said to Parliament "stuff your common carrier regulations - let us do it better!" (* I know and approve of the reason why - rule 1. To misquote: "I disagree with what you model, but I will defend to the death your right to model it!")
  4. I'd use the lit switch on the non-lighting circuit - your smoke generator. Then you'll know if you left it on but it's not generating for some reason.
  5. Ah now I see, having actually gone to have a look at eBay instead of just typing. The first is the type I claimed not to have seen. I mostly ignore these especially if there's a high starting bid, as if there's an auction, why not just let it run. The second is the type I do make offers on. The third, well, if its a bargain... etc. ... that's a fair comment. But I'm a curmudgeon.
  6. [ramble] I usually only make offers where the buyer has set a buy-it-now (i.e. offer is less.) I don't think I've ever tried to make an offer on an auction to try to finish it early (didn't know that existed.) I make an offer that is roughly what I think it's worth. That offer is not necessarily what I'm willing to pay... if the offer is rejected and a counter offer made, I consider it carefully. I'm much more amenable if I get a well worded email with considered justification. Of course, you can count on the thumbs of your feet how often this happens. Sometimes when I see something I really would like, but it's offered at a ridiculous BIN price, I'll send a message first with some research pointers indicating what I think it's worth, followed later by the offer. This, perhaps surprisingly, has worked rather well for me in the past. It has, equally unsurprisingly, provided some properly Bubba Knucklehead responses. However, if the original list price is close to what I'd pay, I usually offer very close to the asking. (If they wanted that precise amount, they wouldn't add the 'offer'... unless they did it by accident as mentioned earlier.) I'm fairly sure companies set automatic accept/reject criteria for offers. Just sayin'. eBay can still feel like a den of thieves, and it really grabs my goat eBay won't let me permanently filter a particular sellers' items out of my searches globally... as there are a couple of reprobates I'd love to do that with. (I do know how to do it on specific searches, I just CBA to set it up each time.) I check RMWeb ads first before I go to the 'bay. [/ramble]
  7. Why not service them and fit them with DCC chips? I know you say you're an electrical novice, but it's not super-difficult to do. Have a read here to judge suitability of yours:
  8. @kevinlms One length of flexi, I agree. Now ten lengths of flexi - a little over 9 metres - would have significant resistance (a little over 2 ohms for the 18m of rail concerned) in comparison to motor windings (which I wouldn't like to guess at but should be roughly similar). I'd lay odds that you would indeed notice the slowing of the loco towards the other end of the straight run. However, this is now a bar discussion only proven by experiementation. (I do agree with you about the corrosion, however... but that's actually what the purpose of the thread is, combatting the corrosion layer with nowt but a pencil!) @Graham Radish Well... the layer of graphite is inconsequential as far as resistance is concerned, it's extremely thin. It's purpose here, and why it works as a concept practically, is that it's being used as an anti-corrosion layer. The NS rail corrodes at a far lower rate, and the graphite doesn't really transfer as there's so little of it, filling all the microscopic cracks and pores in the surface of the rail. For a relatively small loss in traction, you remove the need to continually clean corrosion off your track and wheels. It's a trade-off many people make, and it works just fine. You speak of carbon deposits and carbon film resistors, they are both different material forms of carbon again - apples and oranges. We could diamond coat the track, leving it lovely and shiny, and while the wear resistance would be stellar, it wouldn't really need to be as diamond is a phenomenally good insulator - nothing would be going anywhere. Since you ask, graphite in the same units is around 800, semiconductor carbon about 3500... and diamond is ... somewhere between 10^13 and 10^20. Lots.
  9. I agree with you - but it is a numbers game. Without resorting to units, the resistivity of NS is about 28, the relative resistivity of copper is 1.7. If you jumper all your fishplates wih soldered copper, you'd have a well conducting run of NS, but if the layout only has a single feed, you'll have much more voltage drop at the extremes than if you added a couple of extra copper wired feeds. Practically, it only takes a couple of feeds to assist a small layout beyond the point you can recognise a steady drop off of speed due to these resistances. As soon as you've put in a couple of section feeds in for DC 'cab control', or even just isolating sidings &c., you've fixed a problem you never knew you had. Bear in mind if you use DCC, then you won't see an issue with voltage drops at all (in theory) as the voltages fed to the motors are locally calculated by the electronics in the decoder. As long as the DCC feed voltage is high enough to begin, you should never see a variance in your loco speed. I do remember from more than 30 years back that locos on my codged and bodged 4ftx7ft roundy-roundy (with its rusty steel* Hornby settrack, plastic power clips and probably filthy wheels and pickups) would perform noticably better close to the power feed than directly opposite. While I've witnessed this directly and you state you have not, I think this goes more to proving your point than mine! I'm designing a OO garden layout which may be in the order of 80 metres in extremis, so I've been thinking about these things as they will make a difference for me. Then again, with DCC, as long as there is some signal, Almost certainly, YMMV (Your Meterage May Vary. ) * For info, the resistivity of mild/carbon steel compared to the other materials above is in the 7-10 range.
  10. I was going to have a lovely old "someone is wrong on the internet" rants before I read this comment more carefully: This spirit of this statement is very much a truth - because of the properties of the oxide, it makes NS a good compromise material for rails. Just as a point-of-fact in addition; NS itself is a relatively poor conduction material, hence the generally accepted advice that a set of copper bus wires under the baseboard helping the angry pixies get to where they need to be much more easily is "a good idea". It's alway about cost for products like this. I think from a solving an engineering problem point of view, you could use a zinc-chromate (look up chromate conversion coating) on steel to get a nice bright conductive material with fair corrosion resistance... but the cost and ongoing maintenance of the processes (steel needs to be zinc plated first) probably don't really stand up to using NS as the base material. We could suggest that an aluminium-extruded rail of a decent hard grade of aluminium might get us the colour, corrosion resistance, and conductivity we desire if correctly post-processed, but I dread to think the cost, and we have to suspect that even a robust grade of aluminium will be a touch too soft to combat accidental damage from a clumsy cack-handed fool like me. As far as on-topic discussion goes, I'm on the 'graphite is good' bandwagon. (I think some of my comments on the topic have been quoted in this thread.)
  11. Looks like an eyelet, as used for reinforcing holes in leather, for shoelaces, &c.
  12. A picture is worth a thousand words. However, since we're on DCC here, we can discuss stay alive capacitors for the first problem. I don't know what brand of decoder you favour, but many if not most decoders can support a capacitor. Smoother running in general vs extra expense and some packaging and wiring challenges, However, since we're straying off-topic... It occured to me that even though it's an insulfrog crossng we're talking about, and you mentioned you were using insulated rail joiners - a bit of cunning with some electrical switches hooked up to the feeding turnouts could allow you to throw the polarity of the offending rails. Worth investigating?
  13. Ouch. If you carried it all, I feel for you. I too am in house renovation Hades at the moment.
  14. Having just read this thread through, as it doesn't appear Hornby have retooled the Five since... I think it deserves another bump. Excellent work.
  15. Couple of coats of clear (nail) varnish over the vees? https://www.rmweb.co.uk/community/index.php?/topic/38137-peco-crossing-shorting-issues/
  16. Dave Bodnar for one, when he used that chip in a homemade DCC booster: http://trainelectronics.com/DCC_Arduino/DCC_Booster/index.htm
  17. The Hornby Hobbies outlet shop in Swindon is closing down. It's been this way for a week, and the staff were commenting on how it's begun to get so busy there's a queue out the store for the first time ever - not that it's difficult at the moment as only 8 people are allowed in the store. My advice is that if you do go in, please abide by social distancing. Apparently some model railway enthusiasts are also complete muppets about this when it comes to bargain hunting. There are signs proclaiming "40% off locomotives". This is true for some things, not necessarily for others, but I'd say much of the locomotives (some at good prices anyway) and some (but not all) of the rolling stock is now firmly in the 'bargain' territory. I just picked up a streamlined Coronation (King George VI) for £114, for example, and they had four types available (Coronation, Princess Liz in blue, King George and Duchess of Hamilton in crimson.) Lots of shop bleached/box damaged stock on the tables - mostly coaches for £20-25 - basically halfprice. They had some LNER Thompson suburbans in that pile, but what's left is mostly Era 4/5 British Railways stuff from all regions. I collected much of the LMS Stanier stock at that price, sorry. Hopefully there's a bit more 'out back'. Also - Scalextric cars and Airfix kits of all stripes at these discounts too. Good luck!
  18. How about modelling up some heavy machinery castings? This looks like a lathe bed being machined, it seems about 8 feet long, but I'm sure some Googling will find you some interesting other big castings. Loco machine shops muct have had some whopping lumps of metal. Edit: Wrong country, but check these out!
  19. I see we have foudn the same issue. I wish you luck finding a solution - looks like you're well on your way.
  20. Fascinating. I'm looking forward to seeing more of the block detection and how you will use it to signal (and automate?) the layout. Nice work!
  21. The function code was substantially rebuilt this time. It bugged me. Typing 'D29' now sets all the function bits to zero, turning off all functions. If not mentioned already, I now set the speed to zero when pressing the rotary encoder to change direction. A quick way of just zeroing speed if you 'double click'. As promised, some code to ridicule attached below. Keys 0-9 and A-C are still hotkeys for functions F0 to F12, but now any Dxx command will set function xx. * now turns the power back on to the track after you've set the new loco ID. I'm not sure about this one. I also see that the 'power on' command gets sent every time you twiddle the thottle. This is a waste of bandwidth so I'll address that at some point. I think I'm going to reassign A-C to do something else. Any suggestions? edit: found a bug because I didn't check the F29 addition... ddf should go round the loop one more time, i.e. ddf < 5, not 4. /* Mark Fox's DCC++ 'Bodnar Throttle'. I think I might brand it a 'Bodnar'. :) Rewritten and customised from Dave Bodnar's code from June 16th, 2016, his version 2.6a Version 1.00 uses an Arduino MEGA2560 (devboard) with a 4x4 keypad, 20x4 I2C LCD Display, and uses digital debouncing on the KY-040 rotary encoder without an interrupt. This version is 1.03, a heavy edit streamlining all the function comms. Date 6th August 2020. */ #include "Arduino.h" #include <EEPROM.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> #include <Keypad.h> // Pin definitions #define RE_CLK 2 // Rotary encoder on 2,3,4 #define RE_DATA 3 #define RE_Button 4 #define I2C_ADDR 0x27 int debug = 0; // set to 1 to show debug info on serial port - assume that it will cause issues with DCC++ depending on what is sent uint8_t zerodot[8] = {0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0}; uint8_t onedot[8] = {0x0, 0xe, 0x1f, 0x1b, 0x1f, 0xe, 0x0}; // Setup Keypad variables const byte ROWS = 4; //four rows const byte COLS = 4; //four columns char keys[ROWS][COLS] = { {'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', 'C'}, {'*', '0', '#', 'D'} }; // #=35; *=42; 0-9=48to57; A-D=65to68 //Check all the following are right for the 4x4 keypad onto a Nano - Foxy byte rowPins[ROWS] = {5, 6, 7, 8 }; //{8,7,6,5 }; //connect to the row pinouts of the keypad byte colPins[COLS] = {9, 10, 11, 12}; // {12,11,10,9}; //connect to the column pinouts of the keypad // Now setup the hardware LiquidCrystal_I2C lcd(I2C_ADDR, 20, 4); // Setup LCD Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); static uint8_t prevNextCode = 0; // statics for rotary encoder static uint16_t store = 0; int buttonState = 0; int re_absolute = 0; char key ; // Array set for 4 Locos maximum. Needs code tidyup to make truly flexible. int maxLocos = 4;// number of loco addresses int LocoAddress[4] = {1111, 2222, 3333, 4444}; int LocoDirection[4] = {1, 1, 1, 1}; int LocoSpeed[4] = {0, 0, 0, 0}; // Neater way of storing Loco Function Bytes. // Rows are Locos, Columns are the five sets of function groups // 128 = prefix for functions 0 to 4 (last five bits are functions 04321.) // 176 = prefix for functions 5 to 8 // 160 = prefix for functions 9 to 12 // 0 & 0 are full bitpatterns for functions 13 to 20 and 21 to 28. byte LocoFNs[4][5] = { {128, 176, 160, 0, 0}, {128, 176, 160, 0, 0}, {128, 176, 160, 0, 0}, {128, 176, 160, 0, 0}, }; int ActiveAddress = 0; // make address1 active int i = 0; char VersionNum[] = "1.03"; ///////////////////////// //////////////////////VERSION HERE/////// void setup() { //Setup Encoder Here pinMode(RE_CLK, INPUT); pinMode(RE_CLK, INPUT_PULLUP); pinMode(RE_DATA, INPUT); pinMode(RE_DATA, INPUT_PULLUP); lcd.backlight(); lcd.init(); lcd.createChar(0, zerodot); lcd.createChar(1, onedot); lcd.home (); // go home Serial.begin (115200); getAddresses(); // read loco IDs from eeprom lcd.print("Fox DCC++ Throttle"); lcd.setCursor(0, 1); lcd.print("20200803 v"); for (int i = 0; i < 4; i++) { lcd.print(VersionNum[i]); } Serial.print("20200806 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); // digitalWrite(ledPin, HIGH); // Turn the LED on. // ledPin_state = digitalRead(ledPin); // Store initial LED state. HIGH when LED is on. // keypad.addEventListener(keypadEvent); // Add an event listener for this keypad lcd.clear(); InitialiseSpeedsLCD(); InitialiseFunctionLCD(); lcd.setCursor(4, ActiveAddress); lcd.blink(); } // END SETUP void loop() { static int8_t re_val; // First check the keypad key = keypad.getKey(); if (key) { if (debug == 1) { Serial.println(" "); Serial.println(key); } switch (key) { case '*': all2ZeroSpeed(); InitialiseSpeedsLCD(); getLocoAddress(); updateSpeedsLCD(); key = 0; break; case '#': ActiveAddress++; if (ActiveAddress >= maxLocos) ActiveAddress = 0; updateSpeedsLCD(); InitialiseFunctionLCD(); delay(200); key = 0; re_absolute = LocoSpeed[ActiveAddress]; doDCCspeed(); break; case 'D': //Do nowt for now - menu goes in here? doExtendedFunction(); updateSpeedsLCD(); break; default: // It's 0 - 9 or A - C so perform a loco function key = key - 48; if (key > 10) key = key - 7; doFunction(key); break; } } // Read encoder if ( re_val = read_rotary() ) { re_absolute += re_val; re_absolute = constrain(re_absolute, 0, 126); LocoSpeed[ActiveAddress] = re_absolute; doDCCspeed(); updateSpeedsLCD(); } buttonState = digitalRead(RE_Button); // Serial.println(buttonState); if (buttonState == LOW) { delay(50); buttonState = digitalRead(RE_Button); // check a 2nd time to be sure if (buttonState == LOW) {// check a 2nd time to be sure // Reverse direction... LocoDirection[ActiveAddress] = !LocoDirection[ActiveAddress]; // ... and set speed to zero (saves loco running away on slow decel/accel set in decoder.) LocoSpeed[ActiveAddress] = 0; re_absolute = 0; doDCCspeed(); updateSpeedsLCD(); do { // routine to stay here till button released & not toggle direction buttonState = digitalRead(RE_Button); } while (buttonState == LOW); } } } //END LOOP //START DO FUNCTION BUTTONS void doExtendedFunction() { lcd.setCursor(9 , 0); int counter = 0; int total = 0; do { key = keypad.getKey(); if (key) { counter++; // Abort if # or * if (key < 48) return; // otherwise... int number = key - 48; // if it 3-9 or A-D, and this is the first key... if (number > 2 && counter == 1) { if (debug == 1) Serial.print("First Time, 3 to D"); return; } // else we can assume it's 0,1,2... else if ( counter == 1 ) { lcd.setCursor(9 , number + 1); total = number * 10; } else if (counter == 2 && number < 10) { // Second time around... and 0-9 lcd.setCursor(number + 10 , total / 10 + 1); total = total + number; } else if (counter == 2 && number > 9) { if (debug == 1) Serial.print("Second Time, A-D"); return; } } } while (counter <= 1); // collect exactly 2 digits if (debug == 1) Serial.print(total); doFunction(total); } void doFunction(int FunctoFlip) { // Will be passed a number from 0 to 28. int FuncSet; int FuncLoc; if (debug == 1) { Serial.print("doFunction - passed:"); Serial.println(FunctoFlip); } switch (FunctoFlip) { case (0) ... (4): if (debug == 1) Serial.print("0-4"); FuncSet = 0; FuncLoc = FunctoFlip - 1; if (FuncLoc == -1) FuncLoc = 4; break; case (5) ... (8): if (debug == 1) Serial.print("5-8"); FuncSet = 1; FuncLoc = FunctoFlip - 5; break; case (9) ... (12): if (debug == 1) Serial.print("9-12"); FuncSet = 2; FuncLoc = FunctoFlip - 9; break; case (13) ... (20): if (debug == 1) Serial.print("13-20"); FuncSet = 3; FuncLoc = FunctoFlip - 13; break; case (21) ... (28): if (debug == 1) Serial.print("21-28"); FuncSet = 4; FuncLoc = FunctoFlip - 21; break; case (29): if (debug == 1) Serial.print("29"); // Maybe set all the LocoFNs to zero? // Like this! :) LocoFNs[ActiveAddress][0] = 128; LocoFNs[ActiveAddress][1] = 176; LocoFNs[ActiveAddress][2] = 160; LocoFNs[ActiveAddress][3] = 0; LocoFNs[ActiveAddress][4] = 0; for (int ddf = 0; ddf < 4; ddf++) { doDCCfunction(ddf); } InitialiseFunctionLCD(); return; break; } // What we now have is the number of which bit we'd like to change in that specific function's bitpattern // The next command is effectively 2^number, thus giving us a bitpattern of the number... FuncLoc = 1 << FuncLoc ; // ... which we can then simply XOR onto the existing bitpattern to flip the bit. LocoFNs[ActiveAddress][FuncSet] ^= FuncLoc; doDCCfunction(FuncSet); InitialiseFunctionLCD(); if (debug == 1) { Serial.println("**"); Serial.print(LocoFNs[ActiveAddress][FuncSet], BIN); Serial.print(" - "); Serial.println(LocoFNs[ActiveAddress][FuncSet], DEC); Serial.println(ActiveAddress); Serial.println(FuncSet); Serial.println("**"); } } void getLocoAddress() { int saveAddress = LocoAddress[ActiveAddress]; Serial.print("<0>");// power off to tracks int total = 0; int counter = 0; do { lcd.setCursor( counter , ActiveAddress); key = keypad.getKey(); if (key == '#' || key == '*' || key == 'A' || key == 'B' || key == 'C' || key == 'D' ) { //abort when either is hit //LocoAddress[ActiveAddress] = saveAddress; total = saveAddress; break;// exits the do...while loop if above buttons pressed - ABORT new address } if (key) { counter++; int number = key - 48; total = total * 10 + number; if (key == 48 && total == 0) { lcd.print(" "); } else { lcd.print(key); } 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 // lcd.noBlink(); // If all zeroes entered, return to original address (DCC++ doesn't handle 0.) if (total == 0) total = saveAddress; LocoAddress[ActiveAddress] = total; if (debug == 1) Serial.print("Actually saving: "); if (debug == 1) Serial.println(total); saveAddresses(); Serial.println("<1>");// power back on to tracks updateSpeedsLCD(); } void doDCCspeed() { if (debug == 1) Serial.println(LocoDirection[ActiveAddress] ); 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(">"); } void doDCCfunction(int FuncSetX) { Serial.write("<f "); Serial.print(LocoAddress[ActiveAddress] ); Serial.print(" "); switch (FuncSetX) { case (0) ... (2): // First three function sets are plain single byte commands... break; case (3): // Last two 8-bit sets are prefixed with 222/223. Serial.print("222 "); break; case (4): Serial.print("223 "); break; } int fx = LocoFNs[ActiveAddress][FuncSetX]; Serial.print(fx); Serial.print(" >"); } void all2ZeroSpeed() { /* Loads of bugs here. A) tempx <= maxLocos meant five commands were sent, the fifth to a random(?) loco. B) LocoSpeed and Direction were set to those of loco 1. Not good practice, although not required to be correct as <0> is sent after. As of 4thAugust2020, modified to do what it says it does. */ for (int tempx = 0; tempx < maxLocos; tempx++) { // Set the recorded speeds to zero... LocoSpeed[tempx] = 0; // ... then transmit the commands too. Serial.print("<t1 "); Serial.print(LocoAddress[tempx] );//locoID); Serial.print(" 0 "); Serial.print(LocoDirection[tempx] ); 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(" "); Serial.print("loco = "); Serial.print(LocoAddress[xyz]); Serial.print(" address# = "); 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(" "); Serial.print("loco = "); Serial.print(LocoAddress[xyz]); Serial.print(" address# = "); Serial.print(xyz); Serial.print(" msb "); Serial.print(xxx); Serial.print(" writing to "); Serial.print(xyz * 2); Serial.print(" and "); Serial.print(xyz * 2 + 1); } // Endif EEPROM.write(xyz * 2, xxx); xxx = LocoAddress[xyz] - (xxx * 256); if (debug == 1) { Serial.print(" lsb "); Serial.print(xxx); } EEPROM.write(xyz * 2 + 1, xxx); } EEPROM.write(20, maxLocos); } void InitialiseSpeedsLCD() { for (int tempx = 0; tempx < maxLocos; tempx++) { // Prints LocoID(right justified), direction arrow, and speed(right justified) lcd.setCursor(0, tempx); String temp = " " + String(LocoAddress[tempx] , DEC); int tlen = temp.length() - 4; lcd.print(temp.substring(tlen)); // ... direction... if (LocoDirection[tempx] == 1 ) { lcd.print(">"); } else { lcd.print("<"); } // ... speed ... temp = " " + String(LocoSpeed[tempx] , DEC); tlen = temp.length() - 3; lcd.print(temp.substring(tlen)); } // Return cursor to direction arrow for loco under control lcd.setCursor(4, ActiveAddress); } void InitialiseFunctionLCD() { int funcount = 0; lcd.setCursor(9, 0); lcd.print("F0123456789"); for (int tempy = 0; tempy < 3; tempy++) { lcd.setCursor(9, tempy + 1); lcd.print(tempy); for (int tempx = 0; tempx < 10; tempx++) { lcd.setCursor(tempx + 10, tempy + 1); funcount = tempy * 10 + tempx; // Funkiness to put function 0 on the fourth bit... if (funcount == 0) { lcd.write(byte(bitRead(LocoFNs[ActiveAddress][0], 4))); } // ... and F1 through F4 on the zeroth to third bits. else if (funcount >= 1 && funcount <= 4) { lcd.write(byte(bitRead(LocoFNs[ActiveAddress][0], funcount - 1))); } else if (funcount >= 5 && funcount <= 8) { lcd.write(byte(bitRead(LocoFNs[ActiveAddress][1], funcount - 5))); } else if (funcount >= 9 && funcount <= 12) { lcd.write(byte(bitRead(LocoFNs[ActiveAddress][2], funcount - 9))); } else if (funcount >= 13 && funcount <= 20) { lcd.write(byte(bitRead(LocoFNs[ActiveAddress][3], funcount - 13))); } else if (funcount >= 21 && funcount <= 28) { lcd.write(byte(bitRead(LocoFNs[ActiveAddress][4], funcount - 21))); } else { // 29th location, hint that 29 will turn off all loco functions. lcd.print("X"); } } lcd.setCursor(4, ActiveAddress); } } void updateSpeedsLCD() { int tempx = ActiveAddress; lcd.setCursor(0, tempx); String temp = " " + String(LocoAddress[tempx] , DEC); int tlen = temp.length() - 4; lcd.print(temp.substring(tlen)); if (LocoDirection[tempx] == 1 ) { lcd.print(">"); } else { lcd.print("<"); } temp = " " + String(LocoSpeed[tempx] , DEC); tlen = temp.length() - 3; lcd.print(temp.substring(tlen)); lcd.setCursor(4, ActiveAddress); } // Robust Rotary encoder reading // Copyright John Main - best-microcontroller-projects.com // A vald CW or CCW move returns 1, invalid returns 0. int8_t read_rotary() { static int8_t rot_enc_table[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; prevNextCode <<= 2; if (digitalRead(RE_DATA)) prevNextCode |= 0x02; if (digitalRead(RE_CLK)) prevNextCode |= 0x01; prevNextCode &= 0x0f; // If valid then store as 16 bit data. if (rot_enc_table[prevNextCode] ) { store <<= 4; store |= prevNextCode; if ((store & 0xff) == 0x2b) return -1; if ((store & 0xff) == 0x17) return 1; } return 0; }
  22. Ooookay. I fixed the quick keys. Now 0 actually flips FL/F0, which is the fifth bit, and 1 through 4 actually set functions 1 through 4. I used the A, B and C keys to set F10, F11 and F12. Then, I thought I'd use the D key to set the extended functions, 13 through 28. In order to do this, I rearranged the display thus: So here we have four locos on the left. Using the hash key swaps between them, what you can't see is that the cursor is blinking over the direction arrow to show which loco you're controlling. Of course, rotating the encoder will adjust the speed, loco 7897 is set to 24 here, travelling in reverse. On the right is the function deck for the loco. You can see dots for off and blobs for on. Functions 0 through 12 and function 20 are all on for loco 7897. When you swap locos, it updates the display to show you what's on and off for that loco. To set functions 13 through 20, you simply hit 'D', and it puts the cursor on the 'F' to show it's waiting for further input - in this case, two digits. If you don't hit 0,1 or 2 for the first key, it aborts. When the throttle has a number, it does one of two things... if it's less than 13 or if it's 29, it simply aborts for now. If it's 13 through 28, then it flips the bit for the function, just like the 0-9 and A-C keys for F0 to 13. Here's some debug enabled code. It's saying it saw the D key, then 28 was received, this is then adjusted down to 7 - as F28 is the most significant bit in the byte you have to send to set it. The bitpattern is shown, followed by the decimal, and then the DCC++ serial message for setting F21 to F28 is set. And then... 27... etc. 20:10:23.163 -> D 20:10:26.043 -> 2815 20:10:26.043 -> 7 20:10:26.043 -> 10000000 21to28 d 128<f 7897 223 128 > 20:10:31.403 -> D 20:10:32.963 -> 2714 20:10:32.963 -> 6 20:10:32.963 -> 11000000 21to28 d 192<f 7897 223 192 > I've refined the code a little more, but it's still messy and I can see many ways to improve it. Edit: when I've done that and it's 'tidy enough' I'll post it.
  23. In case you don't know what a Bodnar DCC++ throttle is, you can visit here: http://www.trainelectronics.com/DCC_Arduino/DCC++/Throttle/index.htm I chose to try to build a slightly modified Rotary Encoder & wireless version of his throttle. This is also my first time coding Arduinos (although not working with C++, although I'm a tad rusty.) Here's my progress so far (and please don't expect daily updates on this!) I had a look through the code and thought that it would be straightforward to modify the throttle to activate accessories if desired. With this in mind, I used a 4x4 matrix keypad. I also saw no reason why the rotary encoder couldn't be digitally debounced (even though I bought some capacitors in case I had to bail on that idea.) The display is a 20x4 Dave's throttle uses an Arduino Mini, I've chosen to do the development on a Mega 2560 clone, although I have indeed purchased a Mini and the required USB adapter to flash it. To get me started, I just flashed the code as was. Predictably, the rotary encoder did not work, and the implementation of the LCD display was confusing at best - so I went through the LCD commands, correcting them one by one to use the LiquidCrystal_I2C.h library and deleting the LCD.h inclusion. I spent bit of time trying to figure out both how to digitally debounce the encoder, and how to make the interrupt coding work. I found that I could achieve one of these, or the other, but not both. Eventually, I gave up on the interrupt code and just called the encoder routine every time in the loop. It works fine. However, Dave's code (and if you're here Dave, I thank you very much for the start but...) is a tad untidy. And also, some of it plain doesn't work, or at least doesn't work as it seems to have been expected to. I've spent a bit of time tidying the code up and eliminating unused variables and code. It seems to work OK. Fix list so far: The code uses keys 1 to 5 to flip bits 0 to 4 of the first DCC function set. I think the fifth bit is actually the combination bit for directional headlamps (i.e. 'FL', but this needs a bit of investigation). Pushing the 1 through 4 keys toggles the associated F1 through F4 according the NMRA spec, but 5 flips this 'FL' bit - referred to in the DCC++ coding as F0. The code definitely isn't quite right. Another corollary of this is that the 6 key changes what I believe is more commonly known as 'F5' (and 7=F6, 8=F7, 9=F8.) The code uses the 0 key to turn off all the functions (he sets all the bits for the first two function banks to zero.) I think this needs a close look at with a well set up directional locomotive (something I don't have) in order to make the unit function like a commercial device and/or match the DCC++ intent. Dave suggests the * key will 'zero the speed of the locomotives'. Well, it sorta does. I can see how he meant to write the code, but it doesn't actually execute the way he might have expected. First of all, at no point would his code reset the speeds of the locomotives to zero as the global variable he uses is never set to 1, which his subroutine uses as a flag to set all the speeds to zero. However, what does happen in the function is that the track power is turned off - effectively 'setting all the loco speeds to zero'. He also says that cancelling the * key action (the other function of which is to set the DCC ID of the current cab) with * or # will reset the power back on. It does not, you need to twiddle the pot to turn the power back on. But, what happens is that all the locos throttles stored in the hardware are whatever they were before. At the very least, if you cycled through the loco IDs, all of them would throttle up. I can imagine that if you really wanted to stop everything, this might be 'painful'. I will fix this to make it a bit safer! (This routine also ran one more loop than the number of locos available, with possibly unpredictable results - fixed.) Things to do: Figure out how to employ the ABCD keys. Code functions 9 through 12 (could be assigned to A, B, C as F10, F11, F12...) Change the display to use the new real estate more effectively. Code a method of sending accessory messages... ... and perhaps figure a way of making them practical. Maybe: Change the hotkey method for quick locomotive selection so that more than four locos can be added and remembered, and those locos selected from a menu. Eliminate unnecessary code as it is discovered (some more done tonight... why light the onboard pin13 LED at all?) I did buy a 3.5" coloour TFT touch screen, which worked except for the SD card reader, so its going back. Shame... a small layout display should be relatively easy to code for a small layout that is already set up. Flicking to turnout mode and tapping the right turnout with the probe would have worked OK.
×
×
  • Create New...