Professional Documents
Culture Documents
Page: 1
The switches on the upper left replicate the functions of the top row of switches on the FSX radio stack. The
individual COM/NAV radios are selected using the upper rotary switch, which also has a position to select
the transponder. A dual rotary encoder (centre also obtained from Leo Bodnar) is used to change
frequencies of the COM/NAV radios and also changes the individual auto-pilot parameters (selected by the
lower rotary switch). The upper row of push buttons control auto-pilot operation, whilst the bottom row of
buttons set the transponder code.
The unit is built into a 6 x 4 plastic box and interfaces with FSX using FSUIPC over USB. It works quite well,
but as the BU0836X controller only has inputs, it still relies on the on-screen radio stack display to provide
visual feedback. It occurred to me then that one day I would revisit the task and update the unit to not only
control the inputs but also to include the displays, thereby negating the need to bring up the radio stack on
the screen. That day has now arrived.
Page: 2
Page: 3
Panel Layout
Here is a concept drawing of the panel layout of the proposed radio stack.
FSX users will almost certainly recognise the various elements incorporated in this design.
I intend to use a 10 x 8 x 3mm sheet of Perspex with a paper artwork sheet behind it. The displays will
mount behind the Perspex but remain visible through cutouts in the artwork sheet. Although the buttons
have a square front bezel, they mount through circular holes which can be easily drilled. The only tricky part
will be accurately cutting out the area for the keypad. Each LED will be inserted into some small black tubing
(probably heat-shrink, as I already have that) with a small hole in the artwork to provide a small dot of light
when the associated button is latched, i.e. operated. The artwork, which provides the black background and
all the text labels, will be printed onto premium quality photographic paper, similar to how I did for the
original version.
Page: 4
Breadboard prototype
I know, it looks like a real rats nest but it has evolved overtime. I have added some labels to the image to
help identify the various elements. As I added a new functionality to the breadboard, I wrote and tested the
necessary code on the Arduino to process it. It initially began with just the 7-segment displays driven by two
MAX7221 LED drivers (ultimately, six MAX7221 chips will be required in the final unit). This was based on an
article on the Arduino site at http://playground.arduino.cc/Main/MAX72XXHardware. Then came the dual
rotary encoder used to set the frequency of the standby (rightmost 6-digit display). The rotary encoders are
interrupt-driven using a finite state machine to determine direction of rotation. The idea for this method
was prompted by an article by Oleg Mazurov at http://www.circuitsathome.com/mcu/reading-rotaryencoder-on-arduino. However, my implementation differs considerably from his. The displays are swapped
when the rotary encoder button is pressed.
The keypad and its attendant potential-divider resistors came next. The keypad is simply a 3x4 matrix, with
a button at each inter-section, which when pressed presents a unique voltage to the analogue input pin to
which the resistor network is connected. This voltage on the analogue pin is polled by the software to
determine if a key has been pressed and if so, which one. The keypad wiring was based on an article at
http://www.instructables.com/id/Arduino-3-wire-Matrix-Keypad/step2/Wiring-up-the-resistors.
Page: 5
Next on the list were the momentary push buttons (currently 15 in all) which are wired to a series resistor
network. The far end of the resistor network is connected to +5v, with 2.2Kohm resistors between that and
each button. This eventually connects to another analogue pin. The buttons connect to ground as shown
here.
It is assumed only one button will be pressed at a time and I initially waited (in the code) for the button to be
released before continuing. This was modified when I added the UP/DOWN buttons (the two round red
ones on the lower right of the breadboard) which change the Altitude and Vertical Speed of the Auto-Pilot.
When these are held pressed, the values start to change more rapidly. So a time interval was introduced in
the button process routine. You can just make out the LEDs above each button on the breadboard image
which indicates the latch state of the associated button. The LEDs are currently controlled via two 8-bit shift
registers (SN74HC959N), but I am planning to control these with the MAX7221 devices in the final unit.
I am currently using a 2 (rows) by 16 (columns) LCD shield for the auto-pilot display, which can be seen
connected to the Arduino on the left hand side of the breadboard image. The final design will contain a
separate 2x16 LCD. Although I tend to limit the use of 3rd-party libraries in my code, I made an exception
here for expediency.
See http://arduino.cc/en/Reference/LiquidCrystal?from=Tutorial.LCDLibrary for
details of the LCD library.
Finally I fitted another rotary encoder to the breadboard (just left of the 7-segment displays) which I
programmed to control the heading bug on the heading indicator (one of the six primary flight indicators).
The heading bug value is also output to the auto-pilot display as it is used by the auto-pilot to maintain
direction of flight. I also wanted to make sure the interrupt driven code worked just as well with a cheap
rotary encoder. It did, so I now have ten more of these on their way from China!
Page: 6
Page: 7
The Arduino mandatory loop() routine detects when an interrupt has been fired and calls the relevant
interrupt handling routine
loop() {
// example
Page: 8
Page: 9
} // end of loop()
// poll Keypad
// update the transponder display
/*==================================================================================================
gets current keypad key if pressed and return it, otherwise return NULL.
==================================================================================================*/
char getKey() {
char key = NULL;
// NULL indicates no key pressed
unsigned int adcValue = readAnalogPin(KEYPAD_PIN, KEY_NONE, KEY_MARGIN);
if (! btnPressed(adcValue, KEY_NONE, KEY_MARGIN))
key = mapKeypad(adcValue);
return key;
// returns the key pressed or NULL if none
} // end of getKey()
/*==================================================================================================
returns true if <adcValue> is within range defined by <btnValue> + or - <margin>, otherwise, false
==================================================================================================*/
boolean btnPressed(unsigned int adcValue, unsigned int btnValue, unsigned int margin) {
boolean retval = false;
if ( (adcValue >= (btnValue-margin)) && (adcValue <= (btnValue+margin)) )
retval = true;
return retval;
} // end of btnPressed()
Page: 10
Page: 11
// this is where the current latch state of each button (currently max 16) is stored
unsigned int buttons = 0x0000;
// initialise switch states to all off
#define BTN_COM1 0x8000
// defines bit masks to access relevant bit in buttons variable
#define BTN_COM2 0x4000
#define BTN_BOTH 0x2000
#define BTN_NAV1 0x1000
#define BTN_NAV2 0x0800
#define BTN_MKR
0x0400
#define BTN_DME
0x0200
#define BTN_ADF
0x0100
#define BTN_AP
0x0080
#define BTN_HDG
0x0040
#define BTN_NAV
0x0020
#define BTN_APR
0x0010
#define BTN_REV
0x0008
#define BTN_ALT
0x0004
#define BTN_UP
0x0002
#define BTN_DN
0x0001
Page: 12
Polling Buttons
loop() {
} // end of loop()
//
//
//
//
/*==================================================================================================
reads the ADC value (0-1023) of the button resistive ladder
and return a mask to determine which button is pressed.
if no button is pressed, it returns 0x0000.
==================================================================================================*/
unsigned int checkButtons() {
unsigned int adcValue = readAnalogPin(BUTTON_PIN, BTN_NONE, BTN_MARGIN); // get ADC value (0-1023)
unsigned int btn = 0x0000;
// return 0x0000 if no button has been pressed
if ( ! btnPressed(adcValue, BTN_NONE, BTN_MARGIN)
// however, if a button has been pressed...
btn = mapButtons(adcValue);
// determine which button caused the event
return btn;
// and return bit mask for the button pressed
} // end of checkButtons()
The project is now ready to move into the build stage. This will include making PCBs, installing the
components, building the unit into a suitable housing and finalising the Arduino code. This will be subject of
an update.
TO BE CONTINUED
Page: 13
Page: 14
in a more elegant solution as each display pair (i.e. active and standby) only required a single LED driver chip,
leading to a more modular design.
Some years ago, I built a UV LED light-box in which I expose photo-sensitive copper clad boards using (inkjet)
printed designs to make single sided PCBs. Although it is possible to use this set-up to create double sided
PCBs, obtaining exact alignment for each side does present a challenge. Thus I decided to stick to singlesided PCBS in this project. However, mapping the pins between the 7-segment displays and LED driver chips
required too many jumper wires on a single-sided PCB so I eventually adopted a piggy-back method whereby
the display units are mounted on one PCB and the drivers on another. The boards are then plugged
together via male/female connectors. This method keeps the overall size down as well as supporting design
modularity. To reduce the number of screws required to fit them to the front panel, I included two radio
units (each consisting of an active and a standby display) on each board, but as seen from the two
schematics a single radio board is easily be produced if required.
Page: 15
Page: 16
Page: 17
Page: 18
LEDs
Most of the buttons in this project have a latching action, i.e. each successive button press will toggle the
latch state on then off, etc. Each latching button has a corresponding LED to show its current state. The
LEDs are mounted on small strips of 3mm MDF with black heat-shrink over them to prevent light overspill.
The heat-shrink wrap is glued to the MDF strips and cut flush with the front of the strip. The image below
shows the six auto-pilot LEDs, (upper) and the eight switch panel LEDs (lower).
The cathodes of each LED on each strip are connected together in similar fashion to a single 7-segment
common cathode display unit. The LED anodes are then connected as though there were individual
segments to the driver module. The MAX7219/21 chip can operate in both decode mode (whereby the
required numeric value is sent to the chip where it is decoded to light up the correct segments) or nondecode mode whereby each individual segment can be controlled separately. Fortunately both modes can
co-exist on the same chip, thereby allowing the transponder display and LEDs to share the same chip. The
LED strips have been glued to the back of the front panel art-work and small 1.5mm holes allow their light to
be visible from the front.
Page: 19
The two sets of eight 680 resistors on the bottom left are used to limit the current between the
driver chips and the LEDs. The buttons which control the auto pilot mount around the LCD and
there is also a switch which selects whether ALT (altitude) or VS (vertical speed) is controlled by the
UP/DN buttons. The UP/DN buttons initially increment/decrement the ALT/VS value by 100 feet
with each button press. However, if the button is held pressed for more than a second the ALT/VS
values change at a rate of 1000 feet for each 150 milliseconds (this period may change!) the button
remains pressed.
Page: 20
Here is the working front panel of the radio stack. Note the blue item labelled DREMEL on the lower left of
the image is not part of the unit. Rather it is a jaw of the vice used to hold the bare-bones unit during
construction and testing. As can be seen in the final image overleaf, the breadboard is no more and all the
connections exist entirely between the Arduino Mega256, front panel modules and the small shift register
board. The Arduino and shift register boards will ultimately be fixed to the inside of the enclosure.
The wiring will also be tidied up when the panel is mounted in its enclosure. This has yet to be built, but it is
anticipated it will be fabricated from MDF and painted black to match the panel.
A final update will be posted once the project is completed with hopefully a video showing it in action.
Page: 21
Page: 22