..
Basics for 737-800 MCP.
Don't really know where to post this, but I don't think it is worth a new thread, or if it will even be worth anything to anybody. So OAM, if I may?
Some time the beginning of this year, I cobbled together the hardware and sketch for the default 737-800 MCP. This past weekend I dusted it all off again, made some changes to the sketch (program)
and fired it all up again.
It is not as if I need, or even want, a 737 MCP...I do these things purely out of interest and amusement. But at this point I do not want to go any further with it.
I have put in loads of notations and explanations, so if you are interested, I suggest that you read the sketch basically line for line.
Finally, I make my own circuit boards at home, so you will notice from the photo that the Led Modules are NOT the standard 8xdigit modules available on line.
(Having each MCP function on its own led module, gives you the freedom to mount the modules each in the correct place on the panel).
Like I said, this is the basics of the MCP, dealing mainly with the readouts.
Photos:
![Image](http://www.simviation.com/phpupload/uploads/1480588385.jpg)
Sketch:
//**********************************************************************************
/*
This is a basic "start" for the default Boeing 737-800 MCP For Arduino Mega. By Jan -- Sprocket
It is intended to be used with Jim's Link2FS :
http://www.jimspage.co.nz/Link2fs_Multi.htm I have borrowed heavely from Fess_ter at My Cockpit, as well as from Jim's examples - THANKS GUYS.
General: There are 5 MAX7219 Led modules designated Module 0 to Module 4.
From Left to Right, the digits order are: 7,6,5,4,3,2,1,0
The modules must have their own 5V supply, BUT be shure to COMMON the negatives
MODULE 0 = Course on 3 Digits
MODULE 1 = Speed on 4 Digits
MODULE 2 = Heading on 3 Digits
MODULE 3 = Altitude setting on 5 Digits
MODULE 4 = Vertical Speed setting on 5 Digits
There are 5 rotary encoders with push switch: QuadA for setting Course _ Here I used a half cycle encoder, 24 detents, from the scrap box. **SPECIAL NOTE HERE IN THE ENCODER ENGINE SECTION
QuadB for setting Speed _ For the next 4 I used full cycle/24 detents with "push to make" switch.
QuadC for setting Heading
QuadD for setting Altitude
QuadE for setting Vertical speed
*/
//*****************************************************************************************************************
#include "Quadrature.h" // This Library required for the working of the encoders.
#include "LedControl.h" // This Library required to drive the MAX7219 7 segment LED displays.
// "Led_Module" is the variable name of the daisy chained modules,
LedControl Led_Module = LedControl(22,24,23,8); // running off pins 22,24,23. Pin 22 is DataOut(Goes to 1st MAX "Din"), Pin 24 is clock, Pin 23 is
// Load or CS. The 8 is the count for how many modules you have in the chain. Max allowed = 8.
// To daisy chain the MAX7219 modules, parallel all Clk inputs and all CS (chip select)inputs, then
// Data Out from pin 22 goes to the 1st module "Data In". "Data Out" from the 1st and subsequent module then to next module "Data In"
Quadrature quad1(2, 3);
Quadrature quad2(4, 5);
Quadrature quad3(6, 7);
Quadrature quad4(8, 9);
Quadrature quad5(10,11);
int CodeIn; // used on all serial reads
int Count; // This variable used in loops in the EQUALS() function
int current_pin; //Used on button switches
String current_pin_state; // The state of an individual pin being processed
String current_pin_old_state; // The previous state of an individual pin being processed for comparison
String all_pins_state; // The state of all of the pins that we are using for Encoders, Buttons, and Switches
String all_pins_old_state; // The previous state of all of the pins that we are using for Encoders, Buttons, and Switches for comparison
//****************************************************************************
String Digit;
String QuadAup;
String QuadAdown;
String QuadBup;
String QuadBdown;
String QuadCup;
String QuadCdown;
String QuadDup;
String QuadDdown;
String QuadEup;
String QuadEdown;
String FDon;
String FDoff;
//****************************************************************************
int AP_alt_set[5];
int AP_vs_set[4]; // Hopefully all of these variable names are mostly obvious.
int AP_hdg_set[3]; // The [n] with a number in it tells the arduino to make an array of the size n
int AP_crs_set[3]; // They are used to store the extractions in array format.
int AP_speed_kt_set[3]; // The information is stored in arrays to be able to display it without delay
int AP_mach_set[3];
int AP_AutoThrottle_arm; // State of the Auto Throttle Arm
int AP_Flight_Director_Active; // State of the Flight Director
int KntsMach_select = 50;
long Xold1;// the first encoder "old" reading
long Xold2;// the second encoder "old" reading
long Xold3;// the third encoder "old" reading
long Xold4;// the fourth encoder "old" reading
long Xold5;// the fith encoder "old" reading
char AP_vs_minus; // This is used to designate whether the AutoPilot VS is climbing or descending,
//so for this we use the first digit of Module 1 which will show a "-" or not, depending.
void setup() {
all_pins_old_state = "111111111111111111111111111111111111111111111111111111111111111111111"; // Setting a starting point for comparison.
for (current_pin = 28; current_pin <= 53; current_pin++) // Get all the pins, from 28 to 53, ready as Inputs
{
pinMode(current_pin, INPUT_PULLUP); // By setting the pins as INPUT_PULLUP it makes them all "HIGH"
}
// Then, all of the rest, Pins 54 to 69, are set as Outputs for LED annunciators
pinMode(A0, OUTPUT); // Analog pin A0 is also pin 54
pinMode(A1, OUTPUT); // Analog pin A1 is also pin 55
pinMode(A2, OUTPUT); // Analog pin A2 is also pin 56
pinMode(A3, OUTPUT); // Analog pin A3 is also pin 57
pinMode(A4, OUTPUT); // Analog pin A4 is also pin 58
pinMode(A5, OUTPUT); // Analog pin A5 is also pin 59
pinMode(A6, OUTPUT); // Analog pin A6 is also pin 60
pinMode(A7, OUTPUT); // Analog pin A7 is also pin 61
pinMode(A8, OUTPUT); // Analog pin A8 is also pin 62
pinMode(A9, OUTPUT); // Analog pin A9 is also pin 63
pinMode(A10, OUTPUT); // Analog pin A10 is also pin 64
pinMode(A11, OUTPUT); // Analog pin A11 is also pin 65
pinMode(A12, OUTPUT); // Analog pin A12 is also pin 66
pinMode(A13, OUTPUT); // Analog pin A13 is also pin 67
pinMode(A14, OUTPUT); // Analog pin A14 is also pin 68
pinMode(A15, OUTPUT); // Analog pin A15 is also pin 69
// Wake-up
Led_Module.shutdown(0,false); // The MAX7219's are in power-saving mode on startup, we have to do a wakeup call
delay (100); // Put the delay in so they dont all start drawing current at the same time.
Led_Module.shutdown(1,false);
delay (100);
Led_Module.shutdown(2,false);
delay (100);
Led_Module.shutdown(3,false);
delay (100);
Led_Module.shutdown(4,false);
// Set the display brightness to a lower than medium values
Led_Module.setIntensity(0,8);
Led_Module.setIntensity(1,8);
Led_Module.setIntensity(2,8);
Led_Module.setIntensity(3,8);
Led_Module.setIntensity(4,8);
Serial.begin(115200);
} //end of setup
void loop(){
if (Serial.available())
{
CodeIn = getChar();
if (CodeIn == '=')
{
EQUALS();
}
}
//******************* Rotary Encoders engine ***********************
//****COURSE******
long X1 =(quad1.position()/2); // ** NOTE: divide by 2 here because here I have used a "half cycle" encoder.
if (X1 != Xold1){
if (X1 > Xold1) {Serial.println(QuadAup);} else {Serial.println(QuadAdown);}
Xold1 = X1;
}//end of quad1 read
//****SPEED*****
long X2 =(quad2.position()); // The rest are full cycle encoders
if (X2 != Xold2){
if (X2 > Xold2) {Serial.println(QuadBup);} else {Serial.println(QuadBdown);}
Xold2 = X2;
}//end of quad2 read
//****HEADING********
long X3 =(quad3.position());
if (X3 != Xold3){
if (X3 > Xold3) {Serial.println(QuadCup);} else {Serial.println(QuadCdown);}
Xold3 = X3;
}//end of quad3 read
//****ALTITUDE*****
long X4 =(quad4.position());
if (X4 != Xold4){
if (X4 > Xold4) {Serial.println(QuadDup);} else {Serial.println(QuadDdown);}
Xold4 = X4;
}//end of quad4 read
//****VS*******
long X5 =(quad5.position());
if (X5 != Xold5){
if (X5 > Xold5) {Serial.println(QuadEup);} else {Serial.println(QuadEdown);}
Xold5 = X5;
}//end of quad5 read
{ //**************** End of Encoders engine ***********************
// ***********************************************************
// ************* Manual Settings by encoder knobs ***************
{
QuadAup = "A55";
QuadAdown = "A56";
Led_Module.setDigit(0,7,AP_crs_set[0],false); //Course:
Led_Module.setDigit(0,6,AP_crs_set[1],false);
Led_Module.setDigit(0,5,AP_crs_set[2],false);
}
//{
if (digitalRead(50) == HIGH)
{
QuadBup = "B15";
QuadBdown = "B16";
Led_Module.setDigit(1,6,AP_speed_kt_set[0],false); //Speed in Knts on 3 readouts
Led_Module.setDigit(1,5,AP_speed_kt_set[1],false);
Led_Module.setDigit(1,4,AP_speed_kt_set[2],false);
}
else if (digitalRead(50) == LOW)
{
QuadBup = "B18";
QuadBdown = "B19";
Led_Module.setChar(1,7,' ',false);
Led_Module.setDigit(1,6,AP_mach_set[0],true); //Speed in Mach on 4 readouts
Led_Module.setDigit(1,5,AP_mach_set[1],false);
Led_Module.setDigit(1,4,AP_mach_set[2],false);
}
//}
{
QuadCup = "A57";
QuadCdown = "A58";
Led_Module.setDigit(2,7,AP_hdg_set[0],false); //Heading:
Led_Module.setDigit(2,6,AP_hdg_set[1],false);
Led_Module.setDigit(2,5,AP_hdg_set[2],false);
}
{
QuadDup = "B11";
QuadDdown = "B12";
Led_Module.setDigit(3,7,AP_alt_set[0],false); //Altitude: 5 readouts
Led_Module.setDigit(3,6,AP_alt_set[1],false);
Led_Module.setDigit(3,5,AP_alt_set[2],false);
Led_Module.setDigit(3,4,AP_alt_set[3],false);
Led_Module.setDigit(3,3,AP_alt_set[4],false);
}
{
QuadEup = "B13";
QuadEdown = "B14";
Led_Module.setChar(4,7,AP_vs_minus,false); // Here a "minus" token is use to indicate when the VS is minus.
Led_Module.setDigit(4,6,AP_vs_set[0],false); //Vertical speed: 5 readouts
Led_Module.setDigit(4,5,AP_vs_set[1],false);
Led_Module.setDigit(4,4,AP_vs_set[2],false);
Led_Module.setDigit(4,3,AP_vs_set[3],false);
}
}// Goes high up -do not remove..
}//End of void loop
//**********************************************************************************************************
//**********************************************************************************************************
void INPUTPINS() // All of the Encoders, Buttons and Switches are checked for changes
{
all_pins_state = ""; // Clear this before the "for" loop because we will recreate it at the bottom one pin at a time
for (int current_pin = 21; current_pin <=53; current_pin++) // going to cycle thru all input pins 21 - 53
{
current_pin_state = String(digitalRead(current_pin)); // get the state of the current pin and make it a string format
current_pin_old_state = String(all_pins_old_state.charAt(current_pin - 21)); // acquire the previous state of the current pin
// *** Explanation *** The previous state of the current pin is acquired by reading a single character in the string "all_pins_old_state"
// *** Explanation *** All of the pins, previous states are stored as individual characters in the string "all_pins_old_state" as a "0" or a "1".
// *** Explanation *** We treat the individual characters as being numbered 0,1,2,3,4,...
// *** Explanation *** If the current_pin is 25, "all_pins_old_state.charAt(current_pin - 21)" takes (25-21) which = 4.
// *** Explanation *** ".charAt" gets the character at position 4 in the string "all_pins_old_state"
// *** Explanation *** Now we have the current pin's previous state and we can compare it to the current pin's "current" state.
if (current_pin_state != current_pin_old_state) // compare the state of the current pin to its previous state
{
/* ************** INPUT Pin Uses ******************
22-23_24 Designated pins for the MAX 7219 Modules
2+3 Encoder for Altitude adjust -- (All encoder center pins are connected to ground)
4+5 Encoder for Heading adjust
6+7 Encoder for Vertical speed setting
8+9 Encoder for Course setting
10+11 Encoder for Speed setting
************ Possible INPUT pin uses **************
21 Free
28 Flt Director Switch
29 Free
30 Free
31 Free
32 CMD A Button
33 Free
34 Free
35 ALT HLD Button
36 Free
37 VOR LOC Button
38 APP Button
39 HDG SEL Button
40 VNAV Button
41
42 SPEED/Mach Button
43 A/T Arm Switch
44 Speed Hold Button - Send B26 for toggle, (or B24 for ON and B25 for OFF)
45 N1 Button
46 Push Button on HDG Encoder
47 AP Disengage Switch
48-49
50-51
52-53
************ Possible LED Annunciator Pins (ie, OUTPUTS) *************
2
A0 (54)
A1 (55)
A2 (56)
A3 (57) CMD A Light
A4 (58) V/S Light
A5 (59) ALT HOLD Light
A6 (60) APP Light
A7 (61) VOR LOC Light
A8 (62) LNAV Light
A9 (63) HDG SEL Light
A10 (64)
A11 (65) VNAV Light
A12 (66) SPEED Light
A13 (67) N1 Light
A14 (68)
A15 (69)
*******************************************
*/
// *******************************************************************************************
// N1 Button
if (current_pin == 45)
{
if (digitalRead(45) == HIGH) // N1 Button is depressed and we need to Send a command
{
Serial.println ("B31"); // Send the Toggle command
}
}
// *******************************************************************************************
// SPEED Button
if (current_pin == 44)
{
if (digitalRead(44) == LOW)
{
Serial.println ("B26"); // Toggle Airspeed hold
}
}
// *******************************************************************************************
//Auto Throttle Arm Switch
if (current_pin == 43)
{
if (digitalRead(43) == HIGH and AP_AutoThrottle_arm == 1 ) //Auto Throttle arm ON
{
Serial.println ("B34");
}
if (digitalRead(43) == LOW and AP_AutoThrottle_arm ==0 ) //Auto Throttle arm OFF
{
Serial.println ("B34");
}
}
// *******************************************************************************************
//
![Huh? ???](./images/smilies/huh.gif)
? Button
if (current_pin == 42)
{
if (digitalRead(42) == LOW)
{
Serial.println ("");
}
}
// *******************************************************************************************
//
![Huh? ???](./images/smilies/huh.gif)
?? Button
if (current_pin == 21)
{
if (digitalRead(21) == LOW)
{
Serial.println ("");
}
}
// *******************************************************************************************
// VNAV Button
if (current_pin == 40)
{
if (digitalRead(40) == LOW)
{
Serial.println ("");
}
}
// *******************************************************************************************
// HDG Button
if (current_pin == 39)
{
if (digitalRead(39) == LOW)
{
Serial.println ("B04");
}
}
// *******************************************************************************************
// APP Button
if (current_pin == 38)
{
if (digitalRead(38) == LOW)
{
Serial.println ("B08");
}
}
// *******************************************************************************************
// VOR LOC Button
if (current_pin == 37)
{
if (digitalRead(37) == LOW)
{
Serial.println ("B07");
}
}
// *******************************************************************************************
//
![Huh? ???](./images/smilies/huh.gif)
?? Button
if (current_pin == 36)
{
if (digitalRead(36) == LOW)
{
Serial.println ("B10");
}
}
// *******************************************************************************************
// ALT HOLD Button
if (current_pin == 35)
{
if (digitalRead(35) == LOW)
{
Serial.println ("B05");
}
}
// *******************************************************************************************
} // End of IF Current Pin State Check
all_pins_state += current_pin_state; // Constructs what will become the all_pins_old_state after the "for" loop is done
} // End of 'for' loop
all_pins_old_state = all_pins_state; // all_pins_old_state is updated for the next trip thru the "for" loop
} // End of INPUTPINS() Function
//************************************************************************************************************
// Read from the FS and display the values on the modules
//************************************************************************************************************
char getChar()// Get a character from the serial buffer
{
while(Serial.available()== 0 ); // wait for data//
return((char)Serial.read());
}
void EQUALS(){ // The first identifier was "="
CodeIn = getChar(); // Get another character
switch(CodeIn)
{
case 'b': // AP altitude set
Count = 0;
while (Count < 5)
{
Digit = "";
Digit += getChar();
AP_alt_set[Count] = Digit.toInt();
Count++;
}
{
Led_Module.setDigit(3,7,AP_alt_set[0],false); //Altitude
Led_Module.setDigit(3,6,AP_alt_set[1],false);
Led_Module.setDigit(3,5,AP_alt_set[2],false);
Led_Module.setDigit(3,4,AP_alt_set[3],false);
Led_Module.setDigit(3,3,AP_alt_set[4],false);
}
break;
case 'c': // AP vertical speed set
Count = 0;
while (Count < 4)
{
Digit = "";
Digit += getChar();
if (Count == 0)
{
if (Digit == "-")
{
AP_vs_minus = '-';
}
else
{
AP_vs_minus = ' ';
}
Digit = "";
Digit += getChar();
}
AP_vs_set[Count] = Digit.toInt();
Count++;
{
Led_Module.setChar(4,7,AP_vs_minus,false);
Led_Module.setDigit(4,6,AP_vs_set[0],false); //Vertical speed
Led_Module.setDigit(4,5,AP_vs_set[1],false);
Led_Module.setDigit(4,4,AP_vs_set[2],false);
Led_Module.setDigit(4,3,AP_vs_set[3],false);
}
}
break;
case 'd': // AP heading set
Count = 0;
while (Count < 3)
{
Digit = "";
Digit += getChar();
AP_hdg_set[Count] = Digit.toInt();
Count++;
}
{
Led_Module.setDigit(2,2,AP_hdg_set[0],false); //Heading
Led_Module.setDigit(2,1,AP_hdg_set[1],false);
Led_Module.setDigit(2,0,AP_hdg_set[2],false);
}
break;
case 'e': // AP course set
Count = 0;
while (Count < 3)
{
Digit = "";
Digit += getChar();
AP_crs_set[Count] = Digit.toInt();
Count++;
}
{
Led_Module.setDigit(0,2,AP_crs_set[0],false); //Course
Led_Module.setDigit(0,1,AP_crs_set[1],false);
Led_Module.setDigit(0,0,AP_crs_set[2],false);
}
break;
case 'f': // AP speed knots set kts
Count = 0;
while (Count < 3)
{
Digit = "";
Digit += getChar();
AP_speed_kt_set[Count] = Digit.toInt();
Count++;
}
{
Led_Module.setDigit(1,6,AP_speed_kt_set[0],false); //Speed in Knts
Led_Module.setDigit(1,5,AP_speed_kt_set[1],false);
Led_Module.setDigit(1,4,AP_speed_kt_set[2],false);
}
break;
case 'g': // AP mach set
Count = 0;
while (Count < 3)
{
Digit = "";
Digit += getChar();
if (Digit ==".")
{
Digit = "";
Digit += getChar();
}
AP_mach_set[Count] = Digit.toInt();
Count++;
}
{
Led_Module.setChar(1,7,' ',false);
Led_Module.setDigit(1,6,AP_mach_set[0],true); //Speed in Mach
Led_Module.setDigit(1,5,AP_mach_set[1],false);
Led_Module.setDigit(1,4,AP_mach_set[2],false);
}
break;
// ************************************************
// Following are the annuciators - LED Indicators
case 'a': // AP active
Digit = "";
Digit += getChar();
if (Digit == "1")
{
digitalWrite(57, HIGH);
}
else
{
digitalWrite(57, LOW);
}
break;
case 't': // AP AutoThrottle armed on/off
Digit = "";
Digit += getChar();
AP_AutoThrottle_arm = Digit.toInt();
if (AP_AutoThrottle_arm == 1 )
{
digitalWrite(69, HIGH);
}
else
{
digitalWrite(69, LOW);
}
break;
case 'q': // Flight Director Active
Digit = "";
Digit += getChar();
AP_Flight_Director_Active = Digit.toInt();
if (AP_Flight_Director_Active == 1 )
{
digitalWrite(A1, HIGH);
}
else
{
digitalWrite(A1, LOW);
}
break;
case 'k': // Altitude lock active
Digit = "";
Digit += getChar();
if (Digit == "1")
{
digitalWrite(59, HIGH);
}
else
{
digitalWrite(59, LOW);
}
break;
case 'm': // APP
Digit = "";
Digit += getChar();
if (Digit == "1")
{
digitalWrite(60, HIGH);
}
else
{
digitalWrite(60, LOW);
}
break;
case 'j': // Heading lock Active
Digit = "";
Digit += getChar();
if (Digit == "1")
{
digitalWrite(63, HIGH);
}
else
{
digitalWrite(63, LOW);
}
break;
case 'p': // VLOC
Digit = "";
Digit += getChar();
if (Digit == "1")
{
digitalWrite(61, HIGH);
}
else
{
digitalWrite(61, LOW);
}
break;
case 'v': // v/s
Digit = "";
Digit += getChar();
if (Digit == "1")
{
digitalWrite(58, HIGH);
}
else
{
digitalWrite(58, LOW);
}
break;
case 'o': // LNAV
Digit = "";
Digit += getChar();
if (Digit == "1")
{
digitalWrite(62, HIGH);
}
else
{
digitalWrite(62, LOW);
}
break;
}
}