На главную страницу

MCP для X-Plane


СОДЕРЖАНИЕ

1. ВВЕДЕНИЕ
2. СХЕМА ЭЛЕКТРИЧЕСКАЯ СОЕДИНЕНИЙ
3. ОРГАНЫ УПРАВЛЕНИЯ И ИНДИКАЦИИ
4. КОНСТРУКЦИЯ
5. СБОРКА
6. ПРОГРАММИРОВАНИЕ
7. ТЕСТИРОВАНИЕ
8. ПОДКЛЮЧЕНИЕ К СИМУЛЯТОРУ
9. СПРАВОЧНЫЕ МАТЕРИАЛЫ

1. ВВЕДЕНИЕ

Идея сделать бюджетный и технологически простой MCP вынашивалась давно. Было определено, что это должно быть обязательно USB устройство на базе Arduino с использованием единственной платы, пусть и самой продвинутой Mega2560 (рис.1),

Рис.1

а в качестве индикаторов применяются восьмиразрядные модули с чипом MAX7219 (рис.2), включенные гирляндой от трёх до четырёх штук.

Рис.2

Было заманчиво прихватить в компанию ещё какой-нибудь модуль, чтобы максимально использовать предоставляемое мегой 2560 пространство ввода/вывода. Естественно, это должен быть EFIS.

На рис.3 показано взаимодействие устройства с симулятором через плагин с использованием интерфейса USB.

Рис.3
Плагин xfcfmc-0.6.0.zip.
Прошивка arduino_mcp-0.5.3.zip.

Программное обеспечение устройства должно решать две параллельные асинхронные задачи:

1. Опрос органов управления и отправка событий от этих органов в плагин.
2. Приём от плагина данных и их отображение на органах индикации.

На рис.4 показана стуктурная схема программного обеспечения устройства, отвечающая пунктам 1 и 2.

Рис.4

Сначала главный цикл выглядел так:

void loop() 
{
    refresh_all_digits_n_lamps();  /* takes 8640uS for all 4 x 8 digits (64 registers)*/
    discrete_task();               /* takes 441uS for 85 discrete inputs matrix nodes processing*/
}

Было подозрение, что это не будет нормально работать, и оно подтвердилось. Получалось быстродействие чуть более 100 герц. Для дисплеев это даже сверхбыстро, а дискретный ввод нужно вызывать не менее чем 1000 раз в секунду. Захотелось разменять быстродействие обновления дисплеев так, чтобы частота вызова дискретной задачи повысилась, пусть и за счёт снижения частоты обновления индикации. Решение лежало на поверхности. Квантом времени при выводе на дисплей является время записи одного регистра. Что, если вызов дискретной задачи перенести из главного цикла и поместить после каждого вызова функции записи байта в регистр? Так и было сделано.

void refresh_all_digits_n_lamps(void)
{
    *
    *
    max7219_write_byte(pos); /* takes 135uS per one register */
    discrete_task();        /* takes 441uS for 85 discrete inputs (including matrix nodes) processing*/
    *
    *
    max7219_write_byte(bt); /* takes 135uS per one register */
    discrete_task();        /* takes 441uS for 85 discrete inputs (including matrix nodes) processing*/
    * 
    * 
}           

В итоге получается, что дискретная задача вызывается чаще, чем один раз в миллисекунду, что для программного подавления дребезга и обработки энкодеров вполне достаточно. Обновление всех индикаторов происходит 27 раз в секунду, что тоже более чем приемлемо.

f = 1 / ((135uS + 441uS) x 64 регистра) = 27Hz

Потом уже, когда всё было готово, в экспериментальных целях, была добавлена сигнализация входа в discrete_task() и выхода, путём управления свободным выводом Ардуино A0, чтобы подтвердить рассуждения и уточнить численные значения времён. Высокий уровень означает, что процессорное время отдано discrete_task(), а низкий уровень - время на всё остальное. На рис.5 показана осциллограмма сигнала на ножке A0. Видно, что основной потребитель процессорного времени это discrete_task().

Рис.5

1. СХЕМА ЭЛЕКТРИЧЕСКАЯ СОЕДИНЕНИЙ

Схема в формате PDF.

2. ОРГАНЫ УПРАВЛЕНИЯ И ИНДИКАЦИИ

Таблица 1

Обозн.в
схеме соединений
Функция и тип Кол-во Вид (для справки) Контакты для соединения
с цепью GND
SW1 (BANK LIMIT)
SW2 (RANGE)
SW3 (HSI MODE)
Переключатель
1 направление
12 положений
(используется 8)


Rotary switch 1 pole 12 positions
3

S14 (A/P DISENG)
S19 (F/D ON)
S21 (A/T ARM)
Переключатель
1 направление
2 положения

Toggle switch ON-ON
3

2
S32 (ADF1-OFF-VOR1)

S33 (ADF2-OFF-VOR2)
Переключатель
1 направление
2 положения и
нейтраль

Toggle switch ON-OFF-ON
2

2
S16 (SEL) Кнопка

Push Button
(Momentary Push Button)
тип PBS-10C OFF-(ON)
1



(у кнопки выводы
равноправны,
нумерация условная, для
определённости)
S30 (MTRS)
S37 (FPV)
Кнопка

Push Button
(Momentary Push Button) тип DS-314 OFF-(ON)
2

S1 (CRS)
S2 (HDG)
S11 (V/S)
S13 (ALT)
S17 (IAS)
S27 (BARO)
S33 (MINS)
Энкодер (вал-кодер)
с кнопкой

Rotary encoder
with push button
тип EC-11
7

2, 6, 7
S5 (THR)
S8 (SPD)
S12 (LNAV)
S15 (VNAV)
S6 (HDG HOLD)
S9 (V/S)
S18 (ALT HOLD)
S20 (APP)
S22 (LOC)
S24 (B.CRS)
S3 (CMD-L)
S4 (CMD-C)
S7 (CMD-R)
S10 (SPARE)
S25 (WXR)
S26 (STA)
S28 (WPT)
S29 (ARPT)
S31 (DATA)
S34 (POS)
S36 (TERR)
Кнопка, без фиксации
со встроенным светодиодом

тип KD2-22BBR
22

См. рис.6 для
справки о габаритных
размерах кнопки.

См. рис.7 для
информации о
подключении узла кнопки
U1 (CRS)
U2 (IAS,HDG)
U3 (V/S)
U4 (ALT)
Модуль семисегментного
индикатора на 8 разрядов
с чипом MAX7219
4

Модуль U1 подключается
к плате Мега2560 отдельным
пятипроводным шлейфом.
Остальные модули подключаются
к U1 гирляндой, согласно
схеме электрической соединений.
Рис.6
Рис.7

4. КОНСТРУКЦИЯ

На рис.8 показан внешний вид панелей в таком виде, в каком это всё задумывалось. Видно как нерационально используются индикаторы, но это только на первый взгляд. На самом деле такой подход технологичен и экономически оправдан.

Рис.8

На рис.9 показан прототип устройства сразу после сборки.

Рис.9

А это внешний вид со стороны монтажа (рис.10).

Рис.10

При изготовления прототипа использовался вспененный поливинилхлорид (рекламный пластик) толщиною 2 мм. Особенностью этого материала является то, что он легко режется канцелярским ножом и склеивается встык клеем на основе цианакрилата (суперклей "Секунда"). На рис.11 показан шаблон панели, который надо распечатать из файла по ссылке ниже (нужен принтер формата А3), наклеить на заготовку и сделать обрезку по контурам.
Остальные заготовки вырезались по размерам:

  MCP
 =====
 1. Горизонтальные стенки 370 x 50 x 2 мм ....... 2 шт.
 2. Боковые стенки 50 x 76 x 2 мм ............... 2 шт.
 3. Задняя крышка 366 х 76 х 2 мм ............... 1 шт.
 4. Ребро жёсткости 366 x 25 x 2 мм ............. 1 шт.  
 
  EFIS
 ======
 1. Горизонтальные стенки 145 x 50 x 2 мм ....... 2 шт.
 2. Боковые стенки 50 x 76 x 2 мм ............... 2 шт.
 3. Задняя крышка 141 х 76 х 2 мм ................1 шт.

Сначала склеивалась передняя панель MCP с ребром жёсткости таким образом, чтобы образовалась полка для модулей семисегментных индикаторов, а цифры попали в окна на должном уровне. После чего выклеивался весь короб.

Рис.11

Шаблон для лазерной резки по органическому (акриловому) стеклу (рис.12)

Рис.12

Шаблон для печати наклеек на передние панели с надписями (рис.13)

Рис.13
Рисунки панелей в формате Open Office Draw.
Рисунки панелей в формате PDF.

5. СБОРКА

1. Выполнить соединения по цепи GND согласно таблице 1, колонка "Контакты для соединения с цепью GND".
2. Выполнить объединение кнопок в матрицу по схеме соединений. Лист 4 схемы содержит дополнительное изображение матрицы кнопок в прямоугольной системе координат.
3. Выполнить остальные соединения.

6. ПРОГРАММИРОВАНИЕ.

1. Установить среду разработки Arduino IDE (если не установлена) https://www.arduino.cc/en/Main/Software
2. Скачать прошивку arduino_mcp-0.5.3.zip и распаковать в удобное место.
3. Подключить плату Mega2560 к PC при помощи USB кабеля.
4. Определить имя нового коммуникационного USB устройства Arduino Mega 2560 при помощи Диспетчера устройств, как показано на рис.14 в качестве примера.

Рис.14

5. Открыть файл прошивки из места, определённого в пункте 2
.
Рис.15

6. Сделать увеличение размеров приёмного и передающего буферов в файле

корневая папка установки\Arduino\hardware\arduino\avr\cores\arduino\HardwareSerial.h.

До изменений:

#ifndef HardwareSerial_h
#define HardwareSerial_h

#include <inttypes.h>
#include "Stream.h"
После изменений:
#ifndef HardwareSerial_h
#define HardwareSerial_h
     #define SERIAL_TX_BUFFER_SIZE 512
     #define SERIAL_RX_BUFFER_SIZE 1024
#include <inttypes.h>
#include "Stream.h"
7. Выполнить действия, показанные на рис.16, используя в качестве имени порта данные, полученные в п.4

Рис.16


7. После загрузки прошивки на индикаторах должно появиться заполнение цифрами во всех разрядах, соответствующее номеру индикатора (CRS: 00000000 ... ALT:33333333).
Если в результате прошивки выдана ошибка

#error SERIAL_TX_BUFFER_SIZE still is not 512 bytes
или
#error SERIAL_RX_BUFFER_SIZE still is not 1024 bytes,

это может означать, что изменение размера буфера, описанное в п. 6 не выполнено или выполнено, но не в актуальной папке. Такое возможно, если имеются множественные установки Arduino IDE разных версий.

7. ТЕСТИРОВАНИЕ

1. Скачать тестовую программу mcptest.zip и распаковать в удобное место.
2. Отрыть файл удобное_место\mcptest\Resources\plugins\xfcmcp.ini и отредактировать в секции [serial] значение для port_0 согласно полученному значению в разделе 6 п.4. Ниже, для справки, содержимое этого файла.

[mode]
log=on

[serial]
port_0=COM36
#port_1=COM13
#port_2=COM10
#port_3=COM18

[debug]
keyinfo=on

3. Запустить на выполнение файл удобное_место\mcptest\Resources\plugins\mcptest.exe.
4. В результате п.3 должно появиться консольное окно (рис.17), а индикаторы на панели MCP обнулиться.

Рис.17

5. Выполнять действия с органами управления, наблюдать код в окне тестовой программы и сравнивать с кодами на рис.18 и в таблице 2.

Примечание 1. Нажатие на кнопку со встроенной индикацией должно изменять состояние встроенного светодиода.
Примечание 2. При вращении энкодеров должны изменяться показания соответствующих семисегментных индикаторов.
Примечание 3. События органов управления в окне тестовой программы имеют вид:

          0x2048 Key0072, где
          
          0x - признак шестнадцатеричного представления числа
           2 - один из кодов событий (1-событие переключения на позицию (для многопозиционных переключателей)), 
                                      2-событие энкодера, 
                                      4-цепь разомкнута, 
                                      8-цепь замкнута),
           0 - номер порта,
          48 - код события органа управления,
     Key0072 - Имя секции данного органа управления в ini файле.

Примечание 4. Возможно, нужно будет добавить папку размещения mcptest.exe в исключения Защитника Windows. Было замечено значительное потребление процессорного времени PC со стороны защитника Windows при манипуляциях с органами управления MCP. Добавление папки в исключения решило проблему.

8. ПОДКЛЮЧЕНИЕ К СИМУЛЯТОРУ

1. Загрузить плагин xfcmcp-0.5.3.zip
и разместить файлы по своим местам, как показано ниже.

  
 Содержание архива:
 =================== 
 Resources\plugins\xfcmcp.xpl - плагин, скопировать в папку Resources\plugins\ симулятора
 
 Resources\plugins\xfcmcp.ini - дефолтные настройки, скопировать в папку Resources\plugins\ симулятора
 
 for_boeing757_767_folder\xfcmcp.ini - файл с настройками для Boeing757/767 by FF&STS, 
 поместить в папку модели самолёта (если имеется).
 

2. Отрыть файл папка_симулятора\Resources\plugins\xfcmcp.ini и отредактировать в секции [serial] значение для port_0 согласно полученному значению в разделе 6 п.4. Ниже, для справки, часть содержимого этого файла с настройками последовательного порта.

[mode]
log=on

[serial]
port_0=COM36
#port_1=
#port_2=
#port_3=

[debug]
keyinfo=on

[operation]
reload_key = 20

3. Запустить симулятор и проверить функционирование.

Примечание 1. Настроек в самом симуляторе не требуется.

Примечание 2.Лог плагина ведётся в файле папка_симулятора\Resources\plugins\xfcmcp.log и пересоздаётся при каждом запуске плагина.

Примечание 3. Текущий файл настроек можно редактировать на лету, чтобы перезагрузить настройки нужно вызвать пункт меню симулятора
Plugins/FlyingCat USB I/O hub -> Re-register all

Рис.18

или нажать специальную выделенную кнопку (по умолчанию это кнопка SPARE с кодом 20)

Примечание 4. Служебную функцию перезагрузки настроек допускается назначать на любую кнопку, занятую в обычных настройках. Но, желательно назначать малоиспользуемую кнопку.

Примечание 5. При необходимости перегрузить устройство, можно остановить плагин через Plugin Admin симулятора:

Рис.19

Останов плагина не происходит мгновенно, нужно подождать, пока чек в чекбоксе исчезнет. После этого можно переподключить устройство путём отсоединения/присоединения USB кабеля.

9. СПРАВОЧНЫЕ МАТЕРИАЛЫ.

1. Карта кодов событий органов управления и позиций органов индикации

Рис.20

2. Формат события от устройства к плагину

Имеет вид как показано ниже:
  

{252}

Это текстовый протокол с STX/ETX маркерами начала и конца текстового сообщения. Обычно STX имеет код 0x02, a ETX - код 0x03. В текущей реализации эту же самую роль играют символы { и } соответственно.
В примере, указанном выше, каждый символ означает:
{ - Start of text (STX)
2 - один из один из кодов типа событий
52 - код события органа управления в шестнадцатеричном представлении
} - End of text (ETX)

Коды типов событий
1 - событие переключения на позицию
2 - событие энкодера
4 - цепь разомкнута
8 - цепь замкнута

3. Формат сообщения от плагина к устройству для семисегментных индикаторов

Рис.21

4. Формат сообщения от плагина к устройству для одиночных светодиодных индикаторов

Рис.22

5. Таблица распределения пространства ввода/вывода платы Arduino Mega 2560 и коды событий органов управления

Таблица 2

Ножка
Ардуино
ЦепьСигнал Код
при перекл.
на позицию
Нажатие Отпуск. Тумблер
верхнее
Тумблер
нейтр.
Тумблер
нижнее
Энкодер
вращение
по
часовой
Энкодер
вращение
против
часовой
D2
D3S11:1ALT-B0x20500x2051
D4(D1-A- D1-K) X3Key matrix X3
D5D16:AALT HOLD LED
D6D20:AAPP LED
D7D18:ALOC LED
D8D22:AB.CRS LED
D9S14:3AP DISENGAGE0x80410x4041
D10D29:ACMD-R LED
D11D28:ACMD-C LED
D12D24:ASPARE LED
D13D26ACMD-L LED0x20500x2051
D14S11-1ALT-A0x20500x2051
D15S13:1V/S-A0x204E0x204F
D16S13:3V/S-B0x204E0x204F
D17S21:3A/T ARM0x80430x4043
D18D15:ATHR LED
D19S17:3IAS-B0x204A0x204B
D20S17:1IAS-A0x204A0x204B
D21D17:ASPD LED
D22D21:AVNAV LED
D23D19:ALNAV LED
D24D23:AFL.CH LED
D25D25:AHDG HOLD LED
D26(D3-K-D3-A) X4Key matrix X4
D27S19:3F/D ON0x80420x4042
D28(D4-K-D4-A) X1Key matrix X1
D29(D2-K-D2-A) X2Key matrix X2
D30S1:1CRS-A0x20480x2049
D31S1:3CRS-B0x20480x2049
D32U1:3LOAD (CS)
D33U1:4CLK
D34U1:5DIN
D35(D8-K-D8-A) X7 Key matrix X7
D36(D14-K-D14-A) X5Key matrix X5
D37S2:1HDG-A0x204D0x204C
D38S2:2HDG-B0x204D0x204C
D39D5:AWXR LED
D40D7:ASTA LED
D41D9:AWPT LED
D42D10:AARPT LED
D43D11:ADATA LED
D44D12:APOS LED
D45D13:ATERR LED
D46
D47(DXX:K-DXX:A) X8Key matrix X8
D48S27:1BARO-A0x20520x2053
D49S27:3BARO-B0x20520x2053
D50S33:3MINS-B0x20540x2055
D51S33:1MINS-A0x20540x2055
D52S32:3VOR10x40440x8044
D53S32:1ADF10x80450x4045
A0
A1
A2
A3
A4
A5S35:3VOR20x40460x8046
A6S35:1ADF20x80470x4047
A7(D6-K- D6-A) X6Key matrix X6
A8Y1Key matrix Y1
A9Y2Key matrix Y2
A10Y3Key matrix Y3
A11Y4Key matrix Y4
A12Y5Key matrix Y5
A13Y6Key matrix Y6
A14Y7Key matrix Y7
A15Y8Key matrix Y8
A16
Node X1Y1CRS (Encoder Push)0x80010x4001
Node X1Y2THR (Button)0x80020x4002
Node X1Y3SPD (Button)0x80030x4003
Node X1Y4LNAV (Button)0x80040x4004
Node X1Y5VNAV (Button)0x80050x4005
Node X1Y6SEL (Button)0x80060x4006
Node X1Y7IAS (Encoder Push)0x80070x4007
Node X1Y8FL.CH (Button)0x80080x4008
Node X2Y1HDG (Encoder Push)0x80090x4009
Node X2Y2HDG HOLD (Button)0x800A0x400A
Node X2Y3V/S (Button)0x800B0x400B
Node X2Y4ALT (Encoder Push)0x800C0x400C
Node X2Y5ALT HOLD (Button)0x800D0x400D
Node X2Y6APP (Button)0x800E0x400E
Node X2Y7LOC (Button)0x800F0x400F
Node X2Y8B.CRS (Button)0x80100x4010
Node X3Y1CMD-L (Button)0x80110x4011
Node X3Y2CMD-C (Button)0x80120x4012
Node X3Y3CMD-R (Button)0x80130x4013
Node X3Y4SPARE (Button)0x80140x4014
Node X3Y5
Node X3Y6
Node X3Y7
Node X3Y8
Node X4Y1BANK LIMIT AUTO (Rot.sw pole)0x1019
Node X4Y2BANK LIMIT 5 (Rot.sw pole)0x101A
Node X4Y3BANK LIMIT 10 (Rot.sw pole)0x101B
Node X4Y4BANK LIMIT 15 (Rot.sw pole)0x101C
Node X4Y5BANK LIMIT 25 (Rot.sw pole)0x101D
Node X4Y6BANK LIMIT 30 (Rot.sw pole)0x101E
Node X4Y7
Node X4Y8
Node X5Y1WXR (Button)0x80210x4021
Node X5Y2STA (Button)0x80220x4022
Node X5Y3WPT (Button)0x80230x4023
Node X5Y4ARPT (Button)0x80240x4024
Node X5Y5DATA (Button)0x80250x4025
Node X5Y6POS (Button)0x80260x4026
Node X5Y7Terr (Button)0x80270x4027
Node X5Y8
Node X6Y1APP (Rot.sw pole)0x1029
Node X6Y2VOR (Rot.sw pole)0x102A
Node X6Y3MAP (Rot.sw pole)0x102B
Node X6Y4PLN (Rot.sw pole)0x102C
Node X6Y5
Node X6Y6
Node X6Y7
Node X6Y8
Node X7Y1RANGE 5 (Rot.sw pole)0x1031
Node X7Y2RANGE 10 (Rot.sw pole)0x1032
Node X7Y3RANGE 20 (Rot.sw pole)0x1033
Node X7Y4RANGE 40 (Rot.sw pole)0x1034
Node X7Y5RANGE 80 (Rot.sw pole)0x1035
Node X7Y6RANGE 160 (Rot.sw pole)0x1036
Node X7Y7RANGE 320 (Rot.sw pole)0x1037
Node X7Y8RANGE 640 (Rot.sw pole)0x1038
Node X8Y1
Node X8Y2
Node X8Y3
Node X8Y4
Node X8Y5BARO (Encoder Push)0x803E0x403E
Node X8Y6MTRS (Button)0x803D0x403D
Node X8Y7MINS (Encoder Push)0x803F0x403F
Node X8Y8FPV (Button)0x80400x4040

На главную страницу