Home » Back to basics: program a button for the flight sim connector

Back to basics: program a button for the flight sim connector

by admin
Published: Last Updated on 0 comment 2.3K views

My Patreon supporters could access this article early. If you want to help support this content and receive awesome benefits (early access to content, exclusive 3d files, private chat in Discord, and support priority), head over to https://www.patreon.com/BitsAndDroids.

In this new series, I want to go back to basics. I will shine a light on a wide variety of components, how they work, how to code them but most importantly how to use them with the Bits and droids connector to interface with Microsoft flight simulator 2020.

This particular one will be quite a long read since I try to cover some of the basics you need to get started with the connector and Arduinos. Upcoming entries will reference these basics and will therefore be shorter.


This series wouldn’t be called back to basics if we didn’t start with momentary push buttons. Momentary pushbuttons are buttons (…. well ehm… obviously) that allow current to flow through them as long as you physically press the button.
In the off state, the current flow would look like this:

The power (yellow line) could run up until the button, where it theoretically could go up if another connection were present. The button isn’t pressed so that no current can run from left to right.

The moment we press the button, the power will run through the button towards the ground pin on our board.

When you see the red 5V line, you might instantly think about the 5V power output of your Arduino. But in reality, we won’t use the circuit below for our projects.

If the power running from the 5V pin to ground through our button, there would be no way for our code to read the current state of the button.

Now, this would be a circuit that we’re going to encounter many times when constructing our projects. The pins marked 0-13 and A0 – A5 can all be used for inputs or outputs. A button is a digital signal (so either a 1(HIGH) or 0 (LOW)); therefore, we’re able to use 0-13 and A0-A5.
A potentiometer, for instance, needs to be read as an analog signal (a signal what returns an actual value). For a potentiometer, we could only use pins A0 – A5 (the prefix A refers to Analog).

Remember how I said that power wants to flow from source to ground? In the schematic above, the power would run from the source to the button, but if no button is pressed, the current has no place to go. The readings from this setup would result in noise and unreliable results. Luckily the Arduino has an internal resistor that we can activate that gives the current a place to flow to the ground if the button isn’t pressed. Because power likes to follow the path with the least resistance, the power will flow through the button to the ground wire when the button is pressed. This resistor will also ensure that the signal state is HIGH when no button is pressed and LOW when we press the button. We will see later in this post how we enable this resistor with code.

Setting our coding environment up

Getting a button to work is a rite of passage when working with microcontrollers.
Luckily coding them is quite simple once you get the hang of it. Even if it feels like you’ve entered the magic realm of witchcraft, I promise you that in a few days, you will look back, and you’ll hear that famous sound in your mind going: “Ah, I get it.”
The Arduino programs we write are called sketches and are usually created in the Arduino IDE. The Arduino IDE can be downloaded for free from https://www.arduino.cc/en/software. Just select the version that matches your operating system, and you’re good to go.

Once You’ve installed and opened the IDE you should be greeted by a screen that looks like this:


The language that we’re going to code our sketches in is c++. The Arduino environment adds some extra functionalities to the c++ language to make it more beginner-friendly.
There is already some basic code present, “void setup(){}” and “void loop(){}”. These are functions (which are blocks of code) that get executed. The setup block gets executed (you guessed it) during the setup of the device. So every time the device gets powered on, it will execute once. The loop block will be executed as many times as the Arduino is capable of. This block could be executed hundredths of times per second if we don’t add any delays (or the code get’s too complex).

Coding the button

Now we got everything set up, and it’s time to program our button. For me, it always helps to break down what I want to achieve. So, in this case, let’s dumb it down to every step required.

  • There is a physical button.
  • That is connected to pin 2 on our Arduino.
  • Activate internal pullup resistor
  • We want to know what the button state is (pressed or not pressed)
  • IF the button is pressed, do something
  • We want a longer click time to ensure we can release the button before retriggering the command.

Let’s begin in the beginning. In our Arduino code, we’re able to define where our inputs are connected by adding the following line at the top:

//#define lets us define the pin location and associate a name to the pin
#define buttonA 2

It is common practice to place the #defines at the top of the file. If we would include a library, we place the #defines underneath the libraries. We’ll go over this later in this post.

Now we’ve defined the button pin; we can work our way to the next part of the list: “enabling the internal pull-up resistors.” To enable the internal pull-up resistors, we add a single line of code to the setup block.

void setup(){
   pinMode(buttonA, INPUT_PULLUP);
}

The pinMode function will let you define the way the pin will be used. This could be an INPUT, INPUT_PULLUP, OUTPUT. By selecting INPUT_PULLUP we enable the internal pullup resistor while we can read the state of the button.

If statement

The only thing that is left is to handle the reading of the button states. Because we continuously want to check if the button is checked we put our logic in the loop block. I already gave a hint by typing the word IF in capital letters. In coding, we use the if statement on many occasions. An “if statement” is a statement that checks if a certain condition is true or false and executes the code contained in the statement if the condition is true. In our case we want to check IF the button is pressed -> Do X. In code this translates to this:

void loop(){
    if(digitalRead(buttonA) == LOW){
     //Do something
 }
}

If we break the if statement down we can spot certain elements. A completely empty statement looks like this: “if(){}”. The word if tells our Arduino an if statement is present. Between the () we find the condition. In our case, digitalRead(buttonA) will return the current state of our button. digitalRead(buttonA) == LOW declares that if digitalRead(buttonA) IS EQUAL TO LOW. So only if our state is LOW we will execute the code that is found between the {}.
Between the {} we place the code that needs to be executed when the condition is true. And it will only run if the condition is true. If we want to make it a bit more complicated we could also write this line of code instead:

void loop(){
    if(!digitalRead(buttonA) == LOW){
     //Do something
 }
}

Now at first glance, it might look very similar but pay close attention to the exclamation mark in front of the digitalRead. The exclamation mark usually refers to NOT in code. So in this example, IF NOT digitalRead(buttonA) IS EQUAL TO LOW execute the code. This basically inverts our logic where if the button is not pressed we execute the code (if the state is HIGH).

Now we already have the complete foundation that is needed to use our button. The next step would be to implement the Bits and Droids library and bind our first action to our button. The complete code so far should look like this.

//#define let's us define the pin location and associate a name to the pin
#define buttonA 2
void setup() {
  pinMode(buttonA, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(digitalRead(buttonA) == LOW){
     //Do something
 }
}

The library

The Arduino library’s beauty is that for most heavy lifting, we’re able to use libraries. Libraries are files of code that contain functions and variables like we just encountered in our own code. To receive Microsoft flight simulator 2020 data from our pc over our USB connection, we’d usually need a code block that looks like this:

void BitsAndDroidsFlightConnector::dataHandling() {

  if (Serial.available() > 0) {
    receivedValue = Serial.readStringUntil('\n');
    switchHandling();
  }

}
void BitsAndDroidsFlightConnector::switchHandling(){

    prefix = receivedValue.substring(0, 3);
    cutValue = receivedValue.substring(3);
    int prefixVal = prefix.toInt();
    lastPrefix = prefixVal;

    switch (prefixVal) {
      // Ap

      // lights
      case 33: {
        lightTaxiOn = convBool(cutValue);
        break;
      }

I’ve actually cut this block off after a few rules since the full function spans over 400 lines. In theory, you could write this code yourself every time you want to work with the connector. Still, in reality, your code would become unreadable rather quickly (not even mentioning the cumbersome and error-prone task it provides). The library contains the full block of code that you’re able to reference without reinventing the wheel.
If you haven’t installed the library already, you’re able to open the Arduino IDE. Navigate in the top bar to sketch -> manage libraries -> search for the bits and droids flight sim library and hit install.

Like I already mentioned earlier, we need to include the library at the top of our sketch. We only need 1 line of code for this:

#include<BitsAndDroidsFlightConnector.h>

This will make sure that when we compile the sketch (upload the sketch to our Arduino), the code contained in the library will be uploaded to your Arduino.

To use the library we need to create an object. An object is a digital container that holds functions, properties, and variables. We can give the object any name we’d like but I like to stick with the name connector. In code, it would look like this

#include<BitsAndDroidsFlightConnector.h>
#define buttonA 2
BitsAndDroidsFlightConnector connector = BitsAndDroidsFlightConnector();

This line gets placed underneath the #define section. Since the connector transmits and receives data over a Serial connection, we need to initiate this connection. In the setup block we place:

void setup(){
    pinMode(buttonA, INPUT_PULLUP);
    Serial.begin(115200);
    Serial.setTimeout(15);
}

Serial.begin() starts a Serial connection at a baud rate of 115200. The baud rate is the rate at which the Serial connection sends and transmits data. The higher the value the faster the connection but the faster the connection the more risk of data corruption/loss. The most important part is that it matches the same rate as the connector. Which if no settings are changed runs at 115200.

Sending the action

When we send commands over serial with our Arduino we use the following function:

Serial.println("hello");

This line would send the text hello over our serial line that we initiated in the setup block. I’ve already told you that the connector uses the serial line as the chosen form of communication. Sending a command to the connector is basically just a message sent via connector.send(). In the documentation, you’re able to find all supported commands that are currently available. We need to look for functions that are prefixed with the word send.
Some examples are:

ActionLibrary command
Com 1 Mhz +sendCom1WholeInc
Com 1 Mhz –sendCom1WholeDec
Com 1 Khz +sendKhzComStandby1Plus
Com 1 Khz –sendKhzComStandby1Min
Com 1 SwapsendSwapCom1
Com 1 Fract increasesendCom1FractInc
Com 1 Fract increase carrysendCom1FractIncCarry
Com 1 Fract decreasesendCom1FractDecr
Com 1 Fract decrease carrysendCom1FractDecrCarry

We could pick any of these functions and make our code send the corresponding command over Serial when the button is pushed. As an example, I’ll show you how to fire sendSwapCom1 () which fill obviously swap our com 1 frequency in the airplane. We will fit this into the code we have made so far.

#include <BitsAndDroidsFlightConnector.h>
//#define let's us define the pin location and associate a name to the pin
#define buttonA 2

BitsAndDroidsFlightConnector connector = BitsAndDroidsFlightConnector();
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(15);
  pinMode(buttonA, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(digitalRead(buttonA) == LOW){
     connector.send(sendSwapCom1);
     //This delay value can be altered to your liking
     delay(200);
 }
}

In summary, we’ve created the logic that checks if the button is pressed. We then said if it is pressed send connector.sendSwapCom1() over our Serial line. Followed by a delay of 200 milliseconds to ensure we don’t send the command multiple times per click. The delay could be altered to your own liking. If you have heavy fingers I’d suggest increasing this value or if you want it to fire rapidly you could lower the value.

When you learn to code it’s important that you train spotting patterns. Let’s say we want don’t want to swap the frequency but increase the Mhz part by 1. We first look in the documentation which function is associated with the desired action.
You probably find sendCom1WholeInc() which sounds to do exactly what we need. We can just take our previous code and interchange the function in question.

#include <BitsAndDroidsFlightConnector.h>
//#define let's us define the pin location and associate a name to the pin
#define buttonA 2

BitsAndDroidsFlightConnector connector = BitsAndDroidsFlightConnector();
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(15);
  pinMode(buttonA, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(digitalRead(buttonA) == LOW){
     connector.send(sendCom1WholeInc);
     //This delay value can be altered to your liking
     delay(200);
 }
}

Another example is if we wanted to add a second button that looks like this. If you’re completely new to programming it’s important to pay attention to which code multiplies when adding buttons and which code doesn’t.

#include <BitsAndDroidsFlightConnector.h>
//#define let's us define the pin location and associate a name to the pin
#define buttonA 2
#define buttonB 3

BitsAndDroidsFlightConnector connector = BitsAndDroidsFlightConnector();
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(15);
  pinMode(buttonA, INPUT_PULLUP);
  pinMode(buttonB, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  if(digitalRead(buttonA) == LOW){
     connector.send(sendCom1WholeInc);
     //This delay value can be altered to your liking
     delay(200);
 }
  if(digitalRead(buttonB) == LOW){
     connector.send(sendCom1Swap);
     //This delay value can be altered to your liking
     delay(200);
 }
}

And that’s it. Hopefully, you now know all the ins and outs you need to add as many buttons as you wish to your projects. If you still don’t have a full grasp on the subject, I’d suggest going for a walk, have a nice cup of coffee on your couch, and come back at a later point. Doing something else can sometimes be the best remedy for a clearer mind. And even after that, if you still have questions you know where to find me.

If you are still reading this part, I would like to thank you for hanging out, and I hope to see you in the next one!

You may also like

Leave a Comment

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept