Created
October 11, 2016 23:26
-
-
Save macchina/fc4bdfe5ecce844d2a79a3dc7fdebd43 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Heavily modified from below code - works with NEOPIXEL 24 pos ring and M2 hardware. | |
Program Name: blueShift | |
Version: v0.7 | |
Author: Pete Mills | |
Website: petemills.blogspot.com | |
Email: mills.pete@gmail.com | |
License: CC BY-NC-SA 3.0 ( Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported ) | |
Description: | |
This program intends to read automotive engine parameters over a bluetooth connection from a Ford OpenXC VI. | |
This OpenXC VI is called an API to OBDII Data, where parameters such as engine speed, gearbox position &c are sent. | |
This program parses these bluetooth serial data and displays them on an array or arrangement of individually | |
addressable RGB LED's ( WS2812 ). | |
Presently RPM is displayed in a radial pattern, increasing clockwise. | |
Bugs/ToDo: | |
investigate proper json parsing | |
exit btWaitThrobber( ) when a connection is made, not a timeout | |
display dimming based on headlamp Status message only occurs after an RPM "redraw" of the display - resolved with a kludge | |
during power-on the transition from btWaitThrobber() to normal run causes all of the LEDs to go off - resolved | |
make the last led "sticky" for a time period such as a "tell tale" or peak hold indicator - implemented | |
make the ring draw operation a function - implemented | |
make the last LED Red - implemented | |
delete functions used for grid display, will use them for later versions of blueShift - complete | |
add hysteresis to the RPM display - not really necessary after using the blueShift | |
*/ | |
#include <OBD2.h> | |
#include <DueTimer.h> | |
#include "SamNonDuePin.h" | |
//******************************************** INCLUDES *********************************************// | |
#include <Adafruit_NeoPixel.h> // https://github.com/adafruit/Adafruit_NeoPixel | |
//******************************************** INCLUDES *********************************************// | |
//create the CANport acqisition schedulers | |
cAcquireCAN CANport0(CAN_PORT_0); | |
/***** DEFINITIONS FOR OBD MESSAGES ON CAN PORT 0, see https://en.wikipedia.org/wiki/OBD-II_PIDs to add your own ***************/ | |
//char _name[10], char _units[10], OBD_PID pid, uint8_t OBD_PID_SIZE size, bool _signed, OBD_MODE_REQ mode, float32 slope, float32 offset, cAcquireCAN *, extended ID; | |
cOBDParameter OBD_Speed( "Speed " , " KPH" , SPEED , _8BITS, false, CURRENT, 1, 0, &CANport0, false); | |
cOBDParameter OBD_EngineSpeed("Engine Speed " , " RPM" , ENGINE_RPM , _16BITS, false, CURRENT, 0.25, 0, &CANport0, false); | |
cOBDParameter OBD_Throttle( "Throttle " , " %" , THROTTLE_POS, _8BITS, false, CURRENT, 0.3922, 0, &CANport0, false); | |
cOBDParameter OBD_Coolant( "Coolant " , " C" , COOLANT_TEMP, _8BITS, false , CURRENT, 1, -40, &CANport0, false); | |
cOBDParameter OBD_EngineLoad( "Load " , " %" , ENGINE_LOAD , _8BITS, false, CURRENT, 0.3922, 0, &CANport0, false); | |
cOBDParameter OBD_MAF( "MAF " , " grams/s" , ENGINE_MAF , _16BITS, false, CURRENT, 0.01, 0, &CANport0, false); | |
cOBDParameter OBD_IAT( "IAT " , " C" , ENGINE_IAT , _8BITS, false , CURRENT, 1, -40, &CANport0, false); | |
//******************************************* DEFINITIONS *******************************************// | |
#define RINGPIN 14 | |
//******************************************* DEFINITIONS *******************************************// | |
//***************************************** GLOBAL VARIABLES ****************************************// | |
uint8_t previousBrightness = 0; // typical operation display brightness | |
uint8_t currentBrightness = 255; // typical operation diaplay brightness | |
uint8_t daytimeBrightness = 255; // brightness for when headlampStatus is TRUE | |
uint8_t nighttimeBrightness = 127; // brightness for when headlampStatus is FALSE | |
uint8_t numberOfRingLED = 24; // total number of LED's in the ring display | |
Adafruit_NeoPixel ring = Adafruit_NeoPixel(numberOfRingLED, RINGPIN, NEO_RGBW + NEO_KHZ800); // an instance for the LED ring display | |
int engineSpeed = 0; | |
String headlampStatusString = ""; // contains "t" if headlamps are on, "f" if they are off | |
String curHeadlampStatus = ""; // to detect changes in state | |
String prevHeadlampStatus = ""; | |
int newEngineSpeedData = 0; | |
int newHeadlampStatusData = 0; | |
int RPM = 0; | |
int minRPM = 500; // RPM where the first LED will light | |
int maxRPM = 4000; // RPM where the last LED will light | |
int LEDsForRPM = numberOfRingLED; // the number of LED's used for RPM display - it could be less than the max if you like | |
int peakHoldLedPos = 0; // position of the sticky LED | |
int peakHoldTime = 3000; // number of milliseconds to keep the peak rpm lit up for | |
long peakHoldStartMs = 0; // the millis() value when setting the sticky LED | |
// we dont need to redraw the display if it is the same as the last time | |
int RPMpreviousNumLED = 0; // the number of RPM LED previously lit up | |
int RPMcurrentNumLED = 0; // the current number of RPM LED lit up | |
float incrementRPM = ( maxRPM - minRPM ) / LEDsForRPM; | |
String stringToParse; | |
int btConnection = 0; //1 = connected | |
long prevMillis = 0; // for the sticky LED | |
long myMillis = 0; | |
//******************************************* FUNCTIONS *********************************************// | |
#define Serial SerialUSB | |
const int LOWPOW = PIN_EMAC_ERX0; | |
void setup() { | |
pinModeNonDue(LOWPOW, OUTPUT); | |
digitalWriteNonDue(LOWPOW, HIGH); | |
pinMode(28, OUTPUT); | |
digitalWrite(28, LOW); | |
// pin directions | |
// pinMode( RINGPIN, OUTPUT ); | |
// pinMode( BTPOWER, OUTPUT ); | |
// setup for the ring display | |
ring.begin(); | |
ring.show(); // Initialize all pixels to 'off' | |
ring.setBrightness(25); // 0::255 | |
//set up the transmission/reception of messages to occur at 500Hz (2mS) timer interrupt | |
Timer3.attachInterrupt(PrintScreen).setFrequency(1).start(); | |
//start CAN ports, enable interrupts and RX masks, set the baud rate here | |
CANport0.initialize(_500K); | |
} | |
UINT8 i; | |
UINT32 maxTime; | |
void drawRing( void ) { | |
// if there is valid data then we should update the display. | |
if ( newEngineSpeedData == 1 ) { | |
// turn everything off | |
for ( int i = 0; i < numberOfRingLED; i++ ) { | |
ring.setPixelColor( i, 0, 0, 0 ); | |
} | |
// calculate the number of LEDs to light up | |
RPMcurrentNumLED = ( engineSpeed - minRPM ) / incrementRPM; // round the number of LEDs to light to the lowest integer | |
// prepare to turn them on, if the new number of LED to light is different than the old number to light | |
if ( RPMcurrentNumLED != RPMpreviousNumLED ) { | |
// set all LEDs to light to green to start | |
for ( int i = 0; i < RPMcurrentNumLED; i++ ) { | |
ring.setPixelColor( i, currentBrightness, 0, 0 ); // green | |
} | |
// if the RPM is high, set some intermediary yellows | |
if ( RPMcurrentNumLED >= ( LEDsForRPM - 7 ) ) { | |
for ( int i = ( LEDsForRPM - 7 ); i < RPMcurrentNumLED; i++ ) { | |
ring.setPixelColor( i, currentBrightness, currentBrightness, 0 ); // yellow | |
} | |
} | |
// if the RPM is really high, set the last 4 LED's red | |
if ( RPMcurrentNumLED >= ( LEDsForRPM - 4 ) ) { | |
for ( int i = ( LEDsForRPM - 4 ); i < RPMcurrentNumLED; i++ ) { | |
ring.setPixelColor( i, 0, currentBrightness, 0 ); // red | |
} | |
} | |
// also, I want whichever the highest LED that is currently on to be red, like a pointer | |
// this is probably redundant with the sticky led? | |
ring.setPixelColor( ( RPMcurrentNumLED - 1 ), currentBrightness, 0, 0 ); // red | |
// now figure out the sticky led | |
// if the current RPM LED is higher than the current sticky led position | |
// this continues in the main loop | |
if ( RPMcurrentNumLED > peakHoldLedPos ) { | |
peakHoldLedPos = RPMcurrentNumLED; // set the current value as the peak | |
peakHoldStartMs = millis(); // record the start time of the new peak | |
} | |
// if the sticky led has been lit for too long | |
if ( millis() - peakHoldStartMs > peakHoldTime ) { | |
peakHoldLedPos = RPMcurrentNumLED; // set the current value as the peak | |
peakHoldStartMs = millis(); // record the start time of the new peak | |
} | |
// I also think the sticky LED should be reset if the RPM begins increasing, | |
// but not if the RPM is steady state or decreasing. | |
if ( RPMcurrentNumLED > RPMpreviousNumLED ) { | |
peakHoldLedPos = RPMcurrentNumLED; // set the current value as the peak | |
peakHoldStartMs = millis(); // record the start time of the new peak | |
} | |
// and finally, set the position of the sticky LED | |
ring.setPixelColor( ( peakHoldLedPos - 1 ), currentBrightness, 0, 0 ); // red | |
ring.show(); // show the new LED display | |
RPMpreviousNumLED = RPMcurrentNumLED; | |
} | |
} | |
} | |
void clearRing( void ) { | |
for ( int i = 0; i < numberOfRingLED; i++ ) { | |
ring.setPixelColor( i, 0 ); | |
} | |
} | |
void loop() { | |
CANport0.run(TIMER_2mS); | |
// if (newEngineSpeedData == 1) { | |
engineSpeed = (OBD_EngineSpeed.getData()); | |
Serial.println (engineSpeed); | |
// engineSpeed = RPM; | |
drawRing(); | |
} | |
void PrintScreen() | |
{ | |
newEngineSpeedData = 1; // force a redraw of the ring to occur | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment