├── LICENSE ├── README.md ├── canbus_ecu_reader.ino ├── ecu_reader.cpp └── ecu_reader.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Sukkin Pang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | /* CAN Bus ECU Reader 2 | * www.skpang.co.uk 3 | * V1.0 Jan 2017 4 | * 5 | * Uses Teensy CAN-Bus breakout board: 6 | * http://skpang.co.uk/catalog/teensy-canbus-breakout-board-include-teensy-32-p-1507.html 7 | * 8 | * and 128x64 OLED display: 9 | * http://skpang.co.uk/catalog/oled-128x64-display-for-teensy-breakout-board-p-1508.html 10 | * 11 | * Also requres new FlexCAN libarary 12 | * https://github.com/collin80/FlexCAN_Library 13 | * 14 | * Project details and video https://www.skptechnology.co.uk/teensy-canbus-ecu-reader-with-oled-display/ 15 | * / 16 | -------------------------------------------------------------------------------- /canbus_ecu_reader.ino: -------------------------------------------------------------------------------- 1 | /* CAN Bus ECU Reader 2 | * www.skpang.co.uk 3 | * V1.0 Jan 2017 4 | * 5 | * Uses Teensy CAN-Bus breakout board: 6 | * http://skpang.co.uk/catalog/teensy-canbus-breakout-board-include-teensy-32-p-1507.html 7 | * 8 | * and 128x64 OLED display: 9 | * http://skpang.co.uk/catalog/oled-128x64-display-for-teensy-breakout-board-p-1508.html 10 | * 11 | * Also requres new FlexCAN libarary 12 | * https://github.com/collin80/FlexCAN_Library 13 | * 14 | * 15 | */ 16 | #include "ecu_reader.h" 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #define OLED_DC 6 29 | #define OLED_CS 10 30 | #define OLED_RESET 5 31 | Adafruit_SSD1306 display(OLED_DC, OLED_RESET, OLED_CS); 32 | 33 | #if (SSD1306_LCDHEIGHT != 64) 34 | #error("Height incorrect, please fix Adafruit_SSD1306.h!"); 35 | #endif 36 | 37 | ecu_t old_ecu; 38 | 39 | void setup() { 40 | 41 | display.begin(SSD1306_SWITCHCAPVCC); 42 | display.clearDisplay(); 43 | display.setTextSize(0); 44 | display.setTextColor(WHITE); 45 | display.setCursor(0,15); 46 | display.println(" Teensy ECU Reader"); 47 | display.println(" "); 48 | display.println(" skpang.co.uk"); 49 | display.println(" "); 50 | display.println(" 01/17"); 51 | display.display(); 52 | ecu_reader.init(500000); 53 | delay(1000); 54 | Serial.println(F("ECU Reader v1.0 SK Pang 12/16")); 55 | display.clearDisplay(); 56 | 57 | display.setCursor(0,55); 58 | display.println(" kph rpm"); 59 | display.display(); 60 | old_ecu.engine_rpm = -1; 61 | old_ecu.coolant_temp = 0; 62 | old_ecu.vehicle_speed = -1; 63 | old_ecu.throttle_position = -1; 64 | } 65 | 66 | void loop() { 67 | 68 | int engine_data; 69 | 70 | if(ecu_reader.request(ENGINE_RPM,&engine_data) == 1) // Get engine rpm and display on LCD 71 | { 72 | if(engine_data != old_ecu.engine_rpm) 73 | { 74 | display.setFont(&FreeSansBold12pt7b); 75 | Serial.println(engine_data); 76 | display.fillRect(70,30,55,22,BLACK); 77 | if(engine_data < 10) // Make it right justified 78 | { 79 | display.setCursor(111,50); 80 | }else if(engine_data < 100) 81 | { 82 | 83 | display.setCursor(98,50); 84 | }else if(engine_data < 1000) 85 | { 86 | display.setCursor(83,50); 87 | 88 | }else display.setCursor(70,50); 89 | 90 | display.println(engine_data); 91 | display.display(); 92 | old_ecu.engine_rpm = engine_data; 93 | 94 | } 95 | } 96 | delay(10); 97 | 98 | if(ecu_reader.request(ENGINE_COOLANT_TEMP,&engine_data) == 1) 99 | { 100 | if(engine_data != old_ecu.coolant_temp) 101 | { 102 | Serial.println(engine_data);; 103 | display.setFont(); 104 | display.fillRect(0,0,40,10,BLACK); 105 | display.setCursor(0,0); 106 | display.print(engine_data); 107 | display.print((char) 247); // display degress symbol 108 | display.print("C "); 109 | display.display(); 110 | old_ecu.coolant_temp = engine_data; 111 | } 112 | } 113 | delay(10); 114 | 115 | if(ecu_reader.request(VEHICLE_SPEED,&engine_data) == 1) 116 | { 117 | if(engine_data != old_ecu.vehicle_speed) 118 | { 119 | display.setFont(&FreeSansBold12pt7b); 120 | Serial.println(engine_data);; 121 | display.fillRect(13,30,55,22,BLACK); 122 | if(engine_data < 10) // Make it right justified 123 | { 124 | display.setCursor(40,50); 125 | }else if(engine_data < 100) 126 | { 127 | display.setCursor(28,50); 128 | 129 | }else display.setCursor(13,50); 130 | 131 | display.println(engine_data); 132 | display.display(); 133 | old_ecu.vehicle_speed = engine_data; 134 | } 135 | } 136 | delay(10); 137 | 138 | if(ecu_reader.request(THROTTLE,&engine_data) ==1 ) 139 | { 140 | if(engine_data != old_ecu.throttle_position) 141 | { 142 | Serial.println(engine_data); 143 | display.setFont(); 144 | display.fillRect(100,0,20,10,BLACK); 145 | display.setCursor(100,0); 146 | display.print(engine_data); 147 | display.display(); 148 | 149 | old_ecu.throttle_position = engine_data; 150 | } 151 | } 152 | delay(10); 153 | 154 | } 155 | -------------------------------------------------------------------------------- /ecu_reader.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "ecu_reader.h" 5 | #include 6 | 7 | 8 | /* C++ wrapper */ 9 | ecu_reader_class::ecu_reader_class() { 10 | 11 | 12 | } 13 | 14 | uint8_t ecu_reader_class::init(uint32_t baud) { 15 | 16 | Can0.begin(baud); 17 | return 0; 18 | } 19 | 20 | uint8_t ecu_reader_class::request(uint8_t pid, int *engine_data) 21 | { 22 | 23 | CAN_message_t can_MsgRx,can_MsgTx; 24 | 25 | can_MsgTx.buf[0] = 0x02; 26 | can_MsgTx.buf[1] = 0x01; 27 | can_MsgTx.buf[2] = pid; 28 | can_MsgTx.buf[3] = 0; 29 | can_MsgTx.buf[4] = 0; 30 | can_MsgTx.buf[5] = 0; 31 | can_MsgTx.buf[6] = 0; 32 | can_MsgTx.buf[7] = 0; 33 | can_MsgTx.len = 8; 34 | //can_MsgTx.ext = 0; 35 | can_MsgTx.flags.extended = 0; 36 | can_MsgTx.flags.remote = 0; 37 | can_MsgTx.id = PID_REQUEST; 38 | // can_MsgTx.timeout = 500; 39 | Can0.write(can_MsgTx); 40 | 41 | elapsedMillis waiting; // "waiting" starts at zero 42 | 43 | while (waiting < 1000) { //Check for timeout 44 | 45 | if(Can0.read(can_MsgRx)) 46 | { 47 | if((can_MsgRx.id == PID_REPLY) && (can_MsgRx.buf[2] == pid)) 48 | { 49 | switch(can_MsgRx.buf[2]) 50 | { /* Details from http://en.wikipedia.org/wiki/OBD-II_PIDs */ 51 | case ENGINE_RPM: // ((A*256)+B)/4 [RPM] 52 | *engine_data = ((can_MsgRx.buf[3]*256) + can_MsgRx.buf[4])/4; 53 | //sprintf(buffer,"%d ",(int) engine_data); 54 | break; 55 | 56 | case ENGINE_COOLANT_TEMP: // A-40 [degree C] 57 | *engine_data = can_MsgRx.buf[3] - 40; 58 | //sprintf(buffer,"%d degC ",(int) engine_data); 59 | 60 | break; 61 | 62 | case VEHICLE_SPEED: // A [km] 63 | *engine_data = can_MsgRx.buf[3]; 64 | //sprintf(buffer,"%d km ",(int) engine_data); 65 | 66 | break; 67 | 68 | case MAF_SENSOR: // ((256*A)+B) / 100 [g/s] 69 | *engine_data = ((can_MsgRx.buf[3]*256) + can_MsgRx.buf[4])/100; 70 | //sprintf(buffer,"%d g/s",(int) engine_data); 71 | 72 | break; 73 | 74 | case O2_VOLTAGE: // A * 0.005 (B-128) * 100/128 (if B==0xFF, sensor is not used in trim calc) 75 | *engine_data = can_MsgRx.buf[3]*0.005; 76 | //sprintf(buffer,"%d v ",(int) engine_data); 77 | 78 | case THROTTLE: // 79 | *engine_data = int((can_MsgRx.buf[3]*100)/255); 80 | //sprintf(buffer,"%d %% ",(int) engine_data); 81 | 82 | break; 83 | } 84 | return 1; 85 | } 86 | } 87 | 88 | 89 | } // while 90 | return 0; 91 | 92 | } 93 | 94 | ecu_reader_class ecu_reader; 95 | -------------------------------------------------------------------------------- /ecu_reader.h: -------------------------------------------------------------------------------- 1 | #ifndef ecu_reader_h 2 | #define ecu_reader_h 3 | 4 | #include 5 | /* Details from http://en.wikipedia.org/wiki/OBD-II_PIDs */ 6 | #define MODE1 0x01 //Show current data 7 | #define MODE2 0x02 //Show freeze frame data 8 | #define MODE3 0x03 //Show stored Diagnostic Trouble Codes 9 | #define MODE4 0x04 //Clear Diagnostic Trouble Codes and stored values 10 | 11 | #define PID_SUPPORTED 0x00 12 | #define MONITOR_STATUS 0x01 13 | #define ENGINE_COOLANT_TEMP 0x05 14 | #define ENGINE_RPM 0x0C 15 | #define VEHICLE_SPEED 0x0D 16 | #define MAF_SENSOR 0x10 17 | #define THROTTLE 0x11 18 | #define O2_VOLTAGE 0x14 19 | 20 | #define MODE1_RESPONSE 0x41 21 | #define MODE3_RESPONSE 0x43 22 | #define MODE4_RESPONSE 0x44 23 | #define PID_REQUEST 0x7DF 24 | #define PID_REPLY 0x7E8 25 | 26 | 27 | typedef struct{ 28 | 29 | int coolant_temp; 30 | int engine_rpm; 31 | int throttle_position; 32 | int vehicle_speed; 33 | int maf_airflow; 34 | int o2_voltage; 35 | int dtc; 36 | 37 | }ecu_t; 38 | 39 | extern ecu_t old_ecu; 40 | 41 | class ecu_reader_class 42 | { 43 | public: 44 | 45 | ecu_reader_class(); 46 | uint8_t init(uint32_t baud); 47 | uint8_t request(unsigned char pid, int *engine_data); 48 | private: 49 | 50 | }; 51 | extern ecu_reader_class ecu_reader; 52 | 53 | 54 | #endif 55 | 56 | --------------------------------------------------------------------------------