Building a display for my car based on open source shift light code by Chippernut https://github.com/chippernut .
It has a tachometer with a 4 digital RPM readout and sequential shift light that flashes once a certain RPM is reached.
Started adding features to customise the code for my application but having trouble with the 4 digit RPM reading freezing (you can see it get stuck on 6xxx in the video) after flashing the shift lights as it turns off each of the 25 LEDs. Any idea if this a processing speed issue or a coding issue?
The 14 segment ht16k33 display I added is using backpack over I2C.
The addressable LED strips are dotstar SK9822 (APA102 clone).
Running on an Arduino nano with a second nano sending out a dummy RPM pulse for bench testing.
I was planning on (probably overkill) moving to a Teensy as I add more to features but wanted to get some advice on this in its current state first.
There is a lot of code but this is the bit where the meat is:
```
if (rpm > 0 ){
//START - CHANGE ADD. ht16k33 14 seg//
void showValue(int rpm); {
rpm = constrain(rpm, 0, 9999);
char text[5]; // room for 4 characters plus the terminating '\0'
snprintf(text, sizeof text, "%4d", rpm);
for (uint8_t i = 0; i < 4; i++) {
disp.writeDigitAscii(i, text[i]);
}
disp.writeDisplay();
}
//END - CHANGE ADD. ht16k33 14 seg//
if(DEBUG){Serial.println(rpm); }
if (digitalRead(dimPin) != dimmer){
dimmer = digitalRead(dimPin);
loadallcolors();
if (digitalRead(dimPin) == dimmerlogic){
display.setBrightness(dimval);
disp.setBrightness(ht16k33Dim);//CHANGE ADD. ht16k33 14 seg
}else{
display.setBrightness(brightval);
disp.setBrightness(ht16k33Bright);//CHANGE ADD. ht16k33 14 seg
}
}
} else {
display.setColon(false);
SEG_WRITE[0] = (SEG_G); // -
SEG_WRITE[1] = (SEG_G); // -
SEG_WRITE[2] = (SEG_G); // -
SEG_WRITE[3] = (SEG_G); // -
display.setSegments(SEG_WRITE);
//START - CHANGE ADD. ht16k33 14 seg//
disp.clear(); // Clear the display buffer
disp.writeDigitRaw(0,0b0000000011000000); // Set '—' on the first digit
disp.writeDigitRaw(1,0b0000000011000000); // Set '—' on the second digit
disp.writeDigitRaw(2,0b0000000011000000); // Set '—' on the third digit
disp.writeDigitRaw(3,0b0000000011000000); // Set '—' on the fourth digit
disp.writeDisplay(); // Send buffer to the display
//END - CHANGE ADD. ht16k33 14 seg//
}
if (rpm > highRpmMem) {highRpmMem = rpm;} //CHANGE/ADD this saves the highest RPM
if (rpm < shift_rpm){
digitalWrite (shiftSwitchPin, LOW);
if (shiftStat==true){
for(int i=0; i<TOTALNUMPIXELS; i++) { //CHANGE/ADD
strip.setPixelColor(i, strip.Color(0, 0, 0));
strip.show();
shiftStat = false;//CHANGE/ADD put status change here//CHANGE/ADD
}
}
for (a = 0; a<NUMPIXELS; a++){
if (rpm>rpmtable[a][0]){
switch (rpmtable[a][1]){
case 1:
strip.setPixelColor(a,color1);
break;
case 2:
strip.setPixelColor(a,color2);
break;
case 3:
strip.setPixelColor(a,color3);
break;
}
} else {
strip.setPixelColor(a, strip.Color(0, 0, 0));
}
}
} else {
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > shiftinterval) {
previousMillis = currentMillis;
flashbool = !flashbool;
if (flashbool == true)
for(int i=0; i<TOTALNUMPIXELS; i++) { //CHANGE/ADD
strip.setPixelColor(i, flclr1);
}
else
for(int i=0; i<TOTALNUMPIXELS; i++) { //CHANGE/ADD
strip.setPixelColor(i, flclr2);
}
}
shiftStat = true ;//CHANGE/ADD put status change here
if (shiftSwitchOn == true){
if (shiftSwitchEngauge = true) {digitalWrite (shiftSwitchPin, HIGH);Serial.println("Switch is on"); }
}
}
```
And here is the full (and still quite messy) draft:
Actually I can't post the whole code as it's over the post character limit... Is there another way I can share it here?
Here's the start of the code with the libraries used and the setup:
```
include <Adafruit_DotStar.h>
include <EEPROM.h>
include <EEPROMAnything.h>
include "SSD1306Ascii.h"
include "SSD1306AsciiSoftSpi.h"
include <TM1637Display.h>//CHANGE/ADD. V2 display returns
//ht16k33 14 seg//
include <Wire.h>//CHANGE/ADD. for ht16k33
include <Adafruit_GFX.h>//CHANGE/ADD. for ht16k33
include "Adafruit_LEDBackpackEDIT.h"//CHANGE/ADD. for ht16k33
define DISPLAY_ADDRESS 0x70//CHANGE/ADD. for ht16k33
Adafruit_AlphaNum4 disp = Adafruit_AlphaNum4();//CHANGE/ADD. for ht16k33
int string_pointer = 0;//CHANGE/ADD. for ht16k33
char display_buffer[4];//CHANGE/ADD. for ht16k33
long last_display_refresh = 0L;//CHANGE/ADD. for ht16k33
int ht16k33Bright;//CHANGE/ADD. for ht16k33
int ht16k33Dim;//CHANGE/ADD. for ht16k33
void(* resetFunc) (void) = 0;
int DEBUG;
int NUMPIXELS = 20;
int EXTRANUMPIXELS;//CHANGHE/ADD
int TOTALNUMPIXELS;//CHANGE/ADD
bool shiftStat = false;
define DATAPIN 4 //DIFFERENT TO SCHEMATIC!!!CHANGE/ADD
define CLOCKPIN 5 //DIFFERENT TO SCHEMATIC!!!CHANGE/ADD
Adafruit_DotStar strip = Adafruit_DotStar(EEPROM.read(11)+ EEPROM.read(32), DATAPIN, CLOCKPIN, DOTSTAR_BGR);
const int rpmPin = 2; //CHANGE/ADD. There is no mention of pin 8 which is in the schematic? Looks like old senseoption which used <FreqMeasure.h>
//CHANGE/ADD V2 had ledPin = 13 here
const int dimPin = A2;
const int sensorInterrupt = 0;
const int timeoutValue = 10;
volatile unsigned long lastPulseTime;
volatile unsigned long interval = 0;
volatile int timeoutCounter;
long rpm;
long rpm_last;
int display_rpm;//CHANGE/ADDthis is new for V3
int activation_rpm;
int shift_rpm;
int highRpmMem = 0;//CHANGE/ADD
int menu_enter = 0;
int current_seg_number = 1;
int seg_mover = 0;
long previousMillis = 0;
int shiftinterval = 50;
boolean flashbool = true;
int prev_animation;
int prev_color;
boolean testbright = false;
int prev_variable;
int prev_menu;
boolean testdim = false;
int justfixed; //CHANGE/ADD this is new for V3
//array for rpm averaging, filtering comparison
const int numReadings = 5;
int rpmarray[numReadings];
int index = 0; // the index of the current reading
long total = 0; // the running total
long average = 0; // the average
//These are stored memory variables for adjusting the (5) colors, activation rpm, shift rpm, brightness
//Stored in EEPROM Memory
int c1;
int c2;
int c3;
int c4;
int c5;
int brightval; //7-seg brightness
int dimval; //7-seg dim brightness
int sb; //strip brightness
int dimsb; // strip dim brightness
boolean dimmer = false;
boolean dimmerlogic = false;
int pixelanim=1;
int smoothing;
int rpmscaler;
int shift_rpm1; // USED TO BE A LONG!!
int shift_rpm2;
int shift_rpm3;
int shift_rpm4;
int seg1_start = 1;
int seg1_end = 1;
int seg2_end = 2;
int seg3_end = 3;
int activation_rpm1;
int activation_rpm2;
int activation_rpm3;
int activation_rpm4;
int a; //CHANGE/ADD this is new for V3
//new code bellow//
//int buzzerPin 7;//CHANGE/ADD
int shiftSwitchPin = 10;//CHANGE/ADD
//int otherSwitchPin 9;//CHANGE/ADD
bool shiftSwitchEngauge = false;//CHANGE/ADD
int shiftSwitchOn;//Store in EEPROM. CHANGE ADD
//bool otherSwitchSet = false;//CHANGE/ADD
int rst = 0;
int cal;
int prev_cal;
// COLOR VARIABLES - for use w/ the strips and translated into 255 RGB colors
long color1;
long color2;
long color3;
long flclr1;
long flclr2;//CHANGE/ADD. From V2
//Creates a 32 wide table for our pixel animations
int rpmtable[32][2];
// ROTARY ENCODER VARIABLES
int button_pin = A0; //CHANGE/ADD
int menuvar;
int val;
int rotaryval = 0;
// CONFIGURATION FOR 7-SEG DISPLAY//CHANGE/ADD
define CLK 12
define DIO 11
TM1637Display display(CLK, DIO);
uint8_t SEG_WRITE[] = { // [=] EXIT
SEG_A | SEG_F| SEG_E | SEG_D,
SEG_A | SEG_D,
SEG_A | SEG_D,
SEG_A | SEG_D | SEG_B | SEG_C
};
// A
// ---
// F | | B
// -G-
// E | | C
// ---
// D
// CONFIGURATION FOR OLED DISPLAY
//SSD1306AsciiSoftSpi oled;//CHANGE/ADD. Delete this for TM1637 support
//#define OLED_DC 7
//#define OLED_CS 6
//#define OLED_CLK 10
//#define OLED_DATA 9
// CONFIGURATION FOR THE ROTARY ENCODER
// Arduino pins the encoder is attached to. Attach the center to ground.
#define ROTARY_PIN1 A1//CHANGE/ADD
#define ROTARY_PIN2 A3//CHANGE//ADD
// Use the full-step state table (emits a code at 00 only) //CHANGE/ADD. What is this?
const char ttable[7][4] = {
{0x0, 0x2, 0x4, 0x0}, {0x3, 0x0, 0x1, 0x40},
{0x3, 0x2, 0x0, 0x0}, {0x3, 0x2, 0x1, 0x0},
{0x6, 0x0, 0x4, 0x0}, {0x6, 0x5, 0x0, 0x80},
{0x6, 0x5, 0x4, 0x0},
};
volatile unsigned char state = 0;
char rotary_process() {
char pinstate = (digitalRead(ROTARY_PIN2) << 1) | digitalRead(ROTARY_PIN1);
state = ttable[state & 0xf][pinstate];
return (state & 0xc0);
}
/*************
* SETUP *
*************/
//SETUP TO CONFIGURE THE ARDUINO AND GET IT READY FOR FIRST RUN
void setup() {
//get stored variables
getEEPROM();
check_first_run();
if(DEBUG){
Serial.begin(57600);
Serial.println("ChipperNut ShiftLight Project. V2 or V3");
Serial.println("Prepare for awesome......");
}
for (int thisReading = 0; thisReading < numReadings; thisReading++){
rpmarray[thisReading] = 0;
}
timeoutCounter = timeoutValue;
buildarrays();
strip.begin();
strip.clear(); //CHANGE/ADD. Added in V3
strip.show(); // Initialize all pixels to 'off'
//ROTARY ENCODER
pinMode(rpmPin, INPUT);
pinMode(dimPin, INPUT_PULLUP);
pinMode(button_pin, INPUT_PULLUP);
pinMode(ROTARY_PIN1, INPUT_PULLUP);
pinMode(ROTARY_PIN2, INPUT_PULLUP);
//pinMode(buzzerPin, OUTPUT);//CHANGE/ADD
pinMode(shiftSwitchPin, OUTPUT);//CHANGE//ADD
//pinMode(otherSwitchPin, OUTPUT);//CHANGE//ADD
attachInterrupt(0, sensorIsr, RISING);
loadallcolors();
//oled.begin(&Adafruit128x64, OLED_CS, OLED_DC, OLED_CLK, OLED_DATA);//CHANGE/ADD. Delete this for TM1637 support
//oled.clear();
//oled.setFont(chippernut);
//oled.print("c");
//bootanimation();
//delay(1000);
//oled.clear();
//ht16k33 14 seg//
disp.begin(DISPLAY_ADDRESS);//CHANGE/ADD. for ht16k33
disp.clear();//CHANGE/ADD. for ht16k33
disp.writeDisplay();//CHANGE/ADD. for ht16k33
if(DEBUG){Serial.println("LOADED.");}
if (digitalRead(dimPin) == dimmerlogic){
display.setBrightness(dimval);
disp.setBrightness(ht16k33Dim);//CHANGE/ADD. for ht16k33
}
else{
display.setBrightness(brightval);
disp.setBrightness(ht16k33Bright);//CHANGE/ADD. for ht16k33
}
//Sets the total number of usable leds
TOTALNUMPIXELS = NUMPIXELS+EXTRANUMPIXELS;//CHANGE/ADD
//CHANGE/ADD. Shift lights not working?
disp.clear(); // Clear the display buffer
disp.writeDigitAscii(0, 'H'); // Set 'H' on the first digit
disp.writeDigitAscii(1, 'E'); // Set 'E' on the second digit
disp.writeDigitAscii(2, 'L'); // Set 'L' on the third digit
disp.writeDigitAscii(3, 'P'); // Set 'P' on the fourth digit
disp.writeDisplay(); // Send buffer to the display
display.setColon(false);
//SEG_WRITE[0] = (SEG_G); //-
//SEG_WRITE[1] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G); //g
//SEG_WRITE[2] = (SEG_A | SEG_D | SEG_E | SEG_F | SEG_G); //E
//SEG_WRITE[3] = (SEG_D | SEG_E | SEG_F | SEG_G); //t
//display.setSegments(SEG_WRITE);
//delay(600);
//display.setColon(false);
//SEG_WRITE[0] = (SEG_G); //-
//SEG_WRITE[1] = (SEG_A | SEG_C | SEG_D | SEG_F | SEG_G); //S
//SEG_WRITE[2] = (SEG_A | SEG_D | SEG_E | SEG_F | SEG_G); //E
//SEG_WRITE[3] = (SEG_D | SEG_E | SEG_F | SEG_G); //t
//display.setSegments(SEG_WRITE);
//delay(600);
//display.setColon(false);
SEG_WRITE[0] = (SEG_G); //-
SEG_WRITE[1] = (SEG_G); //-
SEG_WRITE[2] = (SEG_G); //-
SEG_WRITE[3] = (SEG_G); //-
display.setSegments(SEG_WRITE);
delay(400);
display.setColon(false);
SEG_WRITE[0] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F); //O
SEG_WRITE[1] = (SEG_G); //-
SEG_WRITE[2] = (SEG_G); //-
SEG_WRITE[3] = (SEG_G); //-
display.setSegments(SEG_WRITE);
delay(200);
display.setColon(false);
SEG_WRITE[0] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G); //g
SEG_WRITE[1] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F); //O
SEG_WRITE[2] = (SEG_G); //-
SEG_WRITE[3] = (SEG_G); //-
display.setSegments(SEG_WRITE);
delay(200);
display.setColon(false);
SEG_WRITE[0] = (SEG_G); //-
SEG_WRITE[1] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G); //g
SEG_WRITE[2] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F); //O
SEG_WRITE[3] = (SEG_G); //-
display.setSegments(SEG_WRITE);
delay(200);
display.setColon(false);
SEG_WRITE[0] = (SEG_G); //-
SEG_WRITE[1] = (SEG_G); //-
SEG_WRITE[2] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G); //g
SEG_WRITE[3] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F); //O
display.setSegments(SEG_WRITE);
delay(200);
display.setColon(false);
SEG_WRITE[0] = (SEG_G); //-
SEG_WRITE[1] = (SEG_G); //-
SEG_WRITE[2] = (SEG_G); //-
SEG_WRITE[3] = (SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G); //g
display.setSegments(SEG_WRITE);
delay(200);
display.setColon(false);
SEG_WRITE[0] = (SEG_G); //-
SEG_WRITE[1] = (SEG_G); //-
SEG_WRITE[2] = (SEG_G); //-
SEG_WRITE[3] = (SEG_G); //-
display.setSegments(SEG_WRITE);
delay(200);
}
```