Results 1 to 3 of 3
  1. #1
    75+ Posting Member

    BushPilotWannabe's Avatar
    Join Date
    Jan 2014
    Alberta, Canada
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Lowering The Bar In A Can

    I am starting this thread as a project under development towards a Cessna 172 table top simulator. Simple, homemade and as close to the FSX default virtual cockpit as possible. Current changes will include constant speed prop and retracts for future use with something faster. Money 21, Beech 33 or Skylane RG (maybe Cessna T182RG). I hope that my struggles will help future simmers or aviation students build a usable sim quickly.
    Present equipment:
    -(2) HP dc7900SPF computers (surplus) 3 GHz and 2Mb memory. Win7 Pro. One has a 1GB passive video card required by Simbin's "GT Legends"
    -usb SVGA monitor switch, 1 keyboard, 1 mouse and a null modem cable.
    -CH Products Flight Yoke basic model and two joysticks - one assembled and working.
    -A box full of various Arduino boards, shields, 0.28" digits, Max7221 and Max7219 drivers, switches, SMD bits and perf boards.
    -Hantek 6022BE super sound card Digital Oscilloscope which balances the table nicely.
    -Room full of 17" surplus LCD monitors and a Matrox Parhelia video card for P5 box that was not up to the task.

    -Link2fs and an almost unrecognizable Multi-Radiohead-Project (sorry Jim)
    -SimPlugins Panel Builder

    To date:
    -Spent more than I would like on very small electronic parts with more on the way.
    -Strapped an ATtiny85 onto the back of a rotary encoder to provide adjustable UP, DOWN and switch pulses in effort to be recognized when the switch is moved during a delay for LCD panel update. An interrupt will do this but for 15 encoders? The pulses are input like push buttons.
    -Roughed out the fuselage switch panel - magneto switch, lights, radio master etc. Have tried putting it on a stand alone Atmel328P-PU chip connected by IIC serial bus. Have to work out why random packets received by the interrupt function are not passed to the main sketch. Will try another IIC library or 3 wire serial bus.
    -Did the same for Multi-Radiohead-Project panel with push buttons for a 2-axis autopilot filling all digital pins. May change this to run on two analog pins.

    Any hope for success? Paid $349 for a Vic20, $650 for low density floppy drive, $875 for an Epson FX80 printer but only $18/hr wet for a C150 solo including employee discount. Haven't quit yet no matter what anybody says.

    Next to come: In A Can how to's for ATtiny85 on an encoder and fuselage switch panel.
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  2. #2
    75+ Posting Member

    BushPilotWannabe's Avatar
    Join Date
    Jan 2014
    Alberta, Canada
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Re: Lowering The Bar In A Can

    Single Analog Rotary Encoder In A Can

    My thanks to the Arduino, Link2fs, and MyCockpit community especially

    THIS POST concentrates on decoding full cycle, quadrature (two input), rotary encoders (with detented shaft and an attached tactile pushbutton switch) by a single Arduino analog pin. With a full cycle encoder there is no electrical continuity between any contacts (common, channel A, channel B) when the shaft sits in a detent. The focus of this project in the beginning was the aforementioned rotary quadrature encoder, but with time, re-writes, and expansion of the sketch I have come to look on the encoder as three momentary switches - two wiper switches and one tactile pushbutton.

    Rotate the shaft of the encoder a small amount in either direction from the detent position and one of the wipers shorts the common contact to one of the channels while the other wiper - for the time being - remains insulated from the common contact. If you know which wiper closes first, you know the direction of rotation. To count the number of movements in one direction, count the number of times that both wipers move onto an insulated segment.

    What is this third analogRead level that I found between Channel A and Channel B? Think back to quadrature theory. Halfway between detents, both channels are connected to the common contact. And because each channel connects to opposite sides of step up resistor, that resistor is shorted out decreasing the total resistance in the calculation of that voltage divider in particular. Momentarily shorting node R1/R2 to +5V by the tactile pushbutton also removes one resistor from the overall resistance of the ladder for those that want to push in on the encoder knob and rotate to duplicate "outer knob" rotation to adjust frequencies by 1 MHz on Com or Nav radios. Record the additional analogRead levels for channel A and channel B while the switch is closed. Write new instructions for the added switch usage.

    That's it. That's all we have to know.

    (1) 100k --> 1M ohm pullup resistor 1/4 watt
    (6) 12K ohm resistors or any similar value 1/4 watt
    (1) Arduino board
    (1) LED and 520 ohm takeup resistor if you have removed the "blink" LED from the Arduino board.

    Nice to have:
    solderless breadboard
    (3) tactile switches or (1) full cycle rotary encoder with detent shaft and built in momentary switch
    If you don't have the switches or encoder, the demo will work by tapping a jumper (connected to the pullup resistor and analog pin) to each resistor node
    as required. AnalogRead levels used in the sketch depend on your components and as always with analog circuits are observed rather than calculated values.

    Build the circuit starting without encoder or switches and program the Arduino board. Momentarily connect each node of the ladder to the analog pin. Make/break times may be longer than typical with switches and you may see occasional repeated outputs. To duplicate the full quadrature cycle use one jumper for channel A and one jumper for channel B.
    Add the encoder to the circuit and test rate of decoded input and effects of not positioning the encoder in the detent position.

    The Sketch:

    This sketch separates analogRead output into two fields. AnalogRead levels for all nodes on the resistor ladder fall below an arbitrary value of 800. This is where the work is done, whereas anything above 800 tells us that the encoder has returned to a detent position and all switches are open. Controlling directional flow of this function is provided by Gatekeeper (type Boolean) which either kicks the flow of the sketch back to the calling function (void loop) or allows the flow to proceed further into the function. While Gatekeeper has two conditions (Boolean true or false), I prefer to look at it as 'On' or 'Off' and view movement from that of a switch in a stable position. Conditions for passage of analogRead levels above 800 are opposite to that of those for switch closures.


    In real time, all switches are open and it has been a digital life time since the last switch was pushed or rotated. Gatekeeper is "off" and continuous analogReads remain above 800 with minimum code processed before the flow of the sketch returns to void loop() for the next go around. Closing any switch pulls the read below 800 allowing more of the function to be processed. The analogRead value may not match any programmed value and after passing through the function, flow returns to void loop() with all settings unchanged.

    Now if the analogRead level matches a programmed value, the coding for that value is run and Gatekeeper is turned "on" before passing out of the function. While that switch or any combination of switches remains closed, low value analogReads are turned back by Gatekeeper, thereby stopping repeated output for the same button push. That analog pin is effectively dead for input by the operator.

    When the encoder returns to the detent position or the pushbutton(s) is released, a single analogRead above 800 passes beyond Gatekeeper, and before exiting the function changes Gatekeeper back to "off" so the next closure of any switch may be processed.

    For this example you cannot leave the encoder part way between detents and detect closure of the tactile pushbutton. Expand the circuit to run two or more "radios" and one stuck encoder could shut down much of your stack. The last function of the demo sketch monitors only the switches for quadrature input and flashes an LED when it detects slow encoder movement or no return to the detent position. When the encoder knob is comfortably accessible, you can develop a habit of rubbing the knob in the reverse direction before releasing to confirm that the shaft is in the detent position.

    Rotary Encoder includes project schematics and Arduino demo sketch.

    Rotary Encoder

    The original post is enclosed in the following zip including the jpgs below

    Single Analog Rotary Encoder In A
    Attached Images Attached Images
    Last edited by BushPilotWannabe; 08-10-2016 at 10:17 PM. Reason: Added hot rodded demo. Now if I can only replace that early construction photo.
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  3. Thanks skino thanked for this post
    Likes skino liked this post
  4. #3
    75+ Posting Member

    BushPilotWannabe's Avatar
    Join Date
    Jan 2014
    Alberta, Canada
    Contribute If you enjoy reading the
    content here, click the below
    image to support MyCockpit site.
    Click Here To Contribute To Our Site

    Re: Lowering The Bar In A Can

    Simple alternate construction of JimNZ's "Arduino Radio Panel for M$ FSX"

    Yes, it uses analog Input/Output and frees up 6 pins.

    Replace those darned smiley faces with the number 8.

    The number of 5V and Gnd pins is limited on the UNO, to speed assembly of the circuit use I/O pins A3 & A4 as power and gnd.

    Add the resistor ladder circuit as per diagram. If you do have a rotary switch, connect the common pin to Analog5 and select 7 ajoining contacts to connect to the resistor ladder. If you have no rotary switch or momenary contact pushbuttons, a jumper can be used. The last selection will be remembered until the jumper is connected to a new rung on the resistor ladder. The PCB for a magneto switch as illustrated can be soldered to the back of the rotary switch. Cut the traces between SMD pads and add resistor to increase the number of switch positions. Only jumpers for 5V, GND and the analog connection are needed. SMD0805 resistors will work on 100 mill perf board. It's ugly but it works

    10k resistors work well. Use anything at hand and try to provide something like equal spacing. Avoid using less than 2k or 3k ohms total resistance.

    Run the sketch first with the MonitorAnalogInput() function enabled to determine the analogRead level for each resistor node. The values listed in void AnalogRotarySwitchOrPushbutton() are about what you would see using 1% tolerance resistors. Plug in your own numbers in to indentify the the rotary switch position or button push to the rest of the sketch.

    The sketch: Make these changes to JimNZ's "Arduino Radio Panel for M$ FSX" UNO version.

    1) Global Variables, add following before void setup()

    // added AnalogRotarySwitchOrPushbutton
    int monitorRotaryRegister;
    int oldAnalogRead;
    long timerMonitorRotarySwitch;

    // added MonitorAnalogInput
    long timerMonitorAnalog;

    2) void setup(),

    - change line for (int doutPin = 10; doutPin <= 19; doutPin++) to for (int doutPin = 10; doutPin <= 13; doutPin++)
    - add following before end of the function pinMode(int(17),OUTPUT);

    3) void loop(),

    - add the following after the line {ROTARYS();} // go and check the rotary encoder

    if ((millis()-timerMonitorAnalog)>100) {MonitorAnalogInput(); timerMonitorAnalog=millis();}
    if ((millis()-timerMonitorRotarySwitch)>300) {AnalogRotarySwitchOrPushbutton(); timerMonitorRotarySwitch= millis();}

    4) changes to void LCDMODE()

    - starting with line #4 change
    if (digitalRead(XX)==0 and active != YY) { to if (monitorRotaryRegister == ZZ and active != YY) {
    - there are (7) changes. value XX is not important the variable is replaced, value YY starts at 12 and is not changed, value ZZ starts at 1 and ends with 7.

    5) changes to void EQUALS()

    - starting with line #14 change
    if (com1 != XX && digitalRead(YY) == LOW) { to if (XX != YY && monitorRotaryRegister == ZZ) {
    - there are ( changes. value XX starts with com1 and end with dme2, this time value YY is replaced and not important, value ZZ starts with 1 and ends with 7.
    - value 7 is used in DME1 and DME2 routines.

    6) change to void INPUTPINS()

    - line #3 change for (int pinNo = 10; pinNo <= 19; pinNo++){ to for (int pinNo = 10; pinNo <= 13; pinNo++){
    - include the pins later as new uses are found for the I/O ports.
    - analog pin 3 and 4 will be available when resistor ladder 5V and GND are moved to respective power strips.

    7) new functions

    - add the following at the end of the sketch

    void AnalogRotarySwitchOrPushbutton(){
    // 1) Selects radio to be displayed on 16x2 LCD
    // 2) May seem sluggish but how often is the switch moved. I'd rather keep the program available for rotary encoder input.
    // 3) No traditional switch debounce needed but keep the switch contacts clean.
    int analogLevelHigh, analogLevelLow ;
    // Gatekeeper
    // 1) returns to void loop() if the rotary switch is open ie. reading only the pullup resistor
    // 2) returns to void loop() if the rotary switch has not moved
    analogLevelHigh = (analogRead(5)+4);
    analogLevelLow = (analogLevelHigh-;
    if((analogLevelHigh>oldAnalogRead) && (analogLevelLow oldAnalogRead = analogLevelLow+4;
    return ;
    if( (analogLevelHigh>130) && (analogLevelLow<130) && (monitorRotaryRegister!= 1)) { monitorRotaryRegister = 1; } // Serial.println(monitorRotaryRegister);
    if( (analogLevelHigh>260) && (analogLevelLow<260) && (monitorRotaryRegister!= 2)) { monitorRotaryRegister = 2; }
    if( (analogLevelHigh>38 && (analogLevelLow<38 && (monitorRotaryRegister!= 3)) { monitorRotaryRegister = 3; }
    if( (analogLevelHigh>516) && (analogLevelLow<516) && (monitorRotaryRegister!= 4)) { monitorRotaryRegister = 4; }
    if( (analogLevelHigh>643) && (analogLevelLow<643) && (monitorRotaryRegister!= 5)) { monitorRotaryRegister = 5; }
    if( (analogLevelHigh>769) && (analogLevelLow<769) && (monitorRotaryRegister!= 6)) { monitorRotaryRegister = 6; }
    if( (analogLevelHigh>895) && (analogLevelLow<895) && (monitorRotaryRegister!= 7)) { monitorRotaryRegister = 7; }
    oldAnalogRead = (analogLevelLow+4);

    void MonitorAnalogInput(){
    // 1) displays analog(5) level on the monitor and does not flood the display buffers
    // turn off by placing // in front of 'MonitorAnalogInput() ;' in void loop()
    Serial.println(analogRead(5)) ;
    } // end MonitorAnalogInput()

    BushPilotWannabe August 2015

    Attached Images Attached Images
    Last edited by BushPilotWannabe; 07-08-2016 at 11:09 AM. Reason: fix line if(((analogLevelHigh>oldAnalogRead) && (analogLevelLow) 1000 )){
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

Tags for this Thread