Results 1 to 8 of 8
  1. #1
    150+ Forum Groupie


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

    General Aviation Lower Switch Panel In A Can

    /*
    Two_Way_Main_I2C_Controller.ino

    General Aviation Lower Switch Panel In A Can

    Post 1 board to board transmission demo

    My thanks as always to the mycockpit.org community, the arduino.cc community and especially jim for www.jimspage.co.nz

    This sketch is a combination of many posts on the web. My thanks to the authors and the organizations.
    https://www.arduino.cc/en/Tutorial/MasterWriter
    https://michael.bouvy.net/blog/en/20...to-master-i2c/ Master #2 sketch

    Its ugly but it works. Why not use an Arduino Mega and pull the wires from the flap switch with stepper motor and driver, 16 or more
    toggle switches, landing gear switch and indicator leds to one location? Not to mention the circuitry needed by the
    pricipal use for the board. Given the choice between spaghetti code and spaghetti circuitry, I will choose the code
    every time. I hope that this has been brought down to a level that somebody can build this on a breadboard and adapt
    the circuit to their needs.

    A poor man's I2C copy of the SPI protocol is at the centre of the project. The two way transfer is not instantaneous, but
    it is coordinated. Every 60 milliseconds the Main board - Nano, Uno, or Mega - pulls either two bytes from the download
    stack or a single null character and fires the packet at the Deputy (Pro Mini). The data byte from the packet is stored
    in a variable and the Deputy in turn, pulls two data bytes or a null character from its upload queue and fires that off to
    the Main board. The Main board monitors downloads from Link2FS and the Deputy board monitors the switch panel hardware.

    To do this both boards must act as both controller and controllee. This is possible in this bare bones form because the
    Main board transmission triggers the transmission from the Deputy board. Any communication with other I2C devices on the
    circuit should use the more traditional 'transmit' and 'requestFrom' procedures all controlled by the Main board.

    In the 59 or so milliseconds until the next transmission, my Main board will be running King KFC 225_ish scratch built
    autopilot and a King KN 62A_ish DME as well as processing traffic both ways for the flap indicator and gear lamps. Maximum
    time to transmit two bytes in both directions is just under 2 milliseconds. Transmission of the single null byte is
    faster. In future parts, I will see if eliminating the return transmission of the null byte from the Deputy board is beneficial.

    DEMO setup: Any two Arduino boards connect SDA to SDA and SCL to SCL. GND to GND, and 5V to 5V. Get specific pins for your
    board from a pinout .jpeg or Arduino datasheet. This DEMO does not require pullup resistors for SDA and SCL.

    part 1. Main board I2C controller. This is the core sketch. Other posts will add user functions as equipment is added.
    - add code for Link2FS extractions and inputs as required.

    BushPilotWannabe
    May 2017
    */

    #include "Wire.h"

    volatile bool receive_acknol;

    byte dnLdQueue[20]; // holds ten 2 byte data packets (source identifier and data byte)
    long transmit_slot; // time in milliseconds for the next transmission to the Deputy board
    byte transmit_byte1; // source identifier -- magneto, flap, parallel out shift register to start with
    byte transmit_byte2; // data - switch position
    bool transmit_twoBytes; // switch between transmit one byte or two

    //download queue
    byte queue_last; // last occupied element of the queue
    long queue_slot; // time in milliseconds for the next call to QUEUE() function


    // *******************
    // VOID SETUP() **********************************************************************************
    // *******************

    void setup() {
    Wire.begin(0); // join i2c bus -- Wire begin() will not work when using Wire.onReceive() -- must have a device code
    Wire.onReceive(RECEIVE_EVENT);
    Serial.begin(115200);
    dnLdQueue[0] = 255;
    }// end setup

    // *******************
    // VOID LOOP() *********************************************************************************
    // *******************

    void loop() {

    //Receive incoming two bytes from Deputy board
    if (receive_acknol == true) {PROCESS_RECEIVED(); receive_acknol = false;}

    //Prepare the next packet for transmission -- millis() + 10000 stops repeats until reset by PROCESS_RECEIVED()
    if (millis() > queue_slot) {QUEUE(); queue_slot = millis() + 10000;}

    //Send the processed data to the Deputy board and schedule timed operations
    if (millis() > transmit_slot) {
    TRANSMIT();
    queue_slot = millis() + 50;
    transmit_slot = millis() + 60;
    }// close if millis() > transmit_slot

    //Generate simulated data
    DEMO();

    }// end loop()


    // ***************************
    // I2C TRANSMIT & RECEIVE *************************************************************************
    // ***************************

    void RECEIVE_EVENT(int howMany) {
    //Process everything outside the ISR

    receive_acknol = true;
    }// end RECEIVE_EVENT()


    void PROCESS_RECEIVED() {
    //We will process incoming data here

    //Display incoming data
    byte c;
    if (Wire.available()) {
    c = Wire.read();
    // if (c == 255) Serial.println(c);
    if (c == 254) {
    c = Wire.read();
    Serial.println(c);
    }
    if (c == 253) {
    c = Wire.read();
    Serial.print(" "); Serial.println(c);
    }
    }// close if Wire.available()

    //Remove fragments from the wire buffer
    if (Wire.available()) c = Wire.read();
    }// end PROCESS_RECEIVED()


    void TRANSMIT() {
    //Start communication, download bytes of data or null message, and end communication

    Wire.beginTransmission(8 ) ; // to device #8
    if (transmit_twoBytes == true) {
    Wire.write(transmit_byte1);
    Wire.write(transmit_byte2);
    transmit_twoBytes = false;
    //Serial.println(transmit_byte1);
    //Serial.println(transmit_byte2);
    }
    else Wire.write(255);
    Wire.endTransmission();
    }// end TRANSMIT()




    // ********************************
    // GENERATE OUTGOING DEMO DATA ************************************************************************
    // ********************************


    void QUEUE() {
    //Prepare TRANSMIT() for default one byte packet

    transmit_twoBytes = false;
    if (queue_last > 0) {

    //Transfer first two bytes of the queue to variables and freeze their value until transmission
    transmit_byte1 = dnLdQueue[1];
    transmit_byte2 = dnLdQueue[2];

    //Remove the first two elements from the queue
    for (int outer = 0; outer < 2; outer++) {
    for (int inner = 0; inner < queue_last; inner++) {
    dnLdQueue[inner] = dnLdQueue[inner + 1];
    }
    dnLdQueue[queue_last] = 255;
    queue_last--;
    }// close for int outer = 0 ....
    transmit_twoBytes = true;
    }// close if queue_last > 0

    //Lock out call to QUEUE() until loop() updates queue_slot
    queue_slot = millis() + 10000;
    }// end QUEUE()

    void DEMO() {
    //Supply two different series of numbers to dnLdQueue at different rates
    static int demo_counter = 115;
    static int demo_counter1 = 15;
    static long scheduleTimer1;
    static long scheduleTimer2;

    if ((millis() > scheduleTimer1) && (queue_last < 17)){ // queue size is 20 -- anything over will corrupt other data
    queue_last++;
    dnLdQueue[queue_last] = 253;
    queue_last++;
    dnLdQueue[queue_last] = demo_counter;
    demo_counter++;
    if (demo_counter == 151) demo_counter = 101;
    scheduleTimer1 = millis() + 100;
    }// close if millis() > scheduleTimer1
    if ((millis() > scheduleTimer2) && (queue_last < 17)) { // ditto
    queue_last++;
    dnLdQueue[queue_last] = 254;
    queue_last++;
    dnLdQueue[queue_last] = demo_counter1;
    demo_counter1++;
    if (demo_counter1 == 51) demo_counter1 = 1;
    scheduleTimer2 = millis() + 200;
    }// close if millis() > scheduleTimer2
    }// end DEMO()
    Last edited by BushPilotWannabe; 06-15-2017 at 08:24 PM. Reason: small changes to facilitate adding later components
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  2. #2
    150+ Forum Groupie


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

    Re: General Aviation Lower Switch Panel In A Can

    /*
    Two_Way_Deputy_I2C_Controller.ino

    General Aviation Lower Switch Panel In A Can

    Post 2 Deputy board to board transmission demo

    My thanks as always to the mycockpit.org community, the arduino.cc community and especially jim for www.jimspage.co.nz

    Now on to the Pro Mini Deputy board. When complete, the arriving transmission from Main is used to synchronize all
    functions. At zero ms, the outgoing packet is transmitted and the incoming packet updates execution times for the the flap indicator and
    gear position lights (servo or stepper motor and parallel out shift register). At plus 30 ms, analog pins A6 and A7
    are checked for movement of the flap switch and magneto switch. Any changes are added to the upLdQueue. At plus 40 ms two 74xx165
    serial out shift registers add any changes in scanned toggle switch status to the queue. Finally at plus 50, the first two
    bytes of the queue are passed to variables; ready when loop() enables the I2C transmission function following the
    arrival of the next packet from the Main board.

    Most of this DEMO is a copy of the Main I2C sketch. Use comments from there.

    BushPilotWannabe
    May 2017
    */

    #include "Wire.h"

    volatile bool receive_acknol;

    byte upLdQueue[20]; // holds ten 2 byte data packets (source identifier and data byte)
    long transmit_slot; // time in milliseconds for the next transmission to the Deputy board
    byte transmit_byte1; // source identifier -- magneto, flap, parallel out shift register to start with
    byte transmit_byte2; // data - switch position
    bool transmit_twoBytes; // switch between transmit one byte or two

    //download queue
    byte queue_last; // last occupied element on the queue
    long queue_slot; // time in milliseconds for the next call to QUEUE() function


    // *******************
    // VOID SETUP ***************************************************************************************
    // ******************

    void setup() {
    // Stepper pins 2 to 5
    // 74XX165 pins 6 to 9
    // 74xx595 pins 10 to 12
    // pin 13 -- Switched VCC for Hall effect sensor
    // Analog(0) pins 14 Hall sensor input
    // Analog(1) pin 15
    // pin 16 Analog(2) -- sim pause pushbutton
    // Analog(3) pin 17
    // ANALOG (4) I2C SDA pin 18
    // ANALOG (5) I2C SCL pin 19
    // ANALOG (6) FLAP SWITCH // Pro Mini & Nano only -- analog input -- not digital -- use it or lose it
    // ANALOG (7) MAGNETO SWITCH

    Wire.begin(8 ); // join i2c bus with address #8
    Wire.onReceive(RECEIVE_EVENT);
    Serial.begin(115200); // only required for the DEMO and programming later additions
    }// end setup()

    // *************
    // VOID LOOP ***************************************************************************************
    // *************

    void loop() {
    if (receive_acknol == true) {PROCESS_RECEIVED(); receive_acknol = false;}

    //Prepare the next packet for transmission -- millis() + 10000 stops repeats until reset by PROCESS_RECEIVED()
    if (millis() > queue_slot) {QUEUE(); queue_slot = millis() + 10000;}

    //Send the processed data to the Deputy board and schedule timed operations
    if (millis() > transmit_slot) {TRANSMIT(); transmit_slot = millis() + 10000;}

    //Generate simulated data
    DEMO();

    }// end loop()

    // ***************************
    // I2C TRANSMIT & RECEIVE ***************************************************************************************
    // ***************************

    void RECEIVE_EVENT(int howMany) {
    //Process everything outside the ISR

    receive_acknol = true;
    }// end RECEIVE_EVENT())


    void PROCESS_RECEIVED() {
    //We will process incoming data here

    //Display incoming data
    byte c;
    if (Wire.available()) {
    c = Wire.read();
    // if (c == 255) Serial.println(c);
    if (c == 254) {
    c = Wire.read();
    Serial.println(c);
    }
    if (c == 253) {
    c = Wire.read();
    Serial.print(" "); Serial.println(c);
    }
    }// close if Wire.available()

    // schedule calls by void loop() to other functions
    transmit_slot = millis();
    queue_slot = millis() + 50;

    //Remove fragments from the wire buffer
    if (Wire.available()) c = Wire.read();
    }// end PROCESS_RECEIVED()

    void TRANSMIT() {
    //Start communication, download bytes of data or null message, and end communication

    Wire.beginTransmission(0) ; // to Main board device #0
    if (transmit_twoBytes == true) {
    Wire.write(transmit_byte1);
    Wire.write(transmit_byte2);
    transmit_twoBytes = false;
    //Serial.println(transmit_byte1);
    //Serial.println(transmit_byte2);
    }
    else Wire.write(255);
    Wire.endTransmission();
    }// end TRANSMIT()


    // *****************************
    // MANIPULATE OUTGOING DATA ***************************************************************************************
    // *****************************

    void QUEUE() {
    //Prepare TRANSMIT() for default one byte packet

    transmit_twoBytes = false;
    if (queue_last > 0) {

    //Transfer the first two bytes of the queue to variables and freeze their value until transmission
    transmit_byte1 = upLdQueue[1];
    transmit_byte2 = upLdQueue[2];

    //Remove the first two bytes of the queue
    for (int outer = 0; outer < 2; outer++) {
    for (int inner = 0; inner < queue_last; inner++) {
    upLdQueue[inner] = upLdQueue[inner + 1];
    }
    upLdQueue[queue_last] = 255;
    queue_last--;
    }// close for int outer = 0 ....
    transmit_twoBytes = true;
    }// close if queue_last > 0

    //Lock out call to QUEUE() until loop() updates queue_slot
    queue_slot = millis() + 10000;
    }// end QUEUE()

    // ********************************
    // GENERATE OUTGOING DEMO DATA ***************************************************************************************
    // ********************************

    void DEMO() {
    //Supply two different series of numbers to upLdQueue at different rates
    static long scheduleTimer1;
    static long scheduleTimer2;
    static int demo_counter = 160;
    static int demo_counter1 = 60;

    if ((millis() > scheduleTimer1) && (queue_last < 17)){ // upLdQueue[] size is 20 -- anything over will corrupt other data
    queue_last++;
    upLdQueue[queue_last] = 253;
    queue_last++;
    upLdQueue[queue_last] = demo_counter;
    demo_counter++;
    if (demo_counter == 201) demo_counter = 151;
    scheduleTimer1 = millis() + 381;
    //Serial.println(queue_last);
    //Serial.println(demo_counter1);
    }// close if millis() > scheduleTimer1
    if ((millis() > scheduleTimer2) && (queue_last < 17)){ // ditto
    queue_last++;
    upLdQueue[queue_last] = 254;
    queue_last++;
    upLdQueue[queue_last] = demo_counter1;
    demo_counter1++;
    if (demo_counter1 == 101) demo_counter1 = 51;
    scheduleTimer2 = millis() + 85;

    }// close if millis() > scheduleTimer2

    }// end DEMO()
    Last edited by BushPilotWannabe; 06-15-2017 at 08:27 PM. Reason: small changes to facilitate adding later components
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  3. #3
    150+ Forum Groupie


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

    Re: General Aviation Lower Switch Panel In A Can

    
    General Aviation Lower Switch Panel In A Can part 3. Two_Way_Main_Analog_Devices

    My thanks as always to the MyCockpit.org community, the Arduino.cc community and especially Jim for www.Jimspage.co.nz

    This is beginning to look like a hard way of doing Jim's Multi Annunciator Panel -- http://www.jimspage.co.nz/Multi_Annunciators.htm
    We have the Main and Deputy boards communicating in parts 1 & 2. Parts 3 & 4 handle the analog inputs ie. flaps (potentiometer) and the magneto (rotary switch or potentiometer).rand So far this is continueing to employ common components. Everybody has at least two Arduino boards, one 12 pos. rotary switch, and one or two linear wound 50k rotary pots, right?

    This post expands on the post Two_Way_Main_I2C_Controller.ino by receiving two bytes of data from the Deputy board, identify the source, and then package the second byte into Jim’s top line 'SimConnect Inputs' for uploading to Link2FS.

    BushPilotWannabe
    2017

    */

    *** LOAD YOUR EXISTING 'Two_Way_Main_I2C_Controller.ino'
    AND SAVE THE FILE AS
    Two_Way_Main_Analog_Devices
    *** REMOVE THE PREAMBLE FROM THE FIRST SKETCH.

    *** The DEMO data generator is no longer required. Both sketches can run with no data inputs, TRANSMIT() will send null bytes indefinitely.
    *** DELETE THE 2 LINES BELOW FROM void loop()
    //Generate simulated data
    DEMO();
    *** DELETE THE ENTIRE USER FUNCTION 'void DEMO().'

    *** ADD THE NEXT 2 LINES AFTER '#include "Wire.h"' to enable use of F( macro. This stores literal Strings in program memory, taking up no random memory. Place the quote within the F() function brackets. example Serial.println("This uses ram memory"); becomes Serial.println(F("This uses no ram memory"));
    #include "WString.h"
    This text editor will not pass the less than or more than signs. To get the exact line needed go to http://forum.arduino.cc/index.php?topic=91314.0 then copy and paste line 6 to get the exact text for the following line.
    #define F(string_literal) (reinterpret_cast(PSTR(string_literal)))
    *** REPLACE THE OLD void PROCESS_RECEIVED() USER FUNCTION WITH THE FOLLOWING


    void PROCESS_RECEIVED(){
    //All incoming I2C Wire data is processed here
    byte c = 0;

    //Process system identifier
    if (Wire.available()) {
    c = Wire.read(); // process system identifier
    //Serial.println(c);

    //Process flaps
    if (c == 210){
    c = Wire.read();

    //Convert flap switch byte into Link2FS SimConnect Input code
    // format is 'C17' then 3 digit value 0 --> 100 %. 100% is 90 degrees of flap extension. -- That's more than a DHC-3 Otter
    byte tempByte = c;
    String tempString = String(tempByte);
    while (tempString.length() < 3){tempString = '0' + tempString;}
    // NOTE the F macro does not allow construction within the brackets. Use Serial.println(); instead.
    Serial.println("C17" + tempString);
    }// close if c = 210

    //Process magnetos
    if (c == 220){
    c = Wire.read(); // get the data byte

    //Convert magneto switch byte into Link2FS SimConnect Input code
    switch(c){
    // mags off
    case 0: {Serial.println("E11");} break;
    // mags left
    case 1: {Serial.println("E12");} break;
    // mags right
    case 2: {Serial.println("E13");} break;
    // mags both
    case 3: {Serial.println("E14");} break;
    // starter
    case 4: {Serial.println("E42");} break; // if you have Carenado’s C182RG add-on use "E35"
    }// close switch(c)
    }// // close if c = 220
    }// close if Wire.available()

    //Schedule call to prepare next batch of outgoing data
    queue_slot = millis() + 50;

    //Remove fragments from the wire buffer
    if (Wire.available()) c = Wire.read();
    }// end PROCESS_RECEIVED()

    *** You can slow the output to the serial monitor for debugging by changing the line in void loop() from transmit_timer = millis() + 60;
    to transmit_timer = millis() + 1000; . I have had trouble with queue overflow if BOTH DEMO() functions were not removed. Go back to
    transmit_timer = millis() + 60; when you are are ready to run at full speed.

    Hugh
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  4. #4
    150+ Forum Groupie


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

    Re: General Aviation Lower Switch Panel In A Can

    
    General Aviation Lower Switch Panel In A Can part 4. Two_Way_Deputy_Analog_Devices

    My thanks as always to the mycockpit.org community, the arduino.cc community and especially Jim for www.jimspage.co.nz

    Part 4 does not leave much of the earlier part 2 behind. Later posts will add a few lines in Global Variable Declarations area, and a couple new user functions as hardware is added to the panel.

    The flap switch uses a different approach to decoding from that of the magneto switch function. The Link2FS SimConnect Inputs is able to update FSX with the angle of the flaps as a percentage of rotation from zero to ninety degrees, and lets FSX select the nearest notch on the lever. Zero % deflection is flaps up and 100 % deflection is straight down. Aircraft have different flap settings so if a panel mounted lever is used, you may require flap lever stop plates for aircraft with differring numbers of flap positions. So far the flap lever is bolted to a flat topped knob on the potentiomer. Check out this web posting.
    http://azziagiuseppe.blogspot.ca/201...gn-part-2.html . The switch is a beautiful design and the use of gears simplifies mounting the flap lever to a potentiometer knob. I hope that it can be modified to provide room for a stepper motor and a hall effect transistor calibration point. Great idea using gear ratios to increase or decrease shaft rotation to maximize resolution of the device. Nice work. If an your aircraft requires an instruction to move the flaps to an upper or lower position, copy and adapt the code for the magneto switch. Think of the flap switch as a magneto switch turned sideways.

    The magneto switch may be either a rotary switch with an analog decoded resistor loadder per schematic
    http://www.mycockpit.org/forums/showthread.php? t=28740&highlight= post #3 or a high ohm potentiometer (10k or greater). MAGNETO_SWITCH() works with both devices. Unlike the sketch in the above URL, this post uses a ranges of numbers to determine position. Place the magneto switch between the low and high range and you have created the desired output. Instructions for each device are found in the comments of each function.

    BushPilotWannabe
    June 2017


    *** Load 'Two_Way_Deputy_I2C_Controller' AND SAVE THE FILE AS
    Two_Way_Deputy_Analog_Devices
    *** REMOVE THE PREAMBLE FROM THE FIRST SKETCH.

    *** ADD THE FOLLOWING 4 LINES TO THE Global Varialbles Section
    //analog pin processed switches
    long analogSwitch_slot; // time in milliseconds for the next call to MAGNETO_SWITCH_ANALOG() & FLAP_SWITCH_ANALOG()
    int flap_oldCode = 255; // last flap setting -- triggers switch output after startup
    byte Magneto_oldCode = 255; //last magneto setting -- ditto
    *** void loop()
    *** REPLACE THE 2 LINES BELOW
    //Generate simulated data
    DEMO();
    *** WITH THE NEXT 2 LINES
    //Process magneto and flap switches
    if (millis() > analogSwitch_slot) {MAGNETO_SWITCH_ANALOG(); FLAP_SWITCH_ANALOG(); analogSwitch_slot = millis() + 10000;}
    *** void PROCESS_RECEIVED()
    *** REPLACE THE USER FUNCTION PROCESS RECEIVED() WITH THE NEXT 15 LINES
    void PROCESS_RECEIVED() {
    //We will process incoming data here

    //Display incoming data
    byte c;
    if (Wire.available()) {
    c = Wire.read();
    // if (c == 255) Serial.println(c);
    }// close if Wire.available()

    // schedule calls by void loop() to other functions
    transmit_slot = millis();
    analogSwitch_slot = millis() + 20;
    queue_slot = millis() + 50;

    //Remove fragments from the wire buffer
    if (Wire.available()) c = Wire.read();
    }// end PROCESS_RECEIVED()
    *** CIRCUIT SET UP

    Analog Flap Switch
    Connect the potentiometer outside terminals to 5V and GND, and the wiper terminal to Pro Mini pin A6. Reverse the 5V and GND leads if the analogRead level does not increase as the pot is turned anticlockwise. For now, turn the potentiometer knob clockwise and position the knob until it is pointing to ten-thirty o’clock and the analogRead level is zero. Divide the space between ten-thirty o’clock and seven-thirty o’clock into the aircraft flap settings. The aircraft full flap extention is at the seven-thirty. Adjust global variable 'flap_adjust' until the potentiometer rotation matches the aircraft flap deflection.

    Magneto Switch
    A wiring diagram and a parts layout for a rotary switch mounted PCB is shown on http://www.mycockpit.org/forums/showthread.php? t=28740&highlight= post #3. Connect the 'A' terminal to pin A7 of the Pro MIni. Each circuit has slightly different inputs. . Follow the instruction in the remarks at the top of _MAG_SWITCH_ANALOG().

    *** REPLACE THE ENTIRE USER FUNCTION 'void DEMO()' AND THE MARKER ABOVE IT WITH THE FOLLOWING

    // **************************
    // ANALOG FLAP SWITCH *************************************************************************
    // **************************

    void FLAP_SWITCH_ANALOG(){


    //ADJUST 'flap_adjust' until the flap lever sets the flaps when moved onto your 'flap lever stops' in all positions
    float flap_adjust = 675;
    byte flap_pin = 6;
    int flap_code;


    // PLACE "//" IN FRONT OF the next line after recording your flap_pin outputs.
    Serial.println(analogRead(flap_pin));

    // Gatekeeper -- return to the calling function if the analog pin reading is not stable
    // increase '< & >' values if the flap does not move within one or two calls to the function
    int firstRead = analogRead(flap_pin);
    int secondRead = analogRead(flap_pin);
    if ((firstRead + 3 < secondRead) || (firstRead - 3 > secondRead)) return;

    //RETURN CHANGE in flap lever's position as a percentage of the flap movement (0 to 90 degrees)
    //Flap lever moved to 30 degree flap extension may show up as flap_code equals 50 or higher.
    flap_code = byte(map(firstRead, 0, flap_adjust, 0, 100));

    // Return to calling function when the switch has not moved OR induced voltage at analog pin creates change in output
    if (((flap_code +2) > flap_oldCode) && ((flap_code - 2) < flap_oldCode)) return;

    // OR pile the fresh data bytes on end of the queue
    else {
    queue_last++; upLdQueue[queue_last] = 210;
    queue_last++; upLdQueue[queue_last] = flap_code;
    // Serial.println( flap_code);
    flap_oldCode = flap_code;
    }// close else if flap_code + 2 ....
    }// end FLAP_SWITCH_ANALOG()


    // ****************************
    // ANALOG MAGNETO SWITCH ******************************************************************
    // ****************************

    void MAGNETO_SWITCH_ANALOG(){
    byte Magneto_pin = 7;
    int Magneto_code;

    // PLACE "//" IN FRONT OF the next line after recording your analog pin outputs for the rotary switch positions.
    Serial.println(analogRead(Magneto_pin));

    // Rotary Switch:
    // Record the analog levels displayed for each rotary switch position.
    // Calculate a mid point between ajacent switch positions and replace '42' below with your numbers
    // Potentiometer:
    // Draw a radius from the pot 30 degrees apart for each magneto switch position. Place the pointer of
    // the potentiometer mid way between magneto labels and record your values. Replace '42' below with your numbers.

    int midPoint_0 = 42; // mid point between 'Off' and 'Left'
    int midPoint_1 = 42; // mid point between ‘Left’ and ‘Right’
    int midPoint_2 = 42; // mid point between ‘Right’ and ‘Both’
    int midPoint_3 = 42; // mid point between ‘Both’ and ‘Start’
    // For rotary switch - or just a jumper tapping a resister node - analogRead level of last rotary switch position ‘Start’.
    // For potentiometers, point the knob to clockwise edge of the ‘Start’ segment on the dial and add 20.
    int start = 42;

    // Gatekeeper -- return to void loop() if the analog pin reading is not stable
    int firstRead = analogRead(Magneto_pin);
    int secondRead = analogRead(Magneto_pin);
    // increase '<' and '>' values if FSX magneto is slow to react to movement of the switch
    if ((firstRead + 3 < secondRead) || (firstRead - 3 > secondRead)) return;

    //PROCESS MAGNETO SWITCH SETTINGS
    // Match analog reading to the switch position
    byte switchPosition = 0;
    if (firstRead < midPoint_0) Magneto_code = 0; // off
    if ((firstRead > midPoint_0) && (firstRead < midPoint_1)) Magneto_code = 1; // left
    if ((firstRead > midPoint_1) && (firstRead < midPoint_2)) Magneto_code = 2; // right
    if ((firstRead > midPoint_2) && (firstRead < midPoint_3)) Magneto_code = 3; // both
    if ((firstRead > midPoint_3) && (firstRead < start)) Magneto_code = 4; // start

    //Return to calling function when switch has not moved
    //OR put fresh data bytes on end of the queue
    if (Magneto_code == Magneto_oldCode) return;
    else {
    queue_last++;
    upLdQueue[queue_last] = 220;
    queue_last++;
    upLdQueue[queue_last] = Magneto_code;
    Magneto_oldCode = Magneto_code;
    //Serial.println( Magneto_code);
    }// close else if Magneto_code ....
    }// end MAGNETO_SWITCH_ANALOG()
    Hugh
    Last edited by BushPilotWannabe; 08-01-2017 at 11:23 PM. Reason: add the delete remnants routine to PROCESS_RECEIVED()
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  5. #5
    150+ Forum Groupie


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

    Re: General Aviation Lower Switch Panel In A Can

    /*
    Two_Way_Main_XX595_Parallel_Out.ino

    General Aviation Lower Switch Panel In A Can

    Post 5 XX595 Parallel Out Shift Register

    My thanks as always to the MyCockpit.org community, the Arduino.cc community and especially Jim for www.Jimspage.co.nz


    Posts #5 and #6 add hardware for the landing gear indicator lights and a 'Sim Paused' LED to the panel. No two aircraft have the same condiguration, so I am going with an inverted 'V' of three dual colour lights using 5mm red green or red green blue LEDs inside 5mm bezels from eBay. There are are 8 pins on the XX595 chip. Pin 7 is used to light a LED when when the sim is in the paused mode. One pin is still available as well as the ability to daily chain additional XX595 chips. If you are building a sim with only one or two gear lights, skip the construction and drive the 'gear' LEDs and the 'sim paused' LED directly from the Pro Mini and maybe save a pin. Salvage what code you can from case 'Y':, gear down is '222', and anything else is lamp off (gear not safe).

    Also added to the sketch are monitor Link2FS 'profile in use', manifold pressure, flap handle position, airplane on ground, parking brake, and main bus voltage. Some of which requires a small piezo audio transducer connected between Arduino pin 13 and ground to produce various warnings.

    BushPilotWannabe
    July 2017
    */

    *** Link2FS EXTRACTIONS
    - Run Link2FS.
    - for each Link2FS 'profile in use'. THIS PROJECT USES g01.v6card1 for retractable gear aircraft AND g02.v6card1 for the default FSX C172
    - Go to the Link2FS tab connected to your Main board.
    - Open Extractions(1) and Extractions(2) tabs and check the boxes next to the following: - Punch the 'save all boards and startup button.
    - Go to the Link2FS tab connected to your Main board.
    - Open 'Experts' tab and 'Simconnect Extractions' tab.
    - On the first available line enter "FLAPS HANDLE INDEX" and punch 'RESET'.
    - Go to the 'card tab' connected with your Main board and open 'Experts' tab.
    - Check the box next to 'FLAPS HANDLE INDEX', and note the letter beside the '#' sign
    - Punch the 'save all boards and startup button.
    - Connect your Main board, run FSX, Link2FS and enter a refresh time for the 'card' connected to the Main board
    - check that Link2FS downloads the character streams for these outputs to your board.

    *** LOAD YOUR EXISTING 'Two_Way_Main_Analog_Devices.ino' AND SAVE THE FILE AS
    "Two_Way_Main_XX595 Parallel Out.ino"
    *** CHANGE THE LINE 'Post 3 Analog Inputs' TO
    'Post 5 XX595 Parallel Out Shift Register'
    *** GLOBAL VARIABLES DECLARATION
    *** PASTE THE FOLLOWING 18 LINES TO GLOBAL VARIABLES
    //system
    // scale flap extensions to fit 40 degree flap indicator
    // element equals total deflection / 40 * flap position in degrees
    const byte system_flap0[4] = {0, 14, 27, 40}; // max 30 degree
    const byte system_flap1[4] = {0, 10, 20, 40}; // max 40 degree
    const byte system_flap2[5] = {0, 5, 22, 29, 40}; // 4 position (Maule) may be used for aircraft without Link2FS profile
    bool system_busVoltage; // turns off anything electrical when there is no voltage to run the motor or circuit
    byte system_flapHandle;
    byte system_gearStatus;
    bool system_gearUP;
    byte system_flapPosition;
    byte system_manPresOld;
    bool system_manWarning;
    bool system_parkBrk;
    bool system_onGround;

    byte klaxon_pin = 13; // alternator and battery switches in sync warning
    String Link2FS_profile;

    *** void setup()
    *** PASTE THE FOLLOWING LINE AFTER THE LINE 'void setup() {'
    // pin 13 -- used by tone() for miscellaneous warnings -- can be varied in tone and length
    *** void loop()
    *** PASTE THE FOLLOWING 8 LINES AT THE END OF void loop()
    char serial_codeIn;
    if (Serial.available()){ // now lets check the serial buffer for any input data
    serial_codeIn = getChar();
    // '<' and '#' and the user functions are used in later longer posts -- add all three now
    if (serial_codeIn == '<') {LESSTHAN();}// The first identifier is "<"
    if (serial_codeIn == '?') {QUESTION();}// The first identifier is "?"
    if (serial_codeIn == '#') {POUND();} // The first identifier is "#"
    }// close if (Serial.available()

    *** USER FUNCTIONS
    *** ADD THE FOLLOWING TO THE SKETCH

    // *********************
    // Serial Streaming *************************************************************************
    // *********************

    char getChar(){ // Get a character from the serial buffer
    while(Serial.available() == 0);// wait for data
    return((char)Serial.read());// Thanks Doug
    }// end getchar()


    void LESSTHAN(){ // The first identifier was "<"
    byte CodeIn = getChar(); // Get another character
    switch(CodeIn) {// Now lets find what to do with it

    case 'I': { // Airplane On Ground
    system_onGround = (getChar() == '1');
    }// close case I:
    break;

    case 'q': { // Parking Brake -- sounds warning if applied when airborne
    system_parkBrk = (getChar() == '1');
    if ((system_onGround == false) && (system_parkBrk == true)) tone(klaxon_pin,800, 1000);
    }// close case q:
    break;

    }// close switch
    }// end LESSTHAN()

    void QUESTION(){ // The first identifier was "?"
    char serial_codeIn = getChar(); // Get another character
    //Serial.println(serial_codeIn);
    switch(serial_codeIn){ // Now lets find what to do with it - like convert it to an integer

    case 'K':{ // Main Bus Voltage
    // Senses main bus voltage -- disables gear & flap motors -- disables anything electrical
    queue_last++; dnLdQueue[queue_last] = 210;
    system_busVoltage = (getChar() != '0');
    queue_last++; dnLdQueue[queue_last] = (2 + system_busVoltage); // power off 2 + 0 = 2, power on 2 + 1 = 3
    //Serial.print("system_busVoltage "); Serial.println(dnLdQueue[queue_last]);
    for (byte x = 0; x < 3; x++) getChar(); // only first digit is required to show voltage present
    }// close case 'K'
    break;

    case 'Q':{ // Manifold Pressure Eng #1 and Wheels Up warning
    // Senses manifold pressure for gear up warning when man pres below 12 psi
    byte manPres = (byte(getChar()-'0'))*10;
    manPres += byte(getChar()-'0');
    getChar(); getChar();
    if ((manPres < 8 ) && (system_manPresOld >= 8 ) && (Link2FS_profile == "g01")) system_manWarning = true;
    if ((system_manWarning == true) && (system_gearStatus < 222)) {
    tone(klaxon_pin, 1300, 1500); system_manWarning = false;}
    if ((system_manWarning == true) && (manPres >= 8 )) system_manWarning = false;
    system_manPresOld = manPres;
    //Serial.print("system_manPresOld "); Serial.println(system_manPresOld);
    }// close case 'F'
    break;

    case 'Y':{ //Gear Position (Nose, L, R)
    system_gearStatus = (byte(getChar()-'0'))*100;
    system_gearStatus += (byte(getChar()-'0'))*10;
    system_gearStatus += byte(getChar()-'0');
    queue_last++;
    dnLdQueue[queue_last] = 200;
    queue_last++;
    dnLdQueue[queue_last] = system_gearStatus;
    //Wheels Up warning
    if ((Link2FS_profile == "g01") && (system_gearStatus < 222)) {
    if ((system_manWarning == true) && (system_gearUP == true)) {
    tone(klaxon_pin, 1300, 1500); system_gearUP = false; }
    if ((system_flapHandle > 2) && (system_gearUP == true)) {
    tone(klaxon_pin, 1300, 1500); system_gearUP = false; }
    }// close if Link2FS_profile = g01
    }// close case 'Y':
    break ;

    case 'e':{ // Link2FS Profile
    Link2FS_profile = "";
    for (byte counter=0; counter <3; counter++) Link2FS_profile += getChar();
    // Serial.print("Link2FS Profile "); Serial.println(Link2FS_profile);
    }// close case 'e':

    case 'f':{ // FSX paused -- only used by the Deputy board -- no global variables needed
    queue_last++; dnLdQueue[queue_last] = 210;
    queue_last++; dnLdQueue[queue_last] = (getChar() == '1'); // not paused = 0, paused = 1
    //Serial.print("system paused "); Serial.println(dnLdQueue[queue_last]);
    }// close case 'f':
    break;
    }// close switch
    }// end QUESTION()

    void POUND(){ // The first identifier was "#"
    //Enter the capitalized text for each case in EXPERTS SimConnect Extractions tab
    char serial_codeIn = getChar(); // Get another character
    //Serial.println(serial_codeIn);
    switch(serial_codeIn) { // Now lets find what to do with it - like convert it to an integer

    case 'H':{ // Flap handle index -- SimConnect FLAPS HANDLE INDEX
    system_flapHandle = byte(getChar() - '0');
    queue_last++; dnLdQueue[queue_last] = 205;
    queue_last++;
    if (Link2FS_profile == "g01") {dnLdQueue[queue_last] = system_flap1[system_flapHandle];}
    else if (Link2FS_profile == "g02") {dnLdQueue[queue_last] = system_flap0[system_flapHandle];}
    else dnLdQueue[queue_last] = system_flap2[system_flapHandle];
    //Wheels Up warning -- this is linked to the flap switch not the flap extention indicator
    if ((system_flapHandle > 2) && (Link2FS_profile == "g01") && (system_gearStatus < 222)) {
    tone(klaxon_pin, 1300, 1500);}
    }// close case 'I'
    break ;

    }// close switch
    }// end POUND()
    Hugh
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  6. #6
    150+ Forum Groupie


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

    Re: General Aviation Lower Switch Panel In A Can

    /*
    Two_Way_Main_XX595_Parallel_Out.ino

    General Aviation Lower Switch Panel In A Can

    Post 6. Landing Gear LEDs, Gear UP Warnings, and Sim Paused Status LEDs

    I used a SN74HC595N 16 pin DIP parallel out shift register for this project. All pin names and variables names are taken from the manufacture's data sheet. Many chips will work, I recommend that you change the pin names used in the sketch to those specific to your chip and the data sheet used. Pin 13 OE (active low) of the 16 pin DIP package is hardwired to GND, and pin 10 SRCLR (active low) is hardwired to VCC keeping the the LEDs always active. They may not be turned on but they are not disabled. Run a power lead from VCC to all anodes, and ground the LEDs though the chip outputs. Raising the voltage of 74HC595 outputs HIGH turns the LED off. The same LOW or HIGH output works for chips with open latch output.

    There are many shift register tutorials and videos on the web. Have a look at this one https://www.youtube.com/watch?v=7VYxcgqPe9A The shift register is so widely used that you may not find source code for your exact needs. No amount of video can overcome the industry's terrible naming of the register's pins. Maybe its a secret handshake for 2 yr Tech grads.
    The code itself for XX595REG_OUT() is simple, single purpose output. No libraries are used. Start with all bits of the assembly byte HIGH. If an LED is to be illuminated, set the corresponding bit LOW, and shift the assembly byte into the XX595 shift register.
    The easiest to use and cheapest source for the chip would be a 74HC595 breakout board available on line. Dress up the project and use angle pin headers between the Pro Mini and the breakout boards. Hopefully all components can be found locally or in a single online store.
    The build so far puts the three red/green 5mm LEDs on a scrap of two sided proto board using point to point wiring to join the wire harness headers to the voltage takeup resistors to the LEDs. Would you believe a 5.6k ohm resistor for red cathodes and a 56k ohm resistor for green cathodes to get a nice glow.

    Almost half the jumpers used so far are VCC and GND pulled back along with the data cables. Could be time to run a VCC bus and a GND bus across the panel. Did I mention that building custom twisted cables can be very relaxing? 28 or 30 awg wire is available in all ten resister code colours on line in 5 m coils. A lighted magnifying glass stand and cheap crimpers for Dupont terminals complete the equipment. The Dupont connectors and housings are available in starter kits, Some of everything and enough to get you started.

    Bushpilotwannbe
    July 2017+


    *** LOAD YOUR EXISTING 'Two_Way_Deputy_Analog_Devices.ino' AND SAVE THE FILE AS
    "Two_Way_Deputy_XX595_Parallel_Out.ino"
    *** CHANGE THE LINE 'Post 4 Deputy Analog Inputs' TO THE FOLLOWING
    Post 6. Landing Gear and Sim Paused Status LEDs
    *** PASTE THE FOLLOWING 13 LINES BEFORE THE LINE '#include "Wire.h"' LEAVE THE COMMMENT MARKS IN PLACE
    /*
    user functions finder -- this sketch could run 500 lines
    highlight the function, press + , then punch 'FIND' twice
    RECEIVE_EVENT(int howMany) {
    PROCESS_RECEIVED() {
    TRANSMIT() {
    QUEUE() {
    FLAP_SWITCH_ANALOG() {
    MAGNETO_SWITCH_ANALOG() {
    // STEPPER_MOTOR() { // coming soon
    // XX165REG_IN() { // coming soon
    XX595REG_OUT() {
    */

    *** ADD THE FOLLOWING 10 LINES TO THE Global Varialbles Section
    //XX595 PARALLEL OUT REGISTER
    byte RCLK = 10; // chip pin # 12 -- Transfers Serial Register to Output Buffer when LOW goes HIGH (edge triggered)
    byte SER = 11; // chip pin # 14 -- Shift Register input pin
    byte SRCLK = 12; // chip pin # 11 -- Copies bit to store when LOW and enabled -- Shifts bit sideways when LOW goes HIGH
    byte XX595Reg_received; // data byte downloaded from the Main board
    long XX595Reg_slot; // scheduled time to call XX595REG_OUT()

    //System
    bool system_busPowered;
    bool system_simPaused;

    *** void setup()
    *** REPLACE THE LINE '// 74xx595 pins 10 to 12' WITH THE FOLLOWING 4 LINES
    // 74xx595 pins 10 to 12
    pinMode(RCLK, OUTPUT); // pin 10
    pinMode(SER, OUTPUT); // pin 11
    pinMode(SRCLK, OUTPUT);// pin 12

    *** void loop()
    *** ADD THE FOLLOWING 6 LINES AFTER THE LINE STARTING 'if (millis() > transmit_slot) ....
    //Display changes to LED Array -- RECEIVE_EVENT + 2 (milliseconds) after packet received
    if (millis() > XX595Reg_slot) {
    if (system_busPowered == true) {XX595REG_OUT(XX595Reg_received);}
    else {XX595REG_OUT(0);}
    XX595Reg_slot = millis() + 10000;
    }// close if millis() > XX595Reg_slot

    *** void PROCESS_RECEIVED()
    *** ADD THE FOLLOWING LINE AFTER 'void PROCESS_RECEIVED() {'
    static bool process_paused;
    **** REPLACE THE LINE '// if (c==255) Serial.println(c);' WITH THE FOLLOWING 20 LINES
    // if (c == 255) Serial.println(c); // look for and display a null byte coming in from the Main board

    //Process wire data (undercarriage)
    if (c == 200) {
    XX595Reg_received = Wire.read();
    XX595Reg_slot = millis() + 2;
    }// close if c = 200

    //Process wire data -- bus powered -- anything affected will be continue when reversed
    if (c == 210) {
    byte tempByte = Wire.read();
    //sim paused
    if (tempByte == 0) {system_simPaused = false; process_paused = true;} // XX595Reg_slot = millis() + 10;}
    if (tempByte == 1) {system_simPaused = true; process_paused = true;} // XX595Reg_slot = millis() + 10;}
    //bus power -- anything affected will be continue when reversed
    if (tempByte == 2) system_busPowered = false;
    if (tempByte == 3) system_busPowered = true;
    XX595Reg_slot = millis() + 10;
    Serial.println(tempByte);
    }// close if c = 210

    *** ADD THE FOLLOWING USER FUNCTION TO THE SKETCH

    // *********************************
    // PARALLEL SHIFT OUT SN74HC595N***********************************************
    // *********************************

    void XX595REG_OUT(int dataByte) {
    //DISPLAY GEAR & SIM PAUSED LEDS
    byte byteToTransmit;
    //Set up led register
    //Serial.println("xx595");
    //SET ALL BITS HIGH
    byteToTransmit = 255;
    //Serial.println(dataByte);
    // Nose Gear -- All bits are high -- clear bits of lamps to be illuminated
    if (dataByte >= 200) {bitClear(byteToTransmit, 6); dataByte -=200;} // down
    else if (dataByte >= 100) {bitClear(byteToTransmit, 1); dataByte -=100;} // transit
    //Serial.println(dataByte);
    // Left Gear
    if (dataByte >= 20) {bitClear(byteToTransmit, 2); dataByte -=20;} // down
    else if (dataByte >= 10) {bitClear(byteToTransmit, 3); dataByte -=10;} // transit
    //Serial.println(dataByte);
    // Right Gear
    if (dataByte >= 2) {bitClear(byteToTransmit, 5);} // down
    else if (dataByte >= 1) {bitClear(byteToTransmit, 4);} // transit

    //Display system_simPaused LED -- NOTE simPaused is active HIGH -- gear is active LOW
    bitWrite(byteToTransmit, 7, !system_simPaused);

    //DRIVE THE SHIFT REGISTER CLOCK LOW to enable edge triggered 'RCLK' when it is driven high
    digitalWrite(RCLK, LOW);
    // Serial.println(byteToTransmit, BIN);
    //TRANSFER EIGHT BITS OF DATA INTO THE SERIAL REGISTER -- use down counter to process the MSB first
    for (int shiftCounter = 7; shiftCounter > -1; shiftCounter--){

    //DRIVE THE SERIAL REGISTER CLOCK LOW;
    digitalWrite(SRCLK, LOW);

    //DRIVE SER HIGH OR LOW TO MATCH THE BIT IN 'byteToTransmit' TO BE TRANSFERED TO SERIAL REGISTER
    digitalWrite(SER, bitRead(byteToTransmit, shiftCounter));

    //DRIVE SERIAL REGISTER CLOCK HIGH TO STORE BIT ON SER IN ON THE SERIAL REGISTER
    digitalWrite (SRCLK, HIGH);
    }// close TRANSFER EIGHT BITS OF DATA loop


    //DRIVE THE REGISTER CLOCK HIGH TO TRANSFER 8 BITS INTO THE OUTPUT BUFFERS
    digitalWrite(RCLK,HIGH);

    // THAT'S IT. When you can see what is going on. It is easier to understand what is happening.
    }// end XX595REG_OUT()
    Hugh
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  7. #7
    150+ Forum Groupie


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

    Re: General Aviation Lower Switch Panel In A Can

    /*
    EDIT Change something that should have been caught in the original post Hugh, August 17

    Two_Way_Main_XX165_Shift_Register.ino

    General Aviation Lower Switch Panel In A Can

    part 7. Two_Way_Main_XX165_Shift_Register

    My thanks as always to the MyCockpit.org community, the Arduino.cc community and especially Jim for www.Jimspage.co.nz


    Up 'til now we have a whopping two switches processed and seven coloured LEDs displayed. Two SN74HC165N shift registers can handle the basic switches of a single engine aircraft with retractable gear and an adjustable pitch prop. Adding more shift registers increases the number of switches monitored with no increase in the MCU pin count and only a small increase in current draw from the Main board.

    This - more so than the others posts - is a builder project. Location of the shift register may influence the order that the switches are read. This is no problem. Each switch output is matched to a switch case number in PROCESS_RECEIVED(). Moving a switch to another shift register input simply requires a change to the number of the 'case :' statement and then move the statement into its place in the list of switch case statements. Low to high with place keeper statements (case x: { }; break; ) for any unused pins. x is the number of the empty case.

    When starting Link2FS for use and updating the extractions boxes, select the 'profile' for the aircraft to be simmed. I use "g01" for everything used with the FSX default C172 and "g02" for the C182RG. The sketch will read 'Link2FS_profile' when Link2FS starts or resets and control which branch of some code is executed. For example, "g01" restricts the movement of the alternator switch. "g02" does not.

    WARNING! I have found during development of this project that after several updates of the Arduino boards, the 'profile in use' may change from the user profile saved as the 'startup file' to the default .v6card1 even though it was deleted from the list of profiles. The settings in the default file did not match the settings for the aircraft and features that was being developed. Some systems would work, others would not. It all depended on which extractions were set in the current profile. This is no problem in daily use. Load the profile, fly the airplane and shut down when done. Must be a close cousin to the do I need a single or a double equal sign gremlin. If I were not comparing setups between the default C172 and those equipped with retractable gear, I would have put them in seperate installations of Link2FS.

    Only one case statement is included as an example for each group with similar code. The case statements differ only by the details of one or two variables, which are tabled within following comments. Plug the details into the sample instruction and match the case number to the code passed from the Deputy board when the switch is moved.

    Issues.
    - Grounding the 'RST' pin of the Deputy board may interfere with the Arduino serial bus for that USB channel. You lose the ability to display hack point messages, and the USB programmer must be disconnected from the computer to regain the ability to program the Pro MIni. The Pro Mini board was selected because the completed project has no need for a computer connection and it was cheap. This kinda slows developement but what the heh! Some web postings suggest pushing the reset button two times.
    - The landing gear LEDs are turned off after reseting the Deputy Pro Mini board until the gear lever is moved or until Link2FS scheduled update times out. Both actions send a gear status code to the Deputy board.
    - The alternator switch may not update correctly if the battery switch is 'off' before resetting the Deputy board. Develope a sequence for switching the battery and alternator switches, master on, alternator on, alternator off, battery off. When the FSX instrument panel is not visible, moving both switches through one cycle will coordinate the FSX and the hard switches. Use the mouse to move all switches to the opposite position from that of the hard panel, and watch the FSX switches move to match the hard panel when the Deputy board resets.
    - Lastly, this is a closed system. If the single null (255) byte or the two pack (identifier and data bytes) are put on the I2C bus, they must be removed from the wire buffer of the other board on that cycle. A second 'if Wire.available()) c = Wire.read();' has been added before exiting the PROCESS_RECEIVED()' function. This will remove any data bytes that cannot be processed.
    - For the dreaded C172 Master Switch, there may just be enough room inside a SPST rocker switch for a solenoid plunger to push on the backside of the the 'ON' half of the rocker. When the battery and alternator switches are on and you move the ALTERNATOR switch to off, the solenoid pushes the battery switch to the 'off' position and then uploads 'alternator off' pause 'battery off'. Put the battery switch in upside down and reverse the master switch boolean state ('if false' becomes 'if true'). Pushing the alternator switch 'on' when both switches are 'off' moves the upper half of the battery switch in and uploads 'battery on' pause 'alternator on'. Until then, moving the battery and alternator switches incorrectly triggers a short beep without uploading any instruction to Link2Fs. Move the switch back into its last position and then push both switches in the proper sequence. Remember, 'battery on before alternator on', 'alternator off before battery off'.

    BushPilotWannabe 2017
    */

    *** Open your file Two_Way_Main_XX595_Shift_Register.ino and save it to a new folder
    Two_Way_Main_XX165_Serial_Out.
    *** CHANGE THE LINE 'Post 5 XX595 Parallel Out Shift Register' TO
    'Post 7 XX165 Serial Out Shift Register'
    *** Link2FS Extractions
    Check the box for ?F, and ?s in Extractions(2)

    //*** Global Variables Section
    //*** PASTE THE FOLLOWING 2 LINES FOLLOWING THE LAST ENTRY UNDER //systems
    bool system_alternatorSwitch;
    bool system_batterySwitch;

    *** void PROCESS_RECEIVED()
    *** PASTE THE FOLLOWING 2 LINES BEFORE THE LINE '//Process flaps'
    //GATEKEEPER
    if (c == 255) return;
    *** PASTE THE FOLLOWING TWO LINES BEFORE THE LINE '}// close if Wire.available()'
    //PROCESS OUTPUT FROM SHIFT REGISTERS
    if (c == 230){PROCESS_SWITCHES(Wire.read());}

    *** void QUESTION()
    PASTE THE FOLLOWING 2 CASE STATEMENTS IN ALPHABETICAL SEQUENCE

    case 'F':{ // Battery Master
    system_batterySwitch = (getChar() == '1');
    }// close case 'F'
    break;

    case 's':{ // Master Alternator Engines 1, 2 --
    system_alternatorSwitch = (getChar() == '1');
    //Serial.print("alternator "); Serial.println(system_alternatorSwitch);
    getChar(); //do second alternator when I can afford a twin
    }// close case 's':
    break ;
    *** ADD USER FUNCTION TO SKETCH

    // *****************************************
    // XX165 SERIAL IN SHIFT REGISTER ***********************************************************************
    // *****************************************
    void PROCESS_SWITCHES(byte switch_incoming) {
    bool switch_closed = true;
    byte switch_number;
    //GATEKEEPER
    if (switch_incoming == 255) return; // reject bad upload of Deputy queue
    // Serial.println(switch_incoming);
    //SEPARATE closed switches from open switches
    if (switch_incoming > 99){
    switch_closed = false;
    switch_number = switch_incoming - 100;
    }// close if decodeSw_incoming > 99
    else switch_number = switch_incoming;

    //CONVERT digital switch byte into Link2FS SimConnect Input code

    // NOTE ...else if (system_busVoltage == false) {Serial.println(F("blah blah");}...
    // stops light switches from going toggle mode when power bus has no voltage

    switch(switch_number){

    //GROUP 1 -- profile "G01" (independent switches) - profile "G02" C172 (linked switches)

    //MASTER SWITCH
    //alternator switch -- (toggle) E19 -- feedback '?s'
    //C172 Skyhawk Battery and Alternator switches inlocked -- master must be ON
    case 4:{
    if (switch_closed == true) {
    if ((Link2FS_profile == "g02") && (system_alternatorSwitch == false) && (system_batterySwitch == true)) {
    Serial.println(F("E19")); }
    if ((Link2FS_profile == "g02") && (system_batterySwitch == false)) {tone(klaxon_pin, 2000, 200);}
    if ((Link2FS_profile != "g02") && (system_alternatorSwitch == false)) {Serial.println(F("E19"));}
    }// close if switch_closed = false
    if ((switch_closed == false ) && (system_alternatorSwitch == true )) {Serial.println(F("E19"));}
    }// close case 4:
    break;
    // battery switch -- 17 off -- 18 on
    case 5:{
    if ((switch_closed == true) && (system_batterySwitch == false)) {Serial.println(F("E18"));}
    if (switch_closed == false) {
    if ((Link2FS_profile == "g02") && (system_alternatorSwitch == true)) {tone(klaxon_pin, 2000, 200);}
    if ((Link2FS_profile == "g02") && (system_alternatorSwitch == false) && (system_batterySwitch == true)) {
    Serial.println("E17");}
    if ((Link2FS_profile != "g02") && (system_batterySwitch == true)) {Serial.println(F("E17"));}
    }// close if switch_closed = true
    }// close case 5:
    break;

    //GROUP 2: On/Off switch -- will toggle with no power on main bus -- this fix works for default FSX aircraft
    // Taxi light, landing light, nav lights, beacon, and strobe lights

    //taxi light C440 off, C441 on
    case 0:{
    if (switch_closed == true) {Serial.println(F("C441"));}
    else if (system_busVoltage == false) {Serial.println(F("C441"));}
    else Serial.println(F("C440")); }
    break;

    // landing - 'C430 C431', nav - 'C410 C422', beacon - 'C420 C421'
    // strobe - 'C450 C451'

    // GROUP 3: On/Off switches that act normal
    // panel lights, avionics master, pitot heat, carb heat, cowl flaps, landing gear, parking brake, fuel pump

    //panel lights C460 off, C461 on
    case 10:{
    if (switch_closed == true) {Serial.println(F("C461"));}
    else Serial.println(F("C460")); }
    break;

    // avionics master - 'A430 A431', pitot heat - 'C050 C051', cowl flaps - 'C30XXX', carb heat - 'F13 F14'
    // landing gear - 'C01 C02' parking brake - 'C040 C041' fuel pump 'F020 F021'

    // GROUP 4: The oddballs
    //an input that starts when called, runs for two seconds, then shuts itself off.
    //fuel primer (trigger) E37 automatic opens, pauses, and closes
    case 3:{
    if (switch_closed == true) Serial.println(F("E37"));}
    break;
    //Sim Paused C08 (toggle) -- the logic is handled by Deputy board's PROCESS_RECEIVED()
    case 16:{
    Serial.println("C08"); }
    break;

    }// close switch(switch_number)
    }// end PROCESS_SWITCHES()
    Hugh
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013

  8. #8
    150+ Forum Groupie


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

    Re: General Aviation Lower Switch Panel In A Can

    /*
    Two_Way_Deputy_XX165_Serial_Out.ino

    General Aviation Lower Switch Panel In A Can

    Post 8. Toggle Switches and Two Pushbuttons

    My thanks as always to the MyCockpit.org community, the Arduino.cc community and especially Jim for www.Jimspage.co.nz

    As per part 6. If you use a similar shift register, use the names for the chip pins as published in the manufacturer's datasheet and change these names used by TI for the SN74HC165N 16 pin dip package. Call the pins anything you want behind comment marks(//).

    Construction:
    - connect three output lines SH_LD, CLK, and CLK_INH to all XX165 chips and the Pro Mini pins per void setup().
    - For the XX165 chip furthest from the Pro Mini ONLY. Hardwire pin 10 (SER) to GND. It is an unused input.
    - the serial output line starts with QH pin of the chip furthest from the Pro Mini to the SER pin of the next chip inline. QH to SER of the next chip and so on until QH of the last chip connects to Arduino pin QH listed on void setup().
    - connect Arduino VCC and GND sources to all chips.
    - connect each input pin of the chip to a switch contact and continue on through a resister (47k ohms) to VCC. All switches are pulled HIGH using external resistors.
    - connect the other contact of all switches to GND.
    - two normally open momentary pushbuttons have been added to the panel for Deputy board reset and FSX pause. Both switches are connected directly to the Deputy board. Connect one contact of each switch to ground. Connect the remaining contact of the Deputy reset switch to one of the reset pins. Connect the last contact of the FSX 'pause' switch to the Deputy board pin 16 (Analog2). There is no code required for the 'reset' switch. The 'pause' switch uses the system identifier (230) of the XX165REG() shift registers and an input code one number (16) above the last pin number used by the shift registers. When you add another XX165 shift register, change the 'pause' switch code number to one more than the last pin number of the new shift register

    SparkFun has a good introductory video on shift registers. https://www.youtube.com/watch?v=6BLj9Ak2Djs

    Once again the XX165 chip is processed the hard way allowing the user to follow the process and modify any code as desired. No library or shiftOut() function is used.

    Normal operation identifies only the XX165 inputs that have changed since the last scan and places those pin numbers and preceding identification bytes at the end of upLdQueue[]. The line 'XX165Reg_startup = true; XX165REG_IN(); XX165Reg_startup = false;' bipasses the 'compare with last scan' process and sends the position of all switches to the queue. To use this procedure to match the FSX switch panel to the hard panel, the Pro Mini board must be hard reset by shorting the pin 'RST' briefly to GND. The Pro Mini is up and running at 'power up' long before the sim panel is ready so a reset pushbutton somewhere on the sim will be necessary.

    BushPilotWannabe July 2017
    */

    *** LOAD YOUR EXISTING 'Two_Way_Deputy_XX595_Parallel_Out.ino' AND SAVE THE FILE AS
    "Two_Way_Deputy_XX165_Serial_Out.ino"
    *** CHANGE THE LINE 'Post 6. Landing Gear and Sim Paused Status LEDs' TO THE FOLLOWING
    Post 8. Toggle Switches and Two Pushbuttons

    *** CHANGE GLOBAL VARIABLE
    *** CHANGE THE LINE 'byte upLdQueue[2 * (register_bitCount + 2)]; // holds .... TO THE FOLLOWING LINE
    byte upLdQueue[60]; // 36 bytes should be enough for two XX165 registers but running into queue overflow and writing over other programming

    *** GLOBAL VARIABLES SECTION
    *** PASTE THE NEXT FIVE LINES AFTER THE LINE 'volatile bool receive_acknol;'
    // CHANGE 'registerreceiveEvent_chipCount' TO REFLECT NUMBER OF SHIFT REGISTERS
    // THIS ALSO CHANGES 'byte pinRegister[XX165Reg_chipCount]' TO REFLECT NUMBER OF SHIFT REGISTERS
    const byte XX165Reg_chipCount = 2;
    const byte register_bitCount = XX165Reg_chipCount * 8;
    byte pinRegister[XX165Reg_chipCount]; // all bits of the register are initiated low
    *** PASTE THE FOLLOWING 7 LINES BEFORE '//XX595 PARALLEL OUT REGISTER'
    //XX165 Register processed switches
    const byte SH_LD = 6; // SN74165N pin SH/LD with a bar
    const byte CLK = 7; // SN74165N pin CLK
    const byte QH = 8; // SN74165N pin QH
    const byte CLK_INH = 9; // SN74165N pin CLK_INH
    bool XX165Reg_startup; // schedules the first read of XX165 chips to avoid buffer overflow
    long XX165Reg_slot;


    *** void setup()
    *** REPLACE THE LINE '// 74XX165 pins 6 to 9' WITH THE FOLLOWING 5 LINES
    // 74XX165 pins 6 to 9
    pinMode(SH_LD, OUTPUT); //SH_LDbar
    pinMode(CLK, OUTPUT); //CLK
    pinMode(QH, INPUT); //QH
    pinMode(CLK_INH, OUTPUT); //CLK_INH
    *** REPLACE THE 4 LINES STARTING WITH '// pin 13 -- Switched VCC for Hall effect sensor' WITH THE NEXT 4 LINES
    pinMode(13, OUTPUT); digitalWrite (13, LOW); // ANALOG (0) Hall effect sensor -- provides SWITCHED VCC to the Hall sensor
    // Analog A(0) pin 14 -- hall sensor
    // pin 15 Analog(1) not used
    pinMode(16, INPUT_PULLUP); // Analog(2); -- Sim Reset

    *** PASTE THE FOLLOWING 2 LINES BEFORE 'Serial.begin(115200);
    //Match sim and FSX switches when Deputy board starts or resets
    XX165Reg_startup = true; XX165REG_IN(); XX165Reg_startup = false;

    *** void loop()
    *** PASTE THE FOLLOWING 2 LINES BEFORE '// end loop()
    //Process digital switches -- RECEIVE_EVENT + 40
    if (millis() > XX165Reg_slot) {XX165REG_IN(); XX165Reg_slot = millis() + 10000;}

    *** void PROCESS_RECEIVED()
    *** PASTE THE FOLLOWING LINE BEFORE THE LINE 'queue_slot = millis() + 50;'
    XX165Reg_slot = millis() + 40;
    *** PASTE THE FOLLOWING 14 LINES BEFORE THE LINE '// remove fragments from the wire buffer'
    //Read the Sim Reset (PANIC) switch -- pushbutton -- this gets harder all the time
    //process_paused is reset in 'if c = 210' (above) -- half second delay before the LED changes
    if ((digitalRead(16) == LOW) && (process_paused == true)) {
    if (system_simPaused == false) {
    queue_last++; upLdQueue[queue_last] = 230; // 'push' 'push again' pushbutton -- decoded as a 'XX165REG_IN' toggle switch
    queue_last++; upLdQueue[queue_last] = 16;
    //Serial.println(system_simPaused);
    process_paused = false; } //
    if (system_simPaused == true) {
    queue_last++; upLdQueue[queue_last] = 230;
    queue_last++; upLdQueue[queue_last] = 116;
    //Serial.println(system_simPaused);
    process_paused = false; }
    }// close if digitalRead(16) = ....

    ***ADD THE FOLLOWING USER FUNCTION TO THE SKETCH

    // **********************************************
    // 74HC165 SERIAL OUT SHIFT REGISTER *****************************************************************
    // **********************************************

    void XX165REG_IN() {

    bool processBit = false;
    //DRIVE CLK_INH LOW -- disables the shift clock inhibit
    //PULSE SH/LD LOW then HIGH - transfers the voltage level of all switches into the shift register latches
    //DRIVE CLK LOW, so it can initiate the shift when driven high (edge triggered)
    //READ THE VOLTAGE LEVEL OF THE TALE END LATCH and PROCESS DATUM
    // read voltage on QH of the downstream chip
    // check the voltage against stored bit in pinRegister[] IF DIFFERENT process datum
    //PROCESS DATA
    // declare first bit as MSB. Count MSB as register_bitCount-1 using count down loop to coordinate values
    // HIGH outputs are stored as the value of the counter, LOW outputs are stored as value plus 100
    // increment queue_last and store source identifier '230' in the newly assigned transmit_buffer top level
    // increment queue_last and store processed value 'loop1' or 'loop1' plus 100
    // update pinRegister[ current bit being processed ]
    //DRIVE CLK HIGH -- shift all bits one latch downstream -- fifteen more to go
    //DRIVE CLK_INH HIGH -- inhibit shift clock until next call to the function

    digitalWrite(CLK_INH, LOW); // Is this a chip enable pin? Why don't they say so.
    digitalWrite(SH_LD, LOW);
    digitalWrite(SH_LD, HIGH);
    for (int loop1 = register_bitCount - 1; loop1 > -1; loop1--) {
    digitalWrite(CLK, LOW);
    byte bit_received = digitalRead(QH);
    byte oldBit = bitRead(pinRegister[loop1 / 8], loop1 % 8 );
    //Serial.print(bit_received); Serial.print(" "); Serial.println(oldBit);
    //SWITCH BETWEEN FIRST READ OR LATER READS of XX165 chips
    processBit = false;
    if ((XX165Reg_startup == false) && (oldBit != bit_received)) {processBit = true;}
    if (XX165Reg_startup == true) {processBit = true;}

    //Process the bit
    if (processBit == true) {
    // Serial.print("changed "); Serial.println(loop1);
    if (bit_received == 1) {
    queue_last++; upLdQueue[queue_last] = 230; // transmit identifier for digital read switches
    queue_last++; upLdQueue[queue_last] = loop1 + 100;
    }// close if bit_received == 1
    else {
    queue_last++; upLdQueue[queue_last] = 230;
    queue_last++; upLdQueue[queue_last] = loop1;
    }// close else if bit_received == 1
    // Serial.print(upLdQueue[queue_last]); Serial.print(" ");
    // Serial.print(bit_received); Serial.print(" "); Serial.println(oldBit);
    }// close if processBit = true
    bitWrite(pinRegister[loop1 / 8], loop1 % 8, bit_received);
    digitalWrite(CLK, HIGH);
    }// close loop
    // read all bits of the pinRegister -- MSB on the right
    //for (int x=register_bitCount-1; x>-1; x--) {Serial.print(bitRead(pinRegister[x/8], x%8 ));} Serial.println();
    digitalWrite(CLK_INH, HIGH);
    }// end XX165REG_IN()
    Hugh
    ---CYXD ----- TWR --- GND ------ Closed
    ILS-- NDB -- 119.1 -- 121.9 ---- 11/2013