Go Down

Topic: NMEA 2000 Shield (Read 398045 times) previous topic - next topic


I ordered it, so I'll try to let you know when I get around to try it in a few weeks time.
There is now new version of NMEA2000 library, NMEA2000_teensy library and also under my repositories developed version of FlexCAN library.

I do not have dual CAN Teensy, so I can not test library with it. But you should not need NMEA2000 with dual CAN except if you are going to write some gateway system.


Hi timo,
I tried the new code with 3 device output and it worked well. Then I tried adding 3rd device and I wasn't successful outputting 3 devices. I read the documentation and it says it is for two devices can you please confirm that it is for two devices only.


Sorry, but I am bit lost. What do you mean with 2 devices? MultiDevice support? In principle it should have only memory limitation. Or something else?


LOL! I know what the "Or something else" limitation is :) Most likely my ability to write code.
I will sweat it little longer and then if I don't succeed I'll post my code with the attempt to add another device. This time I thought I have it right, damn! LOL :smiley-confuse:


With "Something else" I meant that do you mean with 2 devices multi device support or something else. Device has so many meanings that I was not sure.

And about the multi device support - keep you code simple at the beginning and use just single device definition like in the simple example TemperatureSensor. I started multi device thinking in the very beginning, but soon noticed that other devices on bus actually does not care what you say you are. Roughly saying you can show you device as wind instrument and send only cabin temperature. Others are happy for someone sending cabin temperature.


I did try hard for a long time and finally i discovered the "magic bullet"
Apparently I was missing something very simple

Code: [Select]


After I changed the number of devices to 3 it all worked as suppose to.
I did laugh at myself... for a long time. Still shorter time than what I spent trying to figure out why only 2 devices were showing up on the MFD.

I have a question about
it appears that if the second one is remed out everithing still works, or does it?


In these small devices it is not good to use new/free to extend vectors. That is why you have to first say that "I'll have 3 devices, so reserve me this big vector" with NMEA2000.SetDeviceCount(3); So there will be only one new commad to make vector and no free to cause hole to small memory.

It is best to define both. SetDeviceInformation is the most important, since it defines unique ID for you device. Specially serial number should be different. If you do not define SetDeviceInformation, my library tries to survive by changin some instance value, but your MFD probably can't handle it.

SetProductInformation you need so that your MFD will show different names. Otherwise it will show same name for both devices.


Jun 24, 2017, 07:10 pm Last Edit: Jun 24, 2017, 07:17 pm by seamaster
I'm very excited as the boards arrived on Friday. Here is the first look:

Next stop is assambly and revival of the first 3 boards


Bonjour Timo,

I am still waiting for the Mega board I ordered, so I continue my test with Arduino Boards.
Anyway, parts of my latest sketch work, but not together.

There are 2 main parts:
-   Acquiring datas from the serial port of a Victron BMV700 battery Monitor: Current (A),  Voltage (V) and capacity (%)
-   Sending those datas to the SeaTalkNG network (NMEA2000).
I can send datas to a Raymarine MFD or B&G display if I write test values directly in the     
Code: [Select]
SetN2kDCBatStatus(N2kMsg,0,13.87,5.12,35.12,1) command. That is ok.

I can get data from the BMV700 and print them on the serial Monitor. So I gess this part works.
But for that, I must comment (//) all the lines who send the N2K messages, especially this command
Code: [Select]
// tN2kMsg N2kMsg;

As soon as I uncomment these lines, I only get null values for Current, Voltage and Capacity
I get :
"0.00   0.00   0.00"
, instead of, for example:
 "-3.45   12.90   95.45"

Code: [Select]
     // Print the values on the Serial Monitor
     Serial.print (Current);
     Serial.print ("   ");
     Serial.print (Voltage);
     Serial.print ("   ");
     Serial.println (SOC);

During the test I have modified the structure of your Battery Monitor Example, copying the SendN2kBattery subroutine in the main loop.

Why the tN2kMsg N2kMsg; command seems to RAZ my datas ?

Regards, thanks for your great job.

Code: [Select]
// From http://www.jw5zla.com/?p=7 Interfacing the Victron BMV-700
// and Timo Lappalainen'NMEA2000 libraries

#include <Arduino.h>
#include <SoftwareSerial.h>
#include <SPI.h>
SoftwareSerial Victron(0,3);    // RX= Pin 0, TX= Pin 3(Not used)

char p_buffer[80];
#define P(str) (strcpy_P(p_buffer, PSTR(str)), p_buffer)

#define N2k_SPI_CS_PIN 9        // Valeur 10 pour le shield www.elecrow.com, 9 pour le Seeedunio

#include <NMEA2000_CAN.h>       // This will automatically choose right CAN library and create suitable NMEA2000 object
#include <N2kMessages.h>
char c;
String V_buffer;  // Buffer to hold data from the Victron monitor
String E_buffer;  // Buffer to hold data from the ethernet shield
float Current;
float Voltage;
float SOC;

// List here messages your device will transmit.
const unsigned long TransmitMessages[] PROGMEM={127506L,127508L,0};

// ---  Example of using PROGMEM to hold Product ID.  However, doing this will prevent any updating of
//      these details outside of recompiling the program.
const tProductInformation BatteryMonitorProductInformation PROGMEM={
                                       1300,                        // N2kVersion
                                       100,                         // Manufacturer's product code
                                       "Moniteur Batterie Arduino", // Manufacturer's Model ID C'est la ligne qui est détectée comme appareil par le Triton
                                       " (2017-06)",         // Manufacturer's Software version code
                                       " (2017-06)",         // Manufacturer's Model version
                                       "00000001",                  // Manufacturer's Model serial code
                                       0,                           // SertificationLevel
                                       1                            // LoadEquivalency

// ---  Example of using PROGMEM to hold Configuration information.  However, doing this will prevent any updating of
//      these details outside of recompiling the program.
const char BatteryMonitorManufacturerInformation  [] PROGMEM = "FX VAN THUAN";
const char BatteryMonitorInstallationDescription1 [] PROGMEM = "BMV700 Victron & Arduino";
const char BatteryMonitorInstallationDescription2 [] PROGMEM = "Send Informations to the N2K bus";

void setup()

  // Set Product information
  NMEA2000.SetProductInformation(&BatteryMonitorProductInformation );
  // Set Configuration information
  // Set device information
  NMEA2000.SetDeviceInformation(1,      // Unique number. Use e.g. Serial number.
                                170,    // Device function=Battery. See codes on http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                35,     // Device class=Electrical Generation. See codes on  http://www.nmea.org/Assets/20120726%20nmea%202000%20class%20&%20function%20codes%20v%202.00.pdf
                                999     // Just choosen free from code list on http://www.nmea.org/Assets/20121020%20nmea%202000%20registration%20list.pdf                               
  // Uncomment 3 rows below to see, what device will send to bus                           
  // Serial.begin(115200);
   NMEA2000.SetForwardType(tNMEA2000::fwdt_Text);     // Show in clear text. Leave uncommented for default Actisense format.
 Serial.println ("ETAPE 1");
  // If you also want to see all traffic on the bus use N2km_ListenAndNode instead of N2km_NodeOnly below
  // NMEA2000.SetDebugMode(tNMEA2000::dm_ClearText);     // Uncomment this, so you can test code without CAN bus chips on Arduino Mega
  // NMEA2000.EnableForward(false);                      // Disable all msg forwarding to USB (=Serial)
   NMEA2000.SetN2kCANMsgBufSize(2);                      // For this simple example, limit buffer size to 2, since we are only sending data
   NMEA2000.SetN2kCANSendFrameBufSize(30);               // essai suite lecture forum
  Serial.println ("ETAPE 2");
  Serial.println ("ETAPE 3");

void loop() {
  // Victron
  if (Victron.available()) {
    c = Victron.read();
    if (V_buffer.length() <80) {
      V_buffer += c;
    if (c == '\n') {  // New line.
      if (V_buffer.startsWith("I")) {
        String temp_string = V_buffer.substring(V_buffer.indexOf("\t")+1);
        double temp_int = temp_string.toInt();
        Current = (float) temp_int/1000;
      if (V_buffer.startsWith("V")) {
        String temp_string = V_buffer.substring(V_buffer.indexOf("\t")+1);
        int temp_int = temp_string.toInt();
        Voltage = (float) temp_int/1000;
      if (V_buffer.startsWith("SOC")) {
        String temp_string = V_buffer.substring(V_buffer.indexOf("\t")+1);
        int temp_int = temp_string.toInt();
        SOC = (float) temp_int/10;
     // Print the values on the Serial Monitor
     Serial.print (Current);
     Serial.print ("   ");
     Serial.print (Voltage);
     Serial.print ("   ");
     Serial.println (SOC);

//---------------------- Section N2K

     #define BatUpdatePeriod 1000
     static unsigned long TempUpdated=millis();
// tN2kMsg N2kMsg;

   if ( TempUpdated+BatUpdatePeriod<millis() )
    //SetN2kDCBatStatus(N2kMsg,0,13.87,5.12,35.12,1);     // test
    //SetN2kDCStatus(N2kMsg,1,0,0,56,92,38500,0.012);     // test
         Serial.print(millis()); Serial.println(", Battery send ready");

   }   // Fin de la boucle conditionnelle de temps



Are you are still using Uno, I think it is simple memory problem. When you have tN2kMsg N2kMsg; on loop, it will make a reservarion on stack for that object. The total size of N2kMsg is about 240 bytes. That is over 10% of Uno memory.

You can try to squeeze memory more.
- Change NMEA2000.SetForwardStream(&Serial); -> NMEA2000.SetForwardStream(0);
- comment NMEA2000.SetForwardType(tNMEA2000::fwdt_Text);
- uncomment NMEA2000.EnableForward(false);
- change NMEA2000.SetN2kCANSendFrameBufSize(30); -> NMEA2000.SetN2kCANSendFrameBufSize(20);
- you can try even set NMEA2000.SetN2kCANMsgBufSize(1);

Make own functions for Victron and SendN2kInfo, which have own local variables and call them on loop. In this way it is sure that their local varables does not take memory from stack at same time.

Also you have buffers
char p_buffer[80];
String V_buffer;  // Buffer to hold data from the Victron monitor
String E_buffer;  // Buffer to hold data from the ethernet shield

If these are not needed globally, move them inside some function, so they will need RAM on stack, when needed and then released. I have not checked how String class works in point of memory use as global or local.

And also you have to define all options on NMEA2000_CompilerDefns.h to disable all new features to save memory.

I would say that using Uno is just banging your head to the wall!


Jun 27, 2017, 06:34 am Last Edit: Jun 27, 2017, 06:40 am by timolappalainen
And also either disable interrupt by commenting  #define N2k_SPI_CS_PIN 9 to save one extra frame.

Remember also use format
Serial.println (F("ETAPE 2"));
for all string printing. Without F(...) "EATPE2" string takes RAM instead of Flash.


Bonjour Timo,

Thank you for your prompt reply.

Yes I am still working with a Uno board, waiting for the Mega to be delivered.

Lake of memory ! That is what I guessed.
When I add some lines, I loose the Victron values little by little. For example, Voltage or current go down to zero, or even both of them.

I will apply your advices and tell you the result.



Bonjour Timo,

Yesssssss !
I have modified the sketch according to your advices and it woooooooorks !
Thank you !

Thanks to your tricks, I have win around 5 % of memory, and it is enough. after compilation it use 90% of the UNO board memory.
I am on the limit.

Here are some pictures. The Arduino is well recognized by the Triton T41 B&G and the i70 Raymarine, and the datas are displyed on the a78 Raymarine MFD and the T41

The next sketch will be the termometer of the engine water and the fridge.



But after all memory savings it it rather clear that you can not add much more code for your Uno.

Which Victron device you have? Do you know, does they have some output also on Victron MPPT solar charger? One can connect external display to it, but I have not seen any data how they send it, what protocol etc. Could it be same as in your device?

Go Up