NMEA 2000 Shield

It is a part of the NMEA2000_teensy.cpp. There this is defined:

#if NMEA2000_TEENSY_VER == 1  
  CANbus = new FlexCAN(250000);
#else
  
#if NMEA2000_TEENSY_MAX_CAN_BUSSES == 2 && NMEA2000_TEENSY_VER>1
  if ( CANBusIndex>1 ) CANBusIndex=1;
  if ( CANBusIndex==0 ) { 
    CANbus = &Can0; 
  } else {
    CANbus = &Can1; 
  }
#else
  (void)CANBusIndex; // just avoid warning
  CANbus = &Can0; 
#endif

#endif
  DefTimeOut=_DefTimeOut;
}

This doesn`t say that it is changeable between can1 & can2 but I thought it could be a hint that it is possible. If I understand that right than it is about the 3.2 version.

I think this file is from your repo. I usually just use your files.

All this is because I wanted to use the freqMeasure library for rpm. There the input pin is fixed to pin 3.

The rpm thing is really annoying... One of the last thing I just do not get any working solution done.

Regarding engine torque (PGN 127489 EngineTorque), this is part of engine dynamic parameters. Since this is calculated from EngineSpeed (PGN 127488 EngineSpeed) and the airflow into the engine, shouldn´t this be part of Engine parameters rapid (PGN 127488) instead of Engine parameters dynamic?

Just a thought..

You select CAN bus on contructor second parameter - not with any define. And As I mentioned, only Teensy 3.6 has two CAN bus.

For RMP you could use FreqMeasureMulti library, which is on Teensy framework. See. https://github.com/PaulStoffregen/FreqMeasureMulti It supports pins 5, 6, 9, 10, 20, 21, 22, 23 for Teensy 3.1-3.6 as in readme.

For frequency you need to use lowpass filter with very high filtering, which depends of scaling. I have scaling 1/11 from my altenator W and I get reasonably steady readings with FilterWeight 0.005. Note that with too small FilterWeight RMP gets very slow.

I have not tested code below, but it should work if you fill other necessary code for ...

#include "FreqMeasureMulti.h"

class tFilteredRPM {
protected:
  double Frequency;
  double FilterWeight;
  double Scale;
  uint32_t Pin;
  bool Started;
  FreqMeasureMulti FreqMeasure;
public:
  tFilteredRPM(uint32_t _Pin, double _FilterWeight, double _Scale=1) : 
    Frequency(-1), FilterWeight(_FilterWeight), Scale(_Scale), Pin(_Pin), Started(false) {}
    
  // Call this in loop as often as possible
  void Update() {
    if ( Started ) {
      if ( FreqMeasure.available() ) {
        if ( Frequency<0 ) { // Reset at first read
          Frequency=FreqMeasure.read();
        } else {
          Frequency = (FilterWeight * FreqMeasure.read() + (1 - FilterWeight) * Frequency );
        }
        while ( FreqMeasure.available() ) {
          Frequency = (FilterWeight * FreqMeasure.read() + (1 - FilterWeight) * Frequency );
        }
      }
    } else {
      FreqMeasure.begin(Pin);
      Started=true;
    }
  }

  // Call this to read current RPM
  double Read() const {
    double RPM=0;
    if ( Frequency>=0 ) RPM=FreqMeasureMulti::countToFrequency(Frequency)*60*Scale;
    return RPM;
  }
};

tFilteredRPM RPM(22,0.005,1.0/11.0);

void setup() {
...
}

#define RPMSendPeriod 100

void SendRPM() {
  static unsigned long NextRPMSendTime=millis()+RPMSendPeriod;
  if ( NextRPMSendTime<millis() {
    NextRPMSendTime+=RPMSendPeriod;
    ... RPM.Read()...
  }
}

void loop() {
  ...
  RPM.Update();
  SendRPM();
  ...
}

autopilotNOR:
...shouldn´t this be part of Engine parameters rapid (PGN 127488) instead of Engine parameters dynamic?

Just a thought..

Do not think too much what NMEA organization has been desided. NMEA2000 content is their thoughts and not allways logic.

Thank you Timo!

If I write that something is defined doesn't mean the command #define, this just to clarify.

I`ll try to get that code running. Some things from this sketch I have never seen before like this "public:" & "protected". But I will figure that out I guess! The filtering thing looks also like a new thing for me, special this with FilterWeight. Do you know a place where this method is described since I would like to now how this is working and in which cases I could uses this functionality.

"public:" & "protected" belongs to classes. With classes you can define, which functions or properties are public so that they can be called outside from class. And which are just for internal or inherited use.

The filter method works with many noise data. I use it also for analog. FilterWeight depends of incoming data noice and speed. I use a bit different class and wrote that for example, but it does the main thing - low pass filtering.

See. e.g. A simple digital low-pass filter in C « Kirit Chatterjee

timolappalainen:
"public:" & "protected" belongs to classes. With classes you can define, which functions or properties are public so that they can be called outside from class. And which are just for internal or inherited use.

The filter method works with many noise data. I use it also for analog. FilterWeight depends of incoming data noice and speed. I use a bit different class and wrote that for example, but it does the main thing - low pass filtering.

See. e.g. A simple digital low-pass filter in C « Kirit Chatterjee

Very, very good! Thank you, this pushes me a lot forward! I have looked for months now for the different filtering types but haven´t seen this site yet.

Schematic question regarding resistive sensor in automotive (delivering current instead).

Almost every engine I know has the sensors connected to ground on one side and the other side to the gauges. This gives an voltage divider ( + gauge -> sensor -> ground).

There are very many solutions out there how to connect this to the Arduino.
What is the best practice here if I don't want or can't measure each resistive working area of the sensors?

Another thing, I could stabilize the supply voltage to the sensors by putting an LDO in series to the power supply of the gauges since the supply voltage varies from 12 to 14,2 volt. This is a variation of approx 15% and if I think about the fuel level sensor 15% is a lot in my 300L tank.

What is the best practice for this both questions?

i have a similar issue (albeit my engines/guages are 24V)
and whilst mine seems to be better regulated, there is still some variation in the “positive rail” of the guage - voltage divider - ground.

aside from your suggestion of using a regulated supply to the guages,
one idea I had was to use a second analog input on the arduino to read the “positive rail” voltage
(once again using a voltage divider) - however in this case the voltage divider is fixed, and the
rail voltage changes (a little) .. thus at any given time the arduino knows the actual positive rail voltage and you can then appropriately compensate this in your computation for
measuring the “unknown” voltage divider input.

hopefully my explanation is clear ..

sunnycoastgreg:
i have a similar issue (albeit my engines/guages are 24V)
and whilst mine seems to be better regulated, there is still some variation in the “positive rail” of the guage - voltage divider - ground.

aside from your suggestion of using a regulated supply to the guages,
one idea I had was to use a second analog input on the arduino to read the “positive rail” voltage
(once again using a voltage divider) - however in this case the voltage divider is fixed, and the
rail voltage changes (a little) .. thus at any given time the arduino knows the actual positive rail voltage and you can then appropriately compensate this in your computation for
measuring the “unknown” voltage divider input.

hopefully my explanation is clear ..

Now based on your idea I remember that I anyway measure the system voltage! There I have then the reference of course!

There are several errors in system.

  • reference voltage
  • noise from sensors to measuring system
  • measuring system own noice

So I am bit afraid that if you measure system voltage as own input and then sensor value, you may have noice between measurements and you do not actually get exact measure time difference. If required accuracy is not high, it should give reasonable values.

If it is poosible, I would rather stabilize sensor voltage first. If engine own gauges does not have any differential correction, also them would be stabilized.

For resistive measurement I do not know good way, if you do not know the range of measured sensor. That would require some auto-range system. It is far more easier to measure somehow the range and use suitable constant current source or voltage source+divider resistor. E.g. for tank sensor 30-240 ohm I simply use 3.3 V regulator and 330 resistor. Then I will get range appr. 1.4 - 0.3 V to input.

Hey Timo,

I had the plan to measure the system voltage, by that the charging voltage so I can display it as well.
Currently, I am reading and learning about Aref but I am not sure how that can help with the moving supply voltage for the sensors.
The thing is that the existing gauges should, of course, still be functional. So I thought I could grab the values from the gauges and use them with the Teensy. But I didn't think about that almost all sensor is grounded on one side. This is destroying my whole plan of course.

So if I see the oil pressure sensor for example connected to the gauge as voltage divider then I could grab the voltage supplied to the sensor and break it down with another voltage divider connected to the ground where the middle point connection should give the x - 3.3 V for the teensy.

Regarding using the measured system voltage to use as reference I meant that I could calculate the difference between current system voltage and the 12 V basic voltage of the batteries in %. In max it would be than ~17% (difference between 12 and 14,5 volt). So if the system voltage is currently 14.5 V I could subtract 17% from the measured value before I send it out to the NME2K bus.

This would not fix the problem with lost resolution but I think the resolution is still good enough without working with aref.

This all is just what I think what could work, I am not sure about this is the correct way or that it even would work!

Another thought I had was to use the teensy to power the gauges. By that, I get always shown the correct values on both, MFD and the gauges since the supply voltage is stabilized for the sensors.
This is an old Volvo Penta AQAD40B engine (1986), there are now intelligent sensors at all which correct themselves I guess.
El schema from engine attached.

Engine_EL_SCHEMA.pdf (151 KB)

one thing to be careful of when using a “further voltage divider” to reduce the voltage from existing guage & sensor network.
the additional voltage divider across the sensor adds some additional resistance in the lower leg
of the “guage voltage divider”.
so ideally you want to keep the overall resistance of the voltage divider high,
however there are practical limits given the input impedance of the arduino analog IO .
(i read somewhere that the voltage divider should not be higher than 10k (need to confirm this).

and hence with 10k across a typical tank guage sender unit, it does impact the reading a little.
i did some measurements on my guages (VDO fuel and water ... with resistive sender units.. eg 0-180ohm) and the additinal voltage divider adds a few % error ... not enough to detect
on the analog guage ... but if you plan to keep existing guage - you need to ensure
that you calibrate AFTER adding the extra voltage divider

sunnycoastgreg:
one thing to be careful of when using a “further voltage divider” to reduce the voltage from existing guage & sensor network.
the additional voltage divider across the sensor adds some additional resistance in the lower leg
of the “guage voltage divider”.
so ideally you want to keep the overall resistance of the voltage divider high,
however there are practical limits given the input impedance of the arduino analog IO .
(i read somewhere that the voltage divider should not be higher than 10k (need to confirm this).

and hence with 10k across a typical tank guage sender unit, it does impact the reading a little.
i did some measurements on my guages (VDO fuel and water ... with resistive sender units.. eg 0-180ohm) and the additinal voltage divider adds a few % error ... not enough to detect
on the analog guage ... but if you plan to keep existing guage - you need to ensure
that you calibrate AFTER adding the extra voltage divider

The tank sensor has about max 200 ohm (180 nominal) the others are in the same range. I have an overview from Faria where all this are written down. So if I use the dividers in KOhm area it should not be any problem or causing high error values. Thought to use 9.1K & 24K. This is a lot comparing to the 650 Ohm total the fuel sensor/gauge have. On the gauges, even they are high quality expensive once, there is nothing to adjust, unfortunately. BUT, If this really matter and an error is recognizable than a resistor in parallel to the gauge can compensate I guess.

i was chasing accuracy in fuel tank measurement (I have 2 large tanks that are coupled together)
with only one sender... and a few % is a LOT of litres in my case :slight_smile:
however i quickly realised that the resistive sender unit appears to have quantisation (it doesnt appear to be
a continuous resistance?) .. so given all the errors (inc those mentioned by timo)
and also the effect of boat movement etc ... i realised that a 20 step readout
(ie showing fuel level in 5% increments was the best i could expect ... and realistically
the overall accuracy is probably worse than 5%)

remember that the additional voltage divider you add (is not across the 650ohm ... its across the
voltage output from the sender unit (the lower leg of the voltage divider formed by sender unit( 0-180)

sunnycoastgreg:
i was chasing accuracy in fuel tank measurement (I have 2 large tanks that are coupled together)
with only one sender... and a few % is a LOT of litres in my case :slight_smile:
however i quickly realised that the resistive sender unit appears to have quantisation (it doesnt appear to be
a continuous resistance?) .. so given all the errors (inc those mentioned by timo)
and also the effect of boat movement etc ... i realised that a 20 step readout
(ie showing fuel level in 5% increments was the best i could expect ... and realistically
the overall accuracy is probably worse than 5%)

remember that the additional voltage divider you add (is not across the 650ohm ... its across the
voltage output from the sender unit (the lower leg of the voltage divider formed by sender unit( 0-180)

It depends on what type of fuel level sens it is. The "old good" once where linear 100% resistive sensors. The newer type today is some kind of a pipe with metal or magnetic sensitive switches in series inside. In my case, I have 8 switching points where resistance is added or subtracted depending on position.

With 650 ohms the hole circuit is meant. If I go out from the 180 ohms of the sensor now the additional voltage divider in parallel do not affect the shown value of the gauge at all (180 ohms sensor to 33.1 KOhms voltage divider). If I calculated right this is an error in microAmp. Sensor and gauge together while the sensor have in 180-ohm max. This is values from the datasheet of the gauges/fabricant (Faria Beede).

The movement of the boat has to be compensated by smoothing the measurements.
But there are also other sensors for fuel available, "radar" based once. They are very expensive but deliver a more linear result. But I do not think this is worth the money.

I guess using the digital solution now is much more accurate than the gauges ever have been.

Hey,

I thought to use the RTC of the Teensy 3.5 to count the Engine running seconds and save them to sd. I know there are a ton of threads regarding counting engine running hours, but this all looks so complicated.

As trigger to set the start point I thought to use the rpm (if >=300). How to save the elapsed seconds to sd or EEPROM I have figured out.

Another option I thought can be to use millis to count the seconds and save them to SD every 5 minutes by reading the last saved seconds and add them to the counted seconds and write it back to file.
5 minutes instead of 15 minutes interval I think makes sense since if the power is lost due to the stopped engine I lose too many minutes and the counted time gets to inaccurate.

I use the Teensy 3.5 for all the engine rapid and engine dynamic data (not tested yet live)
I am not sure how the writing to card process will affect the rest of the program. I hope it does not stop the whole process until save to sd is finished?

Any better Idea, does this makes sense?

EEPROM has been guaranteed to work with 100000 write cycles. If you save rarely enough, it is not problem. With 5 s priod you will reach that less than week.

If you have battery on Teensy, you can use VBAT registers.

struct tNvRamData {
   uint32_t EngineRunTime;  // Seconds
};

#define NVRAM_BASE 0x4003E000

tNvRamData *pNvRamData=(tNvRamData *)(NVRAM_BASE); 
...
  pNvRamData->EngineRunTime+=...;
...

tNvRamData has been defined as struct, so you can easily add there more data.

There are totally 32 VBAT registers, but I read somewhere that 0x4003E01C has been used by Teensy code, so there is 28 byte available. This means max. 7 uint32_t.

When you save to SD card, other than interrupts will be stopped.

Very good Timo, thx!

Yesterday I was checking the signal of RPM, that was really strange!
According to the documentation, the signal for rpm should come from an explicit sensor and not from the generator. But I got frequencies from 500 hz to over 1 khz ( see picture attached).
I am not sure, is this frequency normal if this signal comes from the generator?
The results are not hundred % correct.
RPM Hz
1000 520
1100 560
1200 640
1300 690
1400 725
1500 800
2000 1080
2500 1350

See the picture of the oscilloscope at 1000 rpm attached.

So is that normal?

Hey Timo,

I was testing the whole stuff yesterday in the boat. I can't see anything on the MFD at all?
Strange is that I can see all traffic coming from the MFD through the NMEAReader on the teensy.

Do you any hint what could cause that the display does not see the devices at all?

All traffic forwarding is enabled in the config, I tested with enabled serial output and without and forward(false) is commented out.

Regards..