This at least does something with the Due…
it does detect the start of frame properly, so its a start.
I dont know why it seems to stop working after its detected the SOF though.
//
// J1850 decoder, v1.5
// Mats Ekberg (c) 2013
//
// This software decodes the binary data stream from a J1850 compliant
// OBD2 device. Using just one digital input for the data stream and
// transmitting the decoded data on the UART.
//
// http://www.systemconnection.com/downloads/PDFs/OBD-IIJ1850Whitepaper.pdf
//
// Chip: Arduino Mini Pro w ATmega168 at 16MHz
//
#include <DueTimer.h>
// I/O and interrupts. Pin/Int
// UNO: 2/0, 3/1.
// Mega: 2/0, 3/1, 21/2, 20/3, 19/4, 18/5
#define J1850_PIN 15
#define J1850_INT 15
unsigned long tstamp2;
unsigned long delta2;
unsigned long longbit2;
unsigned long shortbit2;
unsigned long abyte2;
// Timing for start of frame
#define SOF_TIME 200
#define SOF_DEV 18
// Timing for end of frame
#define EOF_TIME 200
#define EOF_DEV 18
// Timing for a long bit pulse
#define LONGBIT_TIME 128
#define LONGBIT_DEV 16
// Timing for short bit pulse
#define SHORTBIT_TIME 64
#define SHORTBIT_DEV 15
// timeout after 250 microsec
#define TMR_PRELOAD (65536 - (EOF_TIME*16))
#define TMROVF_INT_OFF Timer1.stop();
#define TMROVF_INT_ON Timer1.start();
#define TMROVF_INT_CLR Timer1.setPeriod(0);
// forward decl
void j1850_interrupt(void);
volatile boolean idle = true;
// Storage, max 11 data bytes + CRC
#define BUFSIZE 13
volatile uint8_t msgbuf[BUFSIZE];
volatile uint8_t msgLen;
//
// Initialization
//
void setup(void)
{
pinMode(J1850_PIN, INPUT);
Serial.begin(115200);
delay(2000);
Serial.println(F("DUE_j1850decoder/v1.5"));
TMROVF_INT_OFF;
// TCCR1A = 0;
Timer1.setPeriod(TMR_PRELOAD); // preload timer 65536-16MHz/256/2Hz
// TCCR1B = _BV(CS10); // no prescaler, start timer
idle = true;
msgLen = 0;
attachInterrupt(J1850_INT, j1850_interrupt, CHANGE);
interrupts();
}
//
// Background loop - print message when available
//
void loop(void)
{
if (msgLen > 0) {
Serial.print(F("> "));
for (int i = 0; i < msgLen; i++) {
if ((i == 3) || (i == msgLen -1)){
Serial.print(" ");
}
if (msgbuf[i] < 16) Serial.print("0");
Serial.print(msgbuf[i], HEX);
}
Serial.println();
msgLen = 0;
}
}
//
// Interrupt routine for changes on j1850 data pin
//
volatile unsigned long lastInt = 0;
volatile uint8_t bitCnt;
volatile long delta;
volatile unsigned long tstamp;
volatile uint8_t aByte;
volatile uint8_t buf[BUFSIZE];
volatile uint8_t bufIdx;
void j1850_interrupt(void)
{
tstamp = micros();
uint8_t pin = digitalRead(J1850_PIN);
// reload the overflow timer with EOF timeout
Timer1.setPeriod(TMR_PRELOAD);
delta = tstamp - lastInt;
long longbit, shortbit;
if (idle)
{
if (pin == 0)
{
longbit = delta - SOF_TIME;
if (abs(longbit) < SOF_DEV)
{
Serial.println("SOF");
// found SOF, start header/data sampling
idle = false;
bitCnt = 0;
bufIdx = 0;
aByte = 0;
}
}
}
else
{
shortbit = delta - SHORTBIT_TIME;
longbit = delta - LONGBIT_TIME;
if (abs(shortbit) < SHORTBIT_DEV) {
// short pulse
if (pin == 0)
// short pulse & pulse was high => active "1"
aByte = (aByte << 1) | 0x01;
else
// short pulse & pulse was low => passive "0"
aByte = (aByte << 1) & 0xFE;
bitCnt++;
}
else if (abs(longbit) < LONGBIT_DEV) {
// long pulse
if (pin == 0)
// long pulse & pulse was high => active "0"
aByte = (aByte << 1) & 0xFE;
else
// long pulse & pulse was low => passive "1"
aByte = (aByte << 1) | 0x01;
bitCnt++;
}
else {
// unknown bit, reset
TMROVF_INT_OFF;
idle = true;
lastInt = tstamp;
return;
}
if (bitCnt >= 8) {
buf[bufIdx++] = aByte;
bitCnt = 0;
if (bufIdx >= sizeof(buf)) {
// too many data bytes, error
TMROVF_INT_OFF;
idle = true;
}
else {
// if all is ok, start the EOF timeout
TMROVF_INT_CLR;
TMROVF_INT_ON;
}
// abyte2 = aByte;
}
}
lastInt = tstamp;
}
// Timer overlflow interrupt
// Occurs when the EOF pulse times out the timer
//
ISR(TIMER1_OVF_vect)
{
Timer1.setPeriod(TMR_PRELOAD);
TMROVF_INT_OFF;
// copy the data so that we can start to fill the buffer again
// but only if the buffer has been consumed in the background
if (bufIdx > 0 && msgLen == 0)
{
memcpy((void*)msgbuf, (const void*)buf, bufIdx);
msgLen = bufIdx;
}
idle = true;
}