-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNMEAmonitor.ino
465 lines (386 loc) · 17.9 KB
/
NMEAmonitor.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
#include <LCDMenuLib.h>
// ============================================================
//
// NMEAmonitor
//
// Shows N2K values as COG, lat, lon, etc. displaying up to
// 12 data pages. These pages can be suppressed, if the data
// is not interesting.
//
// ============================================================
#include <LiquidCrystal.h>
#include <LCDMenuLib.h>
#include <Arduino.h>
#include <EEPROM.h>
#include <NMEA2000_CAN.h> // This will automatically choose right CAN library and create suitable NMEA2000 object
#include <N2kMessages.h>
#include <NMEA2000.h>
#include <N2kMsg.h>
#include <N2kCANMsg.h>
#include <NMEA2000_teensy.h>
#include <FlexCAN.h>
#include <ActisenseReader.h>
#include <DHT.h>
// lib config
#define _LCDML_DISP_cfg_button_press_time 200 // button press time in ms
#define _LCDML_DISP_cfg_initscreen_time 5000 // enable initscreen time
#define _LCDML_DISP_cfg_scrollbar 0 // enable a scrollbar
#define _LCDML_DISP_cfg_cursor 0x7E // cursor Symbol ->
// *********************************************************************
// LCDML TYPE SELECT
// *********************************************************************
// settings for lcd
#define _LCDML_DISP_cols 20
#define _LCDML_DISP_rows 4
#define PAGE_DISPLAY 3 // each page is displayed 3 sec
#define INITIAL_BACKLIT 100 // initial backlit value
#define INITIAL_BACKLIT_TIMEOUT 15 // initial backlit timeout value 15 sec
#define INITIAL_CONTRAST 32 // initial contrast value
#define PIN_ENTER 10 // button enter
#define PIN_DOWN 11 // button down
#define PIN_UP 12 // button up
#define USE_SERIAL 0 // 1=use serial port, 0=don't use
#define PAGECOUNT 13 // number of pages to be displayed
#define PROG_NAME "N2K Monitor "
#define PROG_VER "29.11.2018 v1.02"
#define SHOW_NAME_VER 4 // show name and version for 4 sec
static int flag[PAGECOUNT] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
static char line[] = " ";
const int ledBuiltin = LED_BUILTIN;
const int ledFront = 21; // front LED
// Connections to LCD:
//
// VO contrast (LCD pin 3) to teensy pin 5 (PWM)
// rs (LCD pin 4) to teensy pin 23
// rw (LCD pin 5) to GND
// enable (LCD pin 6) to teensy pin 22
// Back LED+ (LCD pin 15) to teensy Vin via 100 Ohm
// Back LED- (LCD pin 16) via MOSFET to teensy pin 6 (PWM)
// d4 (LCD pin 11), d5 (LCD pin 12), d6 (LCD pin 13), d7 (LCD pin 14) to teensy pins 17, 16, 15, 14
// LiquidCrystal lcd(RS, Enable, D4, D5, D6, D7)
//
LiquidCrystal lcd(23, 22, 17, 16, 15, 14);
const int lcdContrastPin = 5;
const int lcdBacklitPin = 6;
const uint8_t scroll_bar[5][8] = {
{B10001, B10001, B10001, B10001, B10001, B10001, B10001, B10001}, // scrollbar top
{B11111, B11111, B10001, B10001, B10001, B10001, B10001, B10001}, // scroll state 1
{B10001, B10001, B11111, B11111, B10001, B10001, B10001, B10001}, // scroll state 2
{B10001, B10001, B10001, B10001, B11111, B11111, B10001, B10001}, // scroll state 3
{B10001, B10001, B10001, B10001, B10001, B10001, B11111, B11111} // scrollbar bottom
};
const uint8_t contrast_char[1][8] = {
{B11111, B11111, B11111, B11111, B11111, B11111, B11111, B00000}, // contrast symbol
};
// *********************************************************************
// LCDML MENU/DISP
// *********************************************************************
// LCDML_root => layer 0
// LCDML_root_X => layer 1
// LCDML_root_X_X => layer 2
// LCDML_root_X_X_X => layer 3
// LCDML_root_... => layer ...
// create menu
// menu element count - last element id
// this value must be the same as the last menu element
#define _LCDML_DISP_cnt 9
// LCDML_root => layer 0
// LCDML_root_X => layer 1
// LCDML_root_X_X => layer 2
// LCDML_root_X_X_X => layer 3
// LCDML_root_... => layer ...
// LCDMenuLib_add(id, group, prev_layer_element, new_element_num, lang_char_array, callback_function)
LCDML_DISP_init(_LCDML_DISP_cnt);
LCDML_DISP_add (0 , _LCDML_G1 , LCDML_root , 1 , "About" , LCDML_FUNC_information);
LCDML_DISP_add (1 , _LCDML_G1 , LCDML_root , 2 , "Settings" , LCDML_FUNC);
LCDML_DISP_add (2 , _LCDML_G1 , LCDML_root , 3 , "Display pages" , LCDML_FUNC_initscreen);
LCDML_DISP_add (3 , _LCDML_G1 , LCDML_root_2 , 1 , "Contrast" , LCDML_FUNC_contrast);
LCDML_DISP_add (4 , _LCDML_G1 , LCDML_root_2 , 2 , "Backlit value" , LCDML_FUNC_backlit_value);
LCDML_DISP_add (5 , _LCDML_G1 , LCDML_root_2 , 3 , "Backlit timout" , LCDML_FUNC_backlit_time);
LCDML_DISP_add (6 , _LCDML_G1 , LCDML_root_2 , 4 , "Reset pages" , LCDML_FUNC_reset);
LCDML_DISP_add (7 , _LCDML_G1 , LCDML_root_2 , 5 , "Display pages" , LCDML_FUNC_initscreen);
LCDML_DISP_add (8 , _LCDML_G1 , LCDML_root_2 , 6 , "back" , LCDML_FUNC_back);
LCDML_DISP_add (9 , _LCDML_G7 , LCDML_root , 6 , "DISPLAY" , LCDML_FUNC_initscreen); // in G7 => hidden
LCDML_DISP_createMenu(_LCDML_DISP_cnt);
// *********************************************************************
// LCDML BACKEND (core of the menu, do not change here anything yet)
// *********************************************************************
// define backend function
#define _LCDML_BACK_cnt 1 // last backend function id
LCDML_BACK_init(_LCDML_BACK_cnt);
LCDML_BACK_new_timebased_dynamic (0 , ( 20UL ) , _LCDML_start , LCDML_BACKEND_control);
LCDML_BACK_new_timebased_dynamic (1 , ( 1000UL ) , _LCDML_stop , LCDML_BACKEND_menu);
LCDML_BACK_create();
static int currentBacklit = INITIAL_BACKLIT;
static int oldBacklit = INITIAL_BACKLIT;
static int currentBacklitTimeout = INITIAL_BACKLIT_TIMEOUT;
static int oldBacklitTimeout = INITIAL_BACKLIT_TIMEOUT;
static int BackLitTimeout = 0;
static int currentContrast = INITIAL_CONTRAST;
static int oldContrast = INITIAL_CONTRAST;
static double LAT_DEG_disp;
static double LAT_MIN_disp;
static double LONG_DEG_disp;
static double LONG_MIN_disp;
static double SOG_disp;
static double COG_disp;
static double STW_disp;
static double HDG_disp;
static double Hum_disp;
static double TempAirHum_disp;
static double Press_disp;
static double TempAirPress_disp;
static double LOG_disp;
static double TRIP_disp;
static double Bft_disp;
static double Gwd_disp;
static char GwdRose_disp[] = "N ";
static double TWS_disp;
static double TWA_disp;
static double TWD_disp;
static double AWS_disp;
static double AWA_disp;
static double AWArel_disp;
static double AWD_disp;
static int row;
typedef struct
{
unsigned char second; // 0-59
unsigned char minute; // 0-59
unsigned char hour; // 0-23
unsigned char day; // 1-31
unsigned char month; // 1-12
unsigned int year; // 0-9999
}
date_time_t;
static date_time_t DatumZeit_disp;
static double TempWater_disp;
static double Depth_disp;
Stream *OutputStream;
// *********************************************************************
// SETUP
// *********************************************************************
void setup()
{
int i;
// Set Product information
NMEA2000.SetProductInformation("00000123", // Manufacturer's Model serial code
100, // Manufacturer's product code
PROG_NAME, // Manufacturer's Model ID
PROG_VER, // Manufacturer's Software version code
"sby Teensy-N2K-Device", // Manufacturer's Model version
1, // LoadEquivalency
1300, // N2kVersion
1 // CertificationLevel
);
// Det device information
NMEA2000.SetDeviceInformation(123456, // Unique number. Use e.g. Serial number.
130, // Device function=PC Gateway. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
25, // Device class=Inter/Intranetwork Device. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
228 // Manufacturer Code=ZF Marine Electronics. Just choosen free from code list on http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf
);
#if USE_SERIAL == 1
while(!Serial); // wait until serial ready
Serial.begin(115200);
OutputStream = &Serial;
// serial init; only be needed if serial control is used
Serial.println(F(PROG_NAME)); // only for examples
Serial.println(F(PROG_VER)); // only for examples
#else
Serial.begin(115200);
OutputStream = &Serial;
#endif
// to use the alternative can0 with Tindie CAN-Bus Adapter, set High speed mode
pinMode(28, OUTPUT);
digitalWrite(28, LOW);
// to use the can0 with Tindie CAN-Bus Adapter, set High speed mode
pinMode(2, OUTPUT);
digitalWrite(2, LOW);
NMEA2000.SetForwardStream(&Serial);
//NMEA2000.SetForwardType(tNMEA2000::fwdt_Text); // Show in clear text. Leave commented for default Actisense format.
NMEA2000.SetForwardOwnMessages();
// If you also want to see all traffic on the bus use N2km_ListenAndNode instead of N2km_NodeOnly below
NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, 22); // SRC-Addr on N2K-Bus
// NMEA2000.EnableForward(false); // Disable all msg forwarding to USB (=Serial)
NMEA2000.SetMsgHandler(HandleNMEA2000Msg);
NMEA2000.Open();
pinMode(ledBuiltin, OUTPUT);
pinMode(ledFront, OUTPUT);
// check if EEPROM contains a valid config
// start reading from the first byte (address 0) of the EEPROM
if (EEPROM.read(0) == 0xA5) {
// EEPROM contains valid values for flag and contrast
oldContrast = EEPROM.read(1); // read contrast value from EEPROM
oldBacklit = EEPROM.read(2); // read backlit value from EEPROM
oldBacklitTimeout = EEPROM.read(3); // read backlit timeout from EEPROM
// flag loop
for ( i=0; i < PAGECOUNT; i++ ){
flag[i] = EEPROM.read(i+4);
}
}
else {
// EEPROM contains NO valid values for flag and contrast
EEPROM.write(0, 0xA5); // write signature into EEPROM
EEPROM.write(1, oldContrast); // write contrast value into EEPROM
EEPROM.write(2, oldBacklit); // write backlit value into EEPROM
EEPROM.write(3, oldBacklitTimeout); // write backlit timeout into EEPROM
// flag loop
for ( i=0; i < PAGECOUNT; i++ ){
EEPROM.write(i+4, flag[i]); // write flags into EEPROM
}
}
pinMode(lcdContrastPin, OUTPUT);
analogWrite(lcdContrastPin, oldContrast);
pinMode(lcdBacklitPin, OUTPUT);
analogWrite(lcdBacklitPin, oldBacklit);
// LCD Begin
lcd.begin(_LCDML_DISP_cols,_LCDML_DISP_rows);
// Up to eight characters of 5x8 pixels can be programmed (numbered 0 to 7)
// set special chars for scrollbar
lcd.createChar(0, (uint8_t*)scroll_bar[0]);
lcd.createChar(1, (uint8_t*)scroll_bar[1]);
lcd.createChar(2, (uint8_t*)scroll_bar[2]);
lcd.createChar(3, (uint8_t*)scroll_bar[3]);
lcd.createChar(4, (uint8_t*)scroll_bar[4]);
// set special char for contrastbar
lcd.createChar(5, (uint8_t*)contrast_char[0]);
// Enable all items with _LCDML_G1
LCDML_DISP_groupEnable(_LCDML_G1); // enable group 1
// LCDMenu Setup
LCDML_setup(_LCDML_BACK_cnt);
lcd.setCursor(0,0);
lcd.print(F(PROG_NAME)); // print first line to lcd display
lcd.setCursor(0,1);
lcd.print(F(PROG_VER)); // print second line to lcd display
if (_LCDML_DISP_rows == 4) {
lcd.setCursor(0, 2);
lcd.print(line); // print third line to lcd display
lcd.setCursor(0, 3);
lcd.print(line); // print fourth line to lcd display
}
delay(SHOW_NAME_VER*1000);
setupPressHumTemp();
LCDML_DISP_jumpToFunc(LCDML_FUNC_initscreen); // jump to initscreen
}
// *********************************************************************
// LOOP
// *********************************************************************
#define PressHumTempUpdatePeriod 2000
static unsigned long PressHumTempUpdated = millis();
#define EngineUpdatePeriod 2000
static unsigned long EngineUpdated = millis();
void loop()
{
tN2kMsg N2kMsg;
// example for init screen
if((millis() - g_lcdml_initscreen) >= _LCDML_DISP_cfg_initscreen_time) {
g_lcdml_initscreen = millis(); // reset init screen time
lcd.setCursor(0,1); // clear the secound line on lcd
lcd.print(F(" "));
LCDML_DISP_jumpToFunc(LCDML_FUNC_initscreen); // jump to initscreen
}
ledFrontUpdate();
if (PressHumTempUpdated + PressHumTempUpdatePeriod < millis()) {
PressHumTempUpdated = millis();
ReadHumTemp();
ReadPressTemp();
SetN2kOutsideEnvironmentalParameters(N2kMsg, 1, CToKelvin(TempAirHum_disp), CToKelvin(TempAirHum_disp), mBarToPascal(Press_disp));
NMEA2000.SendMsg(N2kMsg);
//SetN2kOutsideEnvironmentalParameters(tN2kMsg &N2kMsg, unsigned char SID, double WaterTemperature, double OutsideAmbientAirTemperature=N2kDoubleNA, double AtmosphericPressure=N2kDoubleNA)
SetN2kEnvironmentalParameters(N2kMsg, 1, N2kts_OutsideTemperature, CToKelvin(TempAirHum_disp), N2khs_OutsideHumidity, Hum_disp, mBarToPascal(Press_disp)); // N2K: 130311 Environmental Parameters(Cabin Temp, Humidity, Pressure)
// SetN2kEnvironmentalParameters(N2kMsg, 1, N2kts_OutsideTemperature, CToKelvin(TempAirPress_disp), N2khs_OutsideHumidity, Hum_disp, mBarToPascal(Press_disp)); // N2K: 130311 Environmental Parameters(Cabin Temp, Humidity, Pressure)
NMEA2000.SendMsg(N2kMsg); // i70: Air-temp, Humidity, Pressure
}
if (EngineUpdated + EngineUpdatePeriod < millis()) {
EngineUpdated = millis();
SetN2kPGN127488(N2kMsg, 1 /*unsigned char EngineInstance*/, 1100 /*double EngineSpeed*/,
N2kDoubleNA /*double EngineBoostPressure = N2kDoubleNA*/, N2kInt8NA /*int8_t EngineTiltTrim = N2kInt8NA*/);
// Engine parameters rapid
// Input:
// - EngineInstance Engine instance.
// - EngineSpeed RPM (Revolutions Per Minute)
// - EngineBoostPressure in Pascal
// - EngineTiltTrim in %
NMEA2000.SendMsg(N2kMsg);
// trace("PGN: 127488:");
SetN2kPGN127489(N2kMsg, 1 /*unsigned char EngineInstance*/, N2kDoubleNA /*double EngineOilPress*/, 373 /*double EngineOilTemp*/,
300 /*double EngineCoolantTemp*/, 13.6 /*double AltenatorVoltage*/,
4 /*double FuelRate*/, 1300 /*double EngineHours*/, N2kDoubleNA /*double EngineCoolantPress=N2kDoubleNA*/,
N2kDoubleNA /*double EngineFuelPress=N2kDoubleNA*/,
N2kInt8NA /*int8_t EngineLoad=N2kInt8NA*/, N2kInt8NA /*int8_t EngineTorque=N2kInt8NA*/,
true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false);
// Engine parameters dynamic
// Input:
// - EngineInstance Engine instance.
// - EngineOilPress in Pascal
// - EngineOilTemp in Kelvin
// - EngineCoolantTemp in Kelvin
// - AltenatorVoltage in Voltage
// - FuelRate in litres/hour
// - EngineHours in seconds
// - EngineCoolantPress in Pascal
// - EngineFuelPress in Pascal
// - EngineLoad in %
// - EngineTorque in %
// - flagCheckEngine
// - flagOverTemp
// - flagLowOilPress
// - flagLowOilLevel
// - flagLowFuelPress
// - flagLowSystemVoltage
// - flagLowCoolantLevel
// - flagWaterFlow
// - flagWaterInFuel
// - flagChargeIndicator
// - flagPreheatIndicator
// - flagHighBoostPress
// - flagRevLimitExceeded
// - flagEgrSystem
// - flagTPS
// - flagEmergencyStopMode
// - flagWarning1
// - flagWarning2
// - flagPowerReduction
// - flagMaintenanceNeeded
// - flagEngineCommError
// - flagSubThrottle
// - flagNeutralStartProtect
// - flagEngineShuttingDown
NMEA2000.SendMsg(N2kMsg);
// trace("PGN: 127489:");
SetN2kPGN127493(N2kMsg, 1 /*unsigned char EngineInstance*/, N2kTG_Forward /*tN2kTransmissionGear TransmissionGear*/,
200 /*double OilPressure*/, 300 /*double OilTemperature*/, 0 /*unsigned char DiscreteStatus1=0*/);
// Transmission parameters, dynamic
// Input:
// - EngineInstance Engine instance.
// - TransmissionGear Selected transmission. See tN2kTransmissionGear
// - OilPressure in Pascal
// - OilTemperature in K
// - EngineTiltTrim in %
NMEA2000.SendMsg(N2kMsg);
// trace("PGN: 127493:");
}
NMEA2000.ParseMessages();
// this function must called here, do not delete it
LCDML_run(_LCDML_priority);
}
#define ledFrontUpdatePeriod 1000
void ledFrontUpdate() {
static unsigned long ledFrontUpdated=millis();
if ( ledFrontUpdated+ledFrontUpdatePeriod<millis() ) {
ledFrontUpdated=millis();
digitalWrite(ledFront, HIGH); //LED=on
delay(100);
digitalWrite(ledFront, LOW); //LED=off
}
}
// *********************************************************************
// check some errors - do not change here anything
// *********************************************************************
# if(_LCDML_DISP_rows > _LCDML_DISP_cfg_max_rows)
# error change value of _LCDML_DISP_cfg_max_rows in LCDMenuLib.h
# endif
# if(_LCDML_DISP_cols > _LCDML_DISP_cfg_max_string_length)
# error change value of _LCDML_DISP_cfg_max_string_length in LCDMenuLib.h
# endif