diff options
-rw-r--r-- | README.md | 10 | ||||
-rw-r--r-- | libraries/OBD/OBD.cpp | 40 | ||||
-rw-r--r-- | libraries/OBD2UART/OBD2UART.cpp | 247 | ||||
-rw-r--r-- | libraries/OBD2UART/OBD2UART.h | 74 | ||||
-rw-r--r-- | libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino | 81 | ||||
-rw-r--r-- | libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino | 97 | ||||
-rw-r--r-- | libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino | 9 | ||||
-rw-r--r-- | libraries/OBD2UART/keywords.txt | 29 | ||||
-rw-r--r-- | libraries/OBD2UART/library.properties | 9 | ||||
-rw-r--r-- | nanologger/README.txt | 5 | ||||
-rw-r--r-- | nanotimer/README.md | 3 | ||||
-rw-r--r-- | simple_obd_display/simple_obd_display.ino | 105 |
12 files changed, 537 insertions, 172 deletions
@@ -1,13 +1,15 @@ Arduino OBD-II Adapter Library & Sketches ========================================= -(C)2012-2017 Freematics.com +(C)2012-2018 Freematics.com -OBD-II Adapter for Arduino is a product that works as a vehicle OBD-II data bridge for Arduino (literally all embedded platforms) with open-source Arduino library provided. Besides providing easy-to-use OBD-II data access, it also integrates 6-axis MEMS sensor module and a voltmeter for measuring vehicle battery power. The adapter draws power from OBD-II port and convert it to 5V for powering attached device. +OBD-II Adapter for Arduino is a product that works as a vehicle OBD-II data bridge for Arduino (literally all embedded platforms) with open-source Arduino library provided. Besides providing easy-to-use OBD-II data access, it also integrates 9-DOF motion sensor and voltmeter for measuring vehicle battery power. The adapter draws power from OBD-II port and convert it to 5V for powering attached device. -OBD-II Adapter: http://freematics.com/pages/products/arduino-obd-adapter/ +Related Products -OBD-II Telematics DIY Kit: http://freematics.com/pages/products/arduino-telematics-kit-3/ +* [Freematics OBD-II UART Adapter](https://freematics.com/pages/products/freematics-obd-ii-uart-adapter-mk2/) +* [Freematics OBD-II I2C Adapter](https://freematics.com/pages/products/arduino-obd-adapter/) +* [OBD-II Telematics Mega Kit](https://freematics.com/pages/products/arduino-telematics-kit-3/) ![Image](http://www.arduinodev.com/wp-content/uploads/2012/03/obdkit1-150x150.jpg) diff --git a/libraries/OBD/OBD.cpp b/libraries/OBD/OBD.cpp index 8dbdd29..92b9bdf 100644 --- a/libraries/OBD/OBD.cpp +++ b/libraries/OBD/OBD.cpp @@ -298,21 +298,31 @@ float COBD::getVoltage() bool COBD::getVIN(char* buffer, byte bufsize) { - if (sendCommand("0902\r", buffer, bufsize)) { - char *p = strstr(buffer, "0: 49 02"); - if (p) { - char *q = buffer; - p += 10; - do { - for (++p; *p == ' '; p += 3) { - if (*q = hex2uint8(p + 1)) q++; - } - p = strchr(p, ':'); - } while(p); - *q = 0; - return true; - } - } + for (byte n = 0; n < 5; n++) { + if (sendCommand("0902\r", buffer, bufsize)) { + int len = hex2uint16(buffer); + char *p = strstr_P(buffer + 4, PSTR("0: 49 02 01")); + if (p) { + char *q = buffer; + p += 11; // skip the header + do { + while (*(++p) == ' '); + for (;;) { + *(q++) = hex2uint8(p); + while (*p && *p != ' ') p++; + while (*p == ' ') p++; + if (!*p || *p == '\r') break; + } + p = strchr(p, ':'); + } while(p); + *q = 0; + if (q - buffer == len - 3) { + return true; + } + } + } + delay(100); + } return false; } diff --git a/libraries/OBD2UART/OBD2UART.cpp b/libraries/OBD2UART/OBD2UART.cpp index 0cb72f1..76968b9 100644 --- a/libraries/OBD2UART/OBD2UART.cpp +++ b/libraries/OBD2UART/OBD2UART.cpp @@ -9,20 +9,16 @@ //#define DEBUG Serial -#ifdef ESP32 -extern HardwareSerial Serial1; -#endif - uint16_t hex2uint16(const char *p) { char c = *p; uint16_t i = 0; - for (char n = 0; c && n < 4; c = *(++p)) { + for (uint8_t n = 0; c && n < 4; c = *(++p)) { if (c >= 'A' && c <= 'F') { c -= 7; } else if (c>='a' && c<='f') { c -= 39; - } else if (c == ' ') { + } else if (c == ' ' && n == 2) { continue; } else if (c < '0' || c > '9') { break; @@ -44,7 +40,9 @@ byte hex2uint8(const char *p) else if (c1 < '0' || c1 > '9') return 0; - if (c2 >= 'A' && c2 <= 'F') + if (c2 == 0) + return (c1 & 0xf); + else if (c2 >= 'A' && c2 <= 'F') c2 -= 7; else if (c2 >= 'a' && c2 <= 'f') c2 -= 39; @@ -61,24 +59,15 @@ byte hex2uint8(const char *p) byte COBD::sendCommand(const char* cmd, char* buf, byte bufsize, int timeout) { write(cmd); - dataIdleLoop(); + idleTasks(); return receive(buf, bufsize, timeout); } -void COBD::sendQuery(byte pid) +bool COBD::readPID(byte pid, int& result) { char cmd[8]; sprintf(cmd, "%02X%02X\r", dataMode, pid); -#ifdef DEBUG - debugOutput(cmd); -#endif write(cmd); -} - -bool COBD::readPID(byte pid, int& result) -{ - // send a query command - sendQuery(pid); // receive and parse the response return getResult(pid, result); } @@ -107,7 +96,7 @@ byte COBD::readDTC(uint16_t codes[], byte maxCodes) sprintf_P(buffer, n == 0 ? PSTR("03\r") : PSTR("03%02X\r"), n); write(buffer); if (receive(buffer, sizeof(buffer)) > 0) { - if (!strstr(buffer, "NO DATA")) { + if (!strstr_P(buffer, PSTR("NO DATA"))) { char *p = strstr(buffer, "43"); if (p) { while (codesRead < maxCodes && *p) { @@ -300,20 +289,30 @@ float COBD::getVoltage() bool COBD::getVIN(char* buffer, byte bufsize) { - if (sendCommand("0902\r", buffer, bufsize)) { - char *p = strstr(buffer, "0: 49 02"); - if (p) { - char *q = buffer; - p += 10; - do { - for (++p; *p == ' '; p += 3) { - if (*q = hex2uint8(p + 1)) q++; - } - p = strchr(p, ':'); - } while(p); - *q = 0; - return true; - } + for (byte n = 0; n < 5; n++) { + if (sendCommand("0902\r", buffer, bufsize)) { + int len = hex2uint16(buffer); + char *p = strstr_P(buffer + 4, PSTR("0: 49 02 01")); + if (p) { + char *q = buffer; + p += 11; // skip the header + do { + while (*(++p) == ' '); + for (;;) { + *(q++) = hex2uint8(p); + while (*p && *p != ' ') p++; + while (*p == ' ') p++; + if (!*p || *p == '\r') break; + } + p = strchr(p, ':'); + } while(p); + *q = 0; + if (q - buffer == len - 3) { + return true; + } + } + } + delay(100); } return false; } @@ -362,7 +361,7 @@ byte COBD::getVersion() return version; } -byte COBD::receive(char* buffer, byte bufsize, int timeout) +int COBD::receive(char* buffer, int bufsize, unsigned int timeout) { unsigned char n = 0; unsigned long startTime = millis(); @@ -393,7 +392,7 @@ byte COBD::receive(char* buffer, byte bufsize, int timeout) // timeout break; } - dataIdleLoop(); + idleTasks(); } } if (buffer) { @@ -415,48 +414,77 @@ bool COBD::init(OBD_PROTOCOLS protocol) { const char *initcmd[] = {"ATZ\r", "ATE0\r", "ATH0\r"}; char buffer[64]; + byte stage; m_state = OBD_DISCONNECTED; - for (unsigned char i = 0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) { - write(initcmd[i]); - if (receive(buffer, sizeof(buffer), OBD_TIMEOUT_LONG) == 0) { - return false; + + for (byte n = 0; n < 2; n++) { + stage = 0; + if (n != 0) reset(); + for (byte i = 0; i < sizeof(initcmd) / sizeof(initcmd[0]); i++) { + delay(10); + if (!sendCommand(initcmd[i], buffer, sizeof(buffer), OBD_TIMEOUT_SHORT)) { + continue; + } } - } - if (protocol != PROTO_AUTO) { - sprintf_P(buffer, PSTR("ATSP %u\r"), protocol); - write(buffer); - if (receive(buffer, sizeof(buffer), OBD_TIMEOUT_LONG) == 0 && !strstr(buffer, "OK")) { - return false; + stage = 1; + if (protocol != PROTO_AUTO) { + sprintf(buffer, "ATSP%u\r", protocol); + delay(10); + if (!sendCommand(buffer, buffer, sizeof(buffer), OBD_TIMEOUT_SHORT) || !strstr(buffer, "OK")) { + continue; + } } - } - - // load pid map - memset(pidmap, 0, sizeof(pidmap)); - bool success = false; - for (byte i = 0; i < 4; i++) { - byte pid = i * 0x20; - sendQuery(pid); - if (receive(buffer, sizeof(buffer), OBD_TIMEOUT_LONG) > 0) { - char *p = buffer; - while ((p = strstr(p, "41 "))) { - p += 3; - if (hex2uint8(p) == pid) { - p += 2; - for (byte n = 0; n < 4 && *(p + n * 3) == ' '; n++) { - pidmap[i * 4 + n] = hex2uint8(p + n * 3 + 1); + stage = 2; + delay(10); + if (!sendCommand("010D\r", buffer, sizeof(buffer), OBD_TIMEOUT_LONG) || checkErrorMessage(buffer)) { + continue; + } + stage = 3; + // load pid map + memset(pidmap, 0, sizeof(pidmap)); + bool success = false; + for (byte i = 0; i < 4; i++) { + byte pid = i * 0x20; + sprintf(buffer, "%02X%02X\r", dataMode, pid); + delay(10); + write(buffer); + if (receive(buffer, sizeof(buffer), OBD_TIMEOUT_LONG) > 0) { + if (checkErrorMessage(buffer)) { + break; + } + char *p = buffer; + while ((p = strstr(p, "41 "))) { + p += 3; + if (hex2uint8(p) == pid) { + p += 2; + for (byte n = 0; n < 4 && *(p + n * 3) == ' '; n++) { + pidmap[i * 4 + n] = hex2uint8(p + n * 3 + 1); + } + success = true; } - success = true; } + } else { + break; } } + if (success) { + stage = 0xff; + break; + } } - - if (success) { + if (stage == 0xff) { m_state = OBD_CONNECTED; errors = 0; + return true; + } else { +#ifdef DEBUG + Serial.print("Stage:"); + Serial.println(stage); +#endif + reset(); + return false; } - return success; } void COBD::end() @@ -477,10 +505,64 @@ bool COBD::setBaudRate(unsigned long baudrate) return true; } -bool COBD::memsInit() +void COBD::reset() +{ + char buf[32]; + sendCommand("ATR\r", buf, sizeof(buf)); + delay(3000); + sendCommand("ATZ\r", buf, sizeof(buf)); +} + +void COBD::uninit() +{ + char buf[32]; + sendCommand("ATPC\r", buf, sizeof(buf)); +} + +byte COBD::checkErrorMessage(const char* buffer) +{ + const char *errmsg[] = {"UNABLE", "ERROR", "TIMEOUT", "NO DATA"}; + for (byte i = 0; i < sizeof(errmsg) / sizeof(errmsg[0]); i++) { + if (strstr(buffer, errmsg[i])) return i + 1; + } + return 0; +} + +uint8_t COBD::getPercentageValue(char* data) +{ + return (uint16_t)hex2uint8(data) * 100 / 255; +} + +uint16_t COBD::getLargeValue(char* data) +{ + return hex2uint16(data); +} + +uint8_t COBD::getSmallValue(char* data) +{ + return hex2uint8(data); +} + +int16_t COBD::getTemperatureValue(char* data) +{ + return (int)hex2uint8(data) - 40; +} + +bool COBD::memsInit(bool fusion) { char buf[16]; - return sendCommand("ATTEMP\r", buf, sizeof(buf)) > 0 && !strchr(buf, '?'); + if (sendCommand("ATTEMP\r", buf, sizeof(buf)) <= 0 || strchr(buf, '?')) + return false; + if (fusion) { + m_fusion = true; + return sendCommand("ATQU1\r", buf, sizeof(buf)); + } else { + if (m_fusion) { + m_fusion = false; + sendCommand("ATQU0\r", buf, sizeof(buf)); + } + return true; + } } bool COBD::memsRead(int16_t* acc, int16_t* gyr, int16_t* mag, int16_t* temp) @@ -515,6 +597,20 @@ bool COBD::memsRead(int16_t* acc, int16_t* gyr, int16_t* mag, int16_t* temp) } while (0); if (!success) return false; } + if (mag) { + success = false; + if (sendCommand("ATMAG\r", buf, sizeof(buf)) > 0) do { + char* p = getResultValue(buf); + if (!p) break; + mag[0] = atoi(p++); + if (!(p = strchr(p, ','))) break; + mag[1] = atoi(++p); + if (!(p = strchr(p, ','))) break; + mag[2] = atoi(++p); + success = true; + } while (0); + if (!success) return false; + } if (temp) { success = false; if (sendCommand("ATTEMP\r", buf, sizeof(buf)) > 0) { @@ -529,6 +625,23 @@ bool COBD::memsRead(int16_t* acc, int16_t* gyr, int16_t* mag, int16_t* temp) return true; } +bool COBD::memsOrientation(float& yaw, float& pitch, float& roll) +{ + char buf[64]; + bool success = false; + if (sendCommand("ATORI\r", buf, sizeof(buf)) > 0) do { + char* p = getResultValue(buf); + if (!p) break; + yaw = (float)atof(p++); + if (!(p = strchr(p, ','))) break; + pitch = (float)atoi(++p); + if (!(p = strchr(p, ','))) break; + roll = (float) atof(++p); + success = true; + } while (0); + return success; +} + #ifdef DEBUG void COBD::debugOutput(const char *s) { diff --git a/libraries/OBD2UART/OBD2UART.h b/libraries/OBD2UART/OBD2UART.h index 62ac18b..2674274 100644 --- a/libraries/OBD2UART/OBD2UART.h +++ b/libraries/OBD2UART/OBD2UART.h @@ -8,8 +8,7 @@ #include <Arduino.h> #define OBD_TIMEOUT_SHORT 1000 /* ms */ -#define OBD_TIMEOUT_LONG 5000 /* ms */ -#define OBD_TIMEOUT_GPS 200 /* ms */ +#define OBD_TIMEOUT_LONG 10000 /* ms */ #ifndef OBDUART #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168P__) @@ -19,6 +18,10 @@ #endif #endif +#ifdef ESP32 +extern HardwareSerial Serial1; +#endif + // Mode 1 PIDs #define PID_ENGINE_LOAD 0x04 #define PID_COOLANT_TEMP 0x05 @@ -73,23 +76,12 @@ #define PID_ENGINE_REF_TORQUE 0x63 // non-OBD/custom PIDs (no mode number) -#define PID_GPS_LATITUDE 0xA -#define PID_GPS_LONGITUDE 0xB -#define PID_GPS_ALTITUDE 0xC -#define PID_GPS_SPEED 0xD -#define PID_GPS_HEADING 0xE -#define PID_GPS_SAT_COUNT 0xF -#define PID_GPS_TIME 0x10 -#define PID_GPS_DATE 0x11 #define PID_ACC 0x20 #define PID_GYRO 0x21 #define PID_COMPASS 0x22 #define PID_MEMS_TEMP 0x23 #define PID_BATTERY_VOLTAGE 0x24 -// custom PIDs for calculated data -#define PID_TRIP_DISTANCE 0x30 - typedef enum { PROTO_AUTO = 0, PROTO_ISO_9141_2 = 3, @@ -115,13 +107,16 @@ uint8_t hex2uint8(const char *p); class COBD { public: - COBD():dataMode(1),errors(0),m_state(OBD_DISCONNECTED) {} // begin serial UART virtual byte begin(); + // terminate communication channel + virtual void end(); // initialize OBD-II connection virtual bool init(OBD_PROTOCOLS protocol = PROTO_AUTO); + // reset OBD-II connection + virtual void reset(); // un-initialize OBD-II connection - virtual void end(); + virtual void uninit(); // set serial baud rate virtual bool setBaudRate(unsigned long baudrate); // get connection state @@ -144,12 +139,12 @@ public: virtual float getVoltage(); // get VIN as a string, buffer length should be >= OBD_RECV_BUF_SIZE virtual bool getVIN(char* buffer, byte bufsize); - // initialize MEMS sensor - virtual bool memsInit(); + // initialize MEMS sensor (enable or disable sensor fusion by quanterion algorithm) + virtual bool memsInit(bool fusion = false); // read out MEMS data (acc for accelerometer, gyr for gyroscope, temp in 0.1 celcius degree) virtual bool memsRead(int16_t* acc, int16_t* gyr = 0, int16_t* mag = 0, int16_t* temp = 0); - // send query for specified PID - virtual void sendQuery(byte pid); + // get computed orientation values + virtual bool memsOrientation(float& yaw, float& pitch, float& roll); // retrive and parse the response of specifie PID virtual bool getResult(byte& pid, int& result); // determine if the PID is supported @@ -157,37 +152,26 @@ public: // get adapter firmware version virtual byte getVersion(); // set current PID mode - byte dataMode; + byte dataMode = 1; // occurrence of errors - byte errors; + byte errors = 0; // bit map of supported PIDs - byte pidmap[4 * 4]; + byte pidmap[4 * 4] = {0}; protected: virtual char* getResponse(byte& pid, char* buffer, byte bufsize); - virtual byte receive(char* buffer, byte bufsize, int timeout = OBD_TIMEOUT_SHORT); + virtual int receive(char* buffer, int bufsize, unsigned int timeout = OBD_TIMEOUT_SHORT); virtual void write(const char* s); - virtual void dataIdleLoop() {} - void recover(); - void debugOutput(const char* s); - int normalizeData(byte pid, char* data); - OBD_STATES m_state; + virtual uint8_t getPercentageValue(char* data); + virtual uint16_t getLargeValue(char* data); + virtual uint8_t getSmallValue(char* data); + virtual int16_t getTemperatureValue(char* data); + virtual int normalizeData(byte pid, char* data); + virtual byte checkErrorMessage(const char* buffer); + virtual char* getResultValue(char* buf); + OBD_STATES m_state = OBD_DISCONNECTED; private: - virtual uint8_t getPercentageValue(char* data) - { - return (uint16_t)hex2uint8(data) * 100 / 255; - } - virtual uint16_t getLargeValue(char* data) - { - return hex2uint16(data); - } - virtual uint8_t getSmallValue(char* data) - { - return hex2uint8(data); - } - virtual int16_t getTemperatureValue(char* data) - { - return (int)hex2uint8(data) - 40; - } - char* getResultValue(char* buf); + void recover(); + virtual void idleTasks() {} + bool m_fusion = false; }; diff --git a/libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino b/libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino index 9b11eab..4d30b0e 100644 --- a/libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino +++ b/libraries/OBD2UART/examples/obd_uart_test/obd_uart_test.ino @@ -1,25 +1,32 @@ /************************************************************************* -* Testing sketch for Freematics OBD-II UART Adapter +* Testing sketch for Freematics OBD-II UART Adapter V1/V2/V2.1 +* Performs AT command-set test * Reads and prints several OBD-II PIDs value -* Distributed under GPL v2.0 -* Visit http://freematics.com for more information -* Written by Stanley Huang <support@freematics.com.au> +* Reads and prints motion sensor data if available +* Distributed under BSD +* Visit https://freematics.com/products for more product information +* Written by Stanley Huang <stanley@freematics.com.au> *************************************************************************/ -#include <SoftwareSerial.h> #include <OBD2UART.h> -// On Arduino Leonardo, Micro, MEGA or DUE, hardware serial can be used for output -// as OBD-II UART adapter uses to Serial1 -// On Arduino UNO and those have no Serial1, we use software serial for output -// as OBD-II UART adapter uses to Serial +// On Arduino Leonardo, Micro, MEGA or DUE, hardware serial can be used for output as the adapter occupies Serial1 +// On Arduino UNO and those have no Serial1, we use software serial for output as the adapter uses Serial +#ifdef ARDUINO_AVR_UNO +#include <SoftwareSerial.h> SoftwareSerial mySerial(A2, A3); -//#define mySerial Serial +#else +#define mySerial Serial +#endif + +#if defined(ESP32) && !defined(Serial1) +HardwareSerial Serial1(1); +#endif COBD obd; bool hasMEMS; -void testOut() +void testATcommands() { static const char cmds[][6] = {"ATZ\r", "ATI\r", "ATH0\r", "ATRV\r", "0100\r", "010C\r", "0902\r"}; char buf[128]; @@ -93,11 +100,12 @@ void readBatteryVoltage() void readMEMS() { - int acc[3]; - int gyro[3]; - int temp; + int16_t acc[3] = {0}; + int16_t gyro[3] = {0}; + int16_t mag[3] = {0}; + int16_t temp = 0; - if (!obd.memsRead(acc, gyro, 0, &temp)) return; + if (!obd.memsRead(acc, gyro, mag, &temp)) return; mySerial.print('['); mySerial.print(millis()); @@ -117,6 +125,13 @@ void readMEMS() mySerial.print('/'); mySerial.print(gyro[2]); + mySerial.print(" MAG:"); + mySerial.print(mag[0]); + mySerial.print('/'); + mySerial.print(mag[1]); + mySerial.print('/'); + mySerial.print(mag[2]); + mySerial.print(" TEMP:"); mySerial.print((float)temp / 10, 1); mySerial.println("C"); @@ -127,23 +142,24 @@ void setup() mySerial.begin(115200); while (!mySerial); - // this will begin serial - byte version = obd.begin(); - - mySerial.print("Freematics OBD-II Adapter "); - if (version > 0) { - mySerial.print("Ver. "); - mySerial.print(version / 10); - mySerial.print('.'); - mySerial.println(version % 10); - } else { - mySerial.println("not detected"); - for (;;); + for (;;) { + delay(1000); + byte version = obd.begin(); + mySerial.print("Freematics OBD-II Adapter "); + if (version > 0) { + mySerial.println("detected"); + mySerial.print("OBD firmware version "); + mySerial.print(version / 10); + mySerial.print('.'); + mySerial.println(version % 10); + break; + } else { + mySerial.println("not detected"); + } } - delay(1000); // send some commands for testing and show response for debugging purpose - testOut(); + testATcommands(); hasMEMS = obd.memsInit(); mySerial.print("MEMS:"); @@ -151,8 +167,9 @@ void setup() // initialize OBD-II adapter do { - mySerial.println("Init..."); + mySerial.println("Connecting..."); } while (!obd.init()); + mySerial.println("OBD connected!"); char buf[64]; if (obd.getVIN(buf, sizeof(buf))) { @@ -160,7 +177,7 @@ void setup() mySerial.println(buf); } - unsigned int codes[6]; + uint16_t codes[6]; byte dtcCount = obd.readDTC(codes, 6); if (dtcCount == 0) { mySerial.println("No DTC"); @@ -176,7 +193,6 @@ void setup() delay(5000); } - void loop() { readPIDSingle(); @@ -186,3 +202,4 @@ void loop() readMEMS(); } } + diff --git a/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino b/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino new file mode 100644 index 0000000..e04949c --- /dev/null +++ b/libraries/OBD2UART/examples/orientation_demo/orientation_demo.ino @@ -0,0 +1,97 @@ +/************************************************************************* +* Testing sketch for Freematics OBD-II UART Adapter V2.1 +* Reads and prints motion sensor data and computed orientation data +* Distributed under BSD +* Visit https://freematics.com/products for more product information +* Written by Stanley Huang <stanley@freematics.com.au> +*************************************************************************/ + +#include <OBD2UART.h> + +// On Arduino Leonardo, Micro, MEGA or DUE, hardware serial can be used for output as the adapter occupies Serial1 +// On Arduino UNO and those have no Serial1, we use software serial for output as the adapter uses Serial +#ifdef ARDUINO_AVR_UNO +#include <SoftwareSerial.h> +SoftwareSerial mySerial(A2, A3); +#else +#define mySerial Serial +#endif + +#if defined(ESP32) && !defined(Serial1) +HardwareSerial Serial1(1); +#endif + +COBD obd; + +void setup() +{ + mySerial.begin(115200); + while (!mySerial); + + // this will begin serial + + for (;;) { + delay(1000); + byte version = obd.begin(); + mySerial.print("Freematics OBD-II Adapter "); + if (version > 0) { + mySerial.println("detected"); + break; + } else { + mySerial.println("not detected"); + } + } + + // initialize MEMS with sensor fusion enabled + bool hasMEMS = obd.memsInit(true); + mySerial.print("Motion sensor is "); + mySerial.println(hasMEMS ? "present" : "not present"); + if (!hasMEMS) { + for (;;) delay(1000); + } +} + + +void loop() +{ + int16_t acc[3] = {0}; + int16_t gyro[3] = {0}; + int16_t mag[3] = {0}; + + if (!obd.memsRead(acc, gyro, mag)) return; + + mySerial.print("ACC:"); + mySerial.print(acc[0]); + mySerial.print('/'); + mySerial.print(acc[1]); + mySerial.print('/'); + mySerial.print(acc[2]); + + mySerial.print(" GYRO:"); + mySerial.print(gyro[0]); + mySerial.print('/'); + mySerial.print(gyro[1]); + mySerial.print('/'); + mySerial.print(gyro[2]); + + mySerial.print(" MAG:"); + mySerial.print(mag[0]); + mySerial.print('/'); + mySerial.print(mag[1]); + mySerial.print('/'); + mySerial.print(mag[2]); + + mySerial.println(); + + float yaw, pitch, roll; + if (obd.memsOrientation(yaw, pitch, roll)) { + mySerial.print("Orientation: "); + mySerial.print(yaw, 2); + mySerial.print(' '); + mySerial.print(pitch, 2); + mySerial.print(' '); + mySerial.println(roll, 2); + } + + delay(100); +} diff --git a/libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino b/libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino index 3e80ae3..5b7a13e 100644 --- a/libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino +++ b/libraries/OBD2UART/examples/rpm_led_uart/rpm_led_uart.ino @@ -1,8 +1,9 @@ /************************************************************************* -* Sample sketch based on OBD-II library for Arduino -* Distributed under GPL v2.0 -* Visit http://freematics.com for more information -* (C)2012-2014 Stanley Huang <stanleyhuangyc@gmail.com> +* Testing sketch for Freematics OBD-II UART Adapter +* Reads engine RPM data from OBD and triggers Arduino onboard LED +* Distributed under BSD +* Visit https://freematics.com/products for more product information +* Written by Stanley Huang <stanley@freematics.com.au> *************************************************************************/ #include <OBD2UART.h> diff --git a/libraries/OBD2UART/keywords.txt b/libraries/OBD2UART/keywords.txt new file mode 100644 index 0000000..316a4fb --- /dev/null +++ b/libraries/OBD2UART/keywords.txt @@ -0,0 +1,29 @@ +################################################################################ +# Datatypes (KEYWORD1) +################################################################################ +COBD KEYWORD1 + +################################################################################ +# Methods and Functions (KEYWORD2) +################################################################################ +begin KEYWORD2 +end KEYWORD2 +init KEYWORD2 +uninit KEYWORD2 +reset KEYWORD2 + +readPID KEYWORD2 +readDTC KEYWORD2 +clearDTC KEYWORD2 +getVoltage KEYWORD2 +getVIN KEYWORD2 + +memsInit KEYWORD2 +memsRead KEYWORD2 +memsOrientation KEYWORD2 + +################################################################################ +# Constants (LITERAL1) +################################################################################ +OBD_PROTOCOLS LITERAL1 +OBD_STATES LITERAL1
\ No newline at end of file diff --git a/libraries/OBD2UART/library.properties b/libraries/OBD2UART/library.properties new file mode 100644 index 0000000..cbb921d --- /dev/null +++ b/libraries/OBD2UART/library.properties @@ -0,0 +1,9 @@ +name=OBD2UART +version=1.2 +author=Stanley Huang <stanley@freematics.com.au> +maintainer=Stanley Huang <stanley@freematics.com.au> +sentence=Arduino library for Freematics OBD-II UART Adapter +paragraph=Arduino library for Freematics OBD-II UART Adapter +category=Communication +url=https://freematics.com +includes=OBD2UART.h
\ No newline at end of file diff --git a/nanologger/README.txt b/nanologger/README.txt index 6fbb9b5..d381889 100644 --- a/nanologger/README.txt +++ b/nanologger/README.txt @@ -1,10 +1,5 @@ This is the source code for the Arduino OBD-II data logger, which displays (on a 128x64 OLED display module) and records (to a SD card) a selected set of OBD-II data. -The recorded data is stored in CSV format and the file can be illustrated into a graphic chart by a free service at: -http://freematics.com/chart/ - To compile the code with Arduino IDE, please copy all library files from the libraries directory to Arduino's libraries directory. -To open the project file (cbp), please download CodeBlocks Arduino Edition (http://arduinodev.com/codeblocks). - The source code is distributed under GPL license. diff --git a/nanotimer/README.md b/nanotimer/README.md new file mode 100644 index 0000000..2698310 --- /dev/null +++ b/nanotimer/README.md @@ -0,0 +1,3 @@ +This sketch works as a Performance Box. It displays live speed (from OBD-II) of the vehicle and the time used for reaching speed of 60km/h, 100km/h, 200km/h and distance of 400m. Measuring is started automatically (when vehicle starts moving). + +![Freematics Nano Kit running NanoTimer sketch](https://freematics.com/pages/wp-content/uploads/2014/08/DSC04398-1000.jpg) diff --git a/simple_obd_display/simple_obd_display.ino b/simple_obd_display/simple_obd_display.ino new file mode 100644 index 0000000..ca36236 --- /dev/null +++ b/simple_obd_display/simple_obd_display.ino @@ -0,0 +1,105 @@ +/************************************************************************* +* Simple OBD Data Display +* Works with any Arduino board connected with SH1106 128*64 I2C OLED and +* Freematics OBD-II UART Adapter - https://freematics.com/products +* Distributed under public domain +* Written by Stanley Huang <stanley@freematics.com.au> +*************************************************************************/ + +#include <Wire.h> +#include <OBD2UART.h> +#include <MicroLCD.h> + +LCD_SH1106 lcd; +COBD obd; + +void reconnect() +{ + lcd.clear(); + lcd.setFontSize(FONT_SIZE_MEDIUM); + lcd.print("Reconnecting"); + //digitalWrite(SD_CS_PIN, LOW); + for (uint16_t i = 0; !obd.init(); i++) { + if (i == 5) { + lcd.clear(); + } + delay(3000); + } +} + +void showData(byte pid, int value) +{ + switch (pid) { + case PID_RPM: + lcd.setCursor(64, 0); + lcd.setFontSize(FONT_SIZE_XLARGE); + lcd.printInt((unsigned int)value % 10000, 4); + break; + case PID_SPEED: + lcd.setCursor(0, 0); + lcd.setFontSize(FONT_SIZE_XLARGE); + lcd.printInt((unsigned int)value % 1000, 3); + break; + case PID_THROTTLE: + lcd.setCursor(88, 5); + lcd.setFontSize(FONT_SIZE_MEDIUM); + lcd.printInt(value % 100, 3); + lcd.setFontSize(FONT_SIZE_SMALL); + lcd.print(" %"); + break; + case PID_ENGINE_LOAD: + lcd.setCursor(12, 5); + lcd.setFontSize(FONT_SIZE_MEDIUM); + lcd.printInt(value, 3); + lcd.setFontSize(FONT_SIZE_SMALL); + lcd.print(" %"); + break; + } +} + +void initScreen() +{ + lcd.clear(); + lcd.setFontSize(FONT_SIZE_SMALL); + lcd.setCursor(24, 3); + lcd.print("km/h"); + lcd.setCursor(110, 3); + lcd.print("rpm"); + lcd.setCursor(0, 7); + lcd.print("ENGINE LOAD"); + lcd.setCursor(80, 7); + lcd.print("THROTTLE"); +} + +void setup() +{ + lcd.begin(); + lcd.setFontSize(FONT_SIZE_MEDIUM); + lcd.println("OBD DISPLAY"); + + delay(500); + obd.begin(); + + lcd.println(); + lcd.println("Connecting..."); + while (!obd.init()); + initScreen(); +} + +void loop() +{ + static byte pids[]= {PID_RPM, PID_SPEED, PID_ENGINE_LOAD, PID_THROTTLE}; + static byte index = 0; + byte pid = pids[index]; + int value; + // send a query to OBD adapter for specified OBD-II pid + if (obd.readPID(pid, value)) { + showData(pid, value); + } + index = (index + 1) % sizeof(pids); + + if (obd.errors >= 2) { + reconnect(); + setup(); + } +} |