Seeed CAN Shield & Uno R3 w/ Haltech ECU

Hello everyone,

I’m trying to use a Seeed CAN Shield and Arduino Uno to create an LCD gauge. I’m not having any issues connecting to the ECU, (Haltech Pro-Plugin), and using the examples provided with the libraries. I can see the CAN ID and buffer information in the serial screen just fine.

Using the provided sample code, (and switching to 1000Kbps):

#include <SPI.h>
#include "mcp_can.h"


const int SPI_CS_PIN = 9;

MCP_CAN CAN(SPI_CS_PIN);                                    

void setup()
{
    Serial.begin(115200);

    while (CAN_OK != CAN.begin(CAN_1000KBPS))              // Haltech uses 1,000Kbps
    {
        Serial.println("CAN BUS Failure...");
        delay(100);
    }
    Serial.println("CAN BUS is ready!");
}


void loop()
{
    unsigned char len = 0;
    unsigned char buf[8];

    if(CAN_MSGAVAIL == CAN.checkReceive())
    {
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

        unsigned char canId = CAN.getCanId();
        
        Serial.println("-----------------------------");
        Serial.print("CAN ID: ");
        Serial.println(canId, HEX);

        for(int i = 0; i<len; i++)    // print the data
        {
            Serial.print(buf[i], HEX);
            Serial.print("\t");
        }
        Serial.println();
    }
}

I receive clear and accurate CAN information from the ECU:

CAN ID: 68
3 AC 0 0 0 0 0 0 
-----------------------------
CAN ID: 6F
0 0 0 0 0 0 0 0 
-----------------------------
CAN ID: 75
0 0 0 0 0 0 0 0 
-----------------------------
CAN ID: 60
5 8 1 7F 0 0 0 0

What I’m having trouble with, is pulling out pieces of the buffer to convert and display on the serial screen, or an LCD screen. ID 68 shows 8 bytes in the buffer, 0 & 1 being lambda(air-fuel ratio) information. The remaining bytes are not used, as those would be for additional wideband sensors. Bytes 0 & 1 combine to hexadecimal 3AC, or decimal 940. I should be able to convert these values further on my own, (940 x .001 = .940 lambda = 13.82 AFR).

I’m having a difficult time pulling these values out directly to display a simple AFR reading on an LCD screen, or the serial screen at least.

Does anyone have any recommendations?
I appreciate any and all help. I’ve been at this for a few days with no luck. I won’t bother showing my botched attempts as there’s quite a few, and they’re embarrassing.

Thank you

I apologize for posting in the wrong section. I realize this should probably be in Programming Questions.

Hi StrokerSi,

What you need to do is to have some type conversions. For the example you mentioned, the ID 86 has the data buffer as:

3 AC 0 0 0 0 0 0

or you also could say:

buf[0] = 0x03
buf[1] = 0xAC
buf[2] = 0x00
(...)

I’n not familiar with the data but if as far I understoo you just need to “merge” those two “uint8_t” bytes into a single “uint16_t” variable. To do that, just use some bit operations, like left or right shifting:

if (canId == 0x68)
{
  uint16_t reading = 0;
  reading = (uint16_t)buf[0] << 8;
  reading |= buf[1];

  Serial.println(reading);
}

I don’t have a C compiler here to test the code, but I believe the idea is quite clear how you can convert two uint8_t into a uint16_t. There a few example on the internet (like this one: http://stackoverflow.com/questions/15249791/combining-two-uint8-t-as-uint16-t). Also, there are many ways to write the same thing, you can do all in a single line or break in multiple lines, depending on your preference.

I also recommend you to stay away from “float” numbers as much as you can, and only “convert” it when you’re printing.

musskopf:
I’n not familiar with the data but if as far I understoo you just need to “merge” those two “uint8_t” bytes into a single “uint16_t” variable. To do that, just use some bit operations, like left or right shifting:

if (canId == 0x68)

{
  uint16_t reading = 0;
  reading = (uint16_t)buf[0] << 8;
  reading |= buf[1];

Serial.println(reading);
}

I see what you’re getting at. I’ll give it a shot in the morning.

Sort of a pain that I have to hook it up to the car each time I make a change.

Much appreciated!

You already have some data samples, so you don't need to hook back in the car to try things out. Just "simulate" the data buffer and go from there.

Cheers