Skip to content

Latest commit

 

History

History
376 lines (270 loc) · 11.4 KB

README.md

File metadata and controls

376 lines (270 loc) · 11.4 KB

maszynaduino

experimental

Maszynaduino jest biblioteką dla Arduino (Uno, Mega, etc) ułatwiającą oprogramowanie pulpitów budowanych na potrzeby symulatora MaSzyna (aka EU07).

Biblioteka posiada obiektowy interfejs i ułatwia korzystanie z analogowych multiplekserów umożliwiających obsługę większej ilości kontrolek, przełączników i mierników, niż fizycznie posiadają mikrokontrolery.

Możliwości

  • obiektowy interfejs
  • szeregowa konsola do diagnostyki
  • wsparcie dla analogowych multiplekserów (typu 74HC4067)
  • obsługa kontrolek i przełączników
  • prostota użycia i czytelność
  • kompatybilność z MaSzyną wysyłającą preambułę w komunikacji UART (cztery bajty 0xEF na początkach ramek wejść i wyjść)

Pierwsze kroki

Użycie biblioteki należy rozpocząć od załadowania plików nagłówkowych:

#include "maszynaduino.h"

W dalszej części (przed setup() i loop()) trzeba zadeklarować kontrolki, przełączniki i sam pulpit. Przykładowo przełącznik baterii podłączony do portu 2 można zadeklarować następująco:

#define PIN_BATERIA 2

Switch *bateria = new PinSwitch(PIN_BATERIA, 0, 2)

Parametry konstruktora PinSwitch są następujące:

  • nr pinu
  • nr bajtu ramki wyjścia (tu: 0, liczony bez preambuły)
  • nr bitu do gaszenia / zapalania (tu: 2)

Do pinu 3 podłączymy kontrolkę lampki czuwaka:

#define PIN_LAMPKA_CZUWAK 3

Indicator *lampkaCzuwaka = new PinIndicator(PIN_LAMPKA_CZUWAK, 4, 6);

Parametry konstuktora PinIndicator są następujące:

  • nr pinu
  • nr bajtu ramki wejścia (tu: 4, liczony bez preambuły)
  • nr bitu określającego stan kontrolki (tu: 6)

W następnym kroku należy utworzyć pulpit określając szeregowy port do komunikacji:

Console *sm42 = new Console(&Serial);

W funkcji setup() należy dodać do pulpitu utworzone przełącznik i kontrolkę, oraz zainicjować pulpit.

void setup() {
    sm42->addSwitch(bateria);           // dodanie przełącznika baterii
    sm42->addIndicator(lampkaCzuwaka);  // dodanie kontrolki czuwaka
    sm42->setup();                      // zainicjowanie pulpitu
}

W funkcji loop() należy dodać aktualizację pulpitu oraz transmisję danych:

void loop() {
    sm42->update();            // aktualizacja pulpitu
    sm42->transmit();          // komunikacja Pulpit <-> PC
}

Aby przykład zadziałał w MaSzynie, w pliku eu07_input-uart.ini, musi pojawić się adekwatny wpis:

2 toggle batteryenable batterydisable

Kompletny przykład:

#include "maszynaduino.h"

#define PIN_BATERIA 2
#define PIN_LAMPKA_CZUWAK 3

Switch *bateria = new PinSwitch(PIN_BATERIA, 0, 2);
Indicator *lampkaCzuwaka = new PinIndicator(PIN_LAMPKA_CZUWAK, 4, 6);

Console *sm42 = new Console(&Serial);


void setup() {
  sm42->addSwitch(bateria);
  sm42->addIndicator(lampkaCzuwaka);
  sm42->setup();
}

void loop() {
  sm42->update();
  sm42->transmit();
}

Schemat połączeń

Do przełączników nie trzeba podłączać rezystorów ściągających, ponieważ Maszynaduino domyślnie konfiguruje wejścia w trybie INPUT_PULLUP (z rezystorami podciągającymi wbudowanymi w Arduino). W razie potrzeby dowolny przełącznik można skonfigurować bez użycia rezystora podciągającego - biblioteka zadba o prawidłową interpretację stanu wejścia.

maszynaduino-example-01

Transmisja danych

W tej chwili Console konfiguruje port szeregowy na 57600 bodów (bez możliwości zmiany), i taką prędkość należy ustawić w eu07.ini w MaSzynie.

Elementy interfejsu programistycznego

Uwaga. Do wydania wersji 1.0 API biblioteki może się zmieniać bez zachowania kompatybilności.

Główne klasy i struktury

Klasa Opis
PinSwitch przełącznik podłączony bezpośrednio do pinu mikrokontrolera
MuxSwitch przełącznik podłączony przez multiplekser
PinIndicator kontrolka podłączona bezpośrednio do pinu mikrokontrolera
Console obiekt opisu i obsługi pulpitu (może być zdefiniowanych wiele pulpitów)
Mux obsługa pojedynczego multipleksera
ConsoleDebug konsola debugowania podłączana do portu szeregowego
Struktura Opis
InputFrame struktura opisująca ramkę wejśc z symulatora (PC)
OutputFrame struktura opisująca ramkę wyjść do symulatora (PC)

Ramki InputFrame i OutputFrame

struct InputFrame {
    uint8_t preamble[4];       // 0-3
    uint16_t tacho;             // 4-5
    uint8_t indicator0;        // 6
    uint8_t indicator1;        // 7
    uint8_t indicator2;        // 8
    uint8_t indicator3;        // 9
    uint8_t indicator4;        // 10
    uint16_t break_pressure;    // 11-12
    uint16_t pipe_pressure;     // 13-14
    uint16_t tank_pressure;     // 15-16
    uint16_t hv_voltage;        // 17-18
    uint16_t hv_current1;       // 19-20
    uint16_t hv_current2;       // 21-22
    uint16_t hv_current3;       // 23-24
    uint16_t year_month;        // 25-26
    uint16_t day_hour_minute;   // 27-28
    uint16_t second_milisecond; // 29-30
    uint32_t odometer;          // 31-34
    uint16_t lv_voltage;        // 35-36
    uint8_t radio_channel;     // 37
    uint8_t unused[14];        // 38-51
};
struct OutputFrame {
    uint8_t preamble[4];
    uint8_t switch0;
    uint8_t switch1;
    uint8_t switch2;
    uint8_t switch3;
    uint8_t switch4;
    uint8_t switch5;
    uint8_t master_controller;
    uint8_t second_controller;
    uint16_t train_brake;
    uint16_t independent_brake;
    uint8_t unused[4];
};

KLasa Console

InputFrame* Console::getInputs();        // odczyt stanu wejść (ostatnio odebrane)
OutputFrame* Console::getOutputs();      // odczyt stanu wyjść (do wysłania)
void addSwitch(Switch *);                // dodanie przełącznika
void addIndicator(Indicator *indicator); // dodanie kontrolki 
void setup();                            // inicjalizacja
void update();                           // aktualizacja przełączników, kontrolek, mierników, itp
void transmit();                         // odebranie i wysłanie danych z/do PC

Konstruktor:

Console(HardwareSerial *serial);
Console(HardwareSerial *serial, Switch **switches, int switchesCount);
Console(HardwareSerial *serial, Switch **switches, int switchesCount, Indicator **indicators, int indicatorsCount);

Przełączniki i kontrolki można podać jako tablice bez konieczności dodawania ich pojedynczo w setup(). Ekwiwalentem dla przykładu z dokumentacji będzie:

Indicator *kontrolki[] = {lampkaCzuwaka};
Switch *hebelki[] = {bateria};

Console *sm42 = new Console(
    &Serial,
    hebelki, ARRAY_LENGTH(hebelki),
    kontrolki, ARRAY_LENGTH(kontrolki)
);

void setup() {
    sm42->setup();
}    

ARRAY_LENGTH jest typowym makrem definiowanym przez bibliotekę.

Użycie multiplekserów

Uwaga. Interfejs obsługi multiplekserów może się zmienić przed wydaniem wersji 1.0

Aby zwiększyć liczbę I/O należy zastosować multiplekser (jeden lub więcej). Biblioteka testowana jest o popularny układ 74HC4067, 16-to kanałowy analogowy multiplekser.

W celu opisania multipleksera wpiętego w układ należy utworzyć instancję klasy Mux z opisem użytych pinów, a przy tworzeniu instancji przełączników lub kontrolek użyć klas dedykowanych dla multipleksera.

Zakładając, że mamy jeden multiplekser wpięty do pinów:

  • 2: pin "enable" multipleksera
  • 3: pin "data" multipleksera
  • 4, 5, 6, 7: piny sterujące "S0-S3" multipleksera, w kodzie programu należy zdefiniować multiplekser następująco:
// Mux(int pinEnable, int pinData, int pinS0, int pinS1, int pinS2, int pinS3);

Mux* mux1 = new Mux(2, 3, 4, 5, 6, 7);

a przełącznik baterii z przykładu należałoy zdefiniować następująco:

// MuxSwitch(Mux *mux, int channel, int nrBajtuRamki, int nrBitu);

Switch *bateria = new MuxSwitch(mux1, MUX_CH1, 0, 2);

Ponieważ multiplekser zajął pin 3, to lampkę czuwaka (z przykładu) należałoby podłączyć do innego pinu (np. 8). To wszystkie zmiany, które należy wprowadzić w celu przeniesienia przełącznika na multiplekser.

Konsola debugowania

Maszynaduino posiada prostą konsolę szeregową do ułatwienia debugowania. Konsolę można podłączyć pod dowolny port szeregowy wpierany przez Arduino.

maszynaduino_consoledebug

// Pulpit będzie komunikował się z PC podstawowym portem (`Serial`)
Console *sm42 = new Console(&Serial);  

// Konsola debugowania będzie używała portu `Serial1`
ConsoleDebug *debug = new ConsoleDebug(sm42, &Serial1);

void setup() {
    sm42->setup();
    debug->setup();
}

void loop() {
    sm42->update();
    sm42->transmit();

    // wysłanie debug output na konsolę debugowania
    debug->send();
}

Aby wykorzystać dodatkowe porty szeregowe do debugowania, konieczna będzie płytka obsługująca większą liczbę portów szeregowych (typu Arduino Mega, Arduino Due) oraz adapter USB.

usb-ttl-serial-adapter

Konsolę debugowania można też uruchomić także na urządzeniach z jednym portem szeregowym (typu Arduino Uno). W tej sytuacji nie powino się transmitować danych z/do PC (za pomocą Console::transmit()), bo zaburzy to dzialanie konsoli. Transmisję danych warto wtedy uruchamiać warunkowo. Przykład:

#define DEBUG

#ifdef DEBUG
ConsoleDebug *debug = new ConsoleDebug(sm42, &Serial);
#endif

void setup() {
  // ...
#ifdef DEBUG
    debug->setup();
#endif
  // ...
}

void loop() {
  // ...
#ifdef DEBUG
    debug->send();
#else
    sm42->update();
    sm42->transmit();
#endif
  // ...
}

Transmisja

Ponieważ konsola debugowania wysyła polecenia terminala do "czyszczenia" ekranu, zalecane jest korzystanie z Putty lub Screena zamiast Serial Monitora wbudowanego w Arduino IDE. Przykładowo:

screen /dev/ttyACM0 57600

Transmisja konsoli debugowania wymaga ustawienia prędkości na 57600 bodów. W przyszłości będzie możliwa zmiana.

Plan rozwoju

1.0

  • przełączniki (bezpośrednio do pinów)
  • przełączniki (przez multiplekser)
  • kontrolki (bezpośrednio do pinów)
  • kontrolki (przez multiplekser)
  • przełączniki wielopozycyjne
  • wskaźniki / mierniki (direct i mux)
  • ułatwienie obsługi wielu multiplekserów (do 4 szt, common data i select)
  • optymalizacje, użycie przerwań, ewentualna przebudowa i stabilizacja API

1.1

  • gotowe rozwiązania dla mierników, manometrów (np. servo)

Sugestie i pytania

Pytania i sugestie proszę wpisywać za pomocą https://github.com/marcinn/maszynaduino/issues

FAQ

Czy można korzystać z biblioteki za darmo?

Tak.

Czy mogę budować swoje produkty w oparciu o nią?

Tak, ale z zachowaniem zasad licencji GPL v3.0 (w skrócie - powstały produkt także musi być tak samo licencjonowany i dystrybuowany).

Biblioteka nie posiada bardzo potrzebnej funkcji.

Należy opisać problem, sugestię lub zapotrzebowanie za pomocą https://github.com/marcinn/maszynaduino/issues.