Hi, so i have the following issue.
When driving the 7 segment display the tlc takes about a millisecond to change the channels which seems waaay too long, especially since the data sheet of the tlc touts a 30mhz data rate. How did i notice the problem?: Well unless i change the delayMicroseconds(value) line to value = 1000 the number that is displayed on the previous digit is also displayed on the next digit for a short while. Does anybody know why tlc5940 might be so slow to do anything or even how i can fix it?
Code:
< /* Atmega328p based speedometer
written by
updated last:
19.05.21
*/
#include "FRAM.h"
#include "SparkFun_Tlc5940.h"
#include <FastLED.h>
#define NUM_LEDS 23
#define DATA_PIN 8
#include <stdlib.h>
// Define the array of leds
CRGB leds[NUM_LEDS];
FRAM fram;
uint32_t start;
uint32_t stop;
const static uint8_t kmA = 8;
const static uint8_t kmB = 9;
const static uint8_t kmC = 10;
const static uint8_t kmD = 11;
const static uint8_t kmE = 12;
const static uint8_t kmF = 13;
const static uint8_t kmG = 14;
const static uint8_t kmDP = 15;
const static uint8_t kphA = 0;
const static uint8_t kphB = 1;
const static uint8_t kphC = 2;
const static uint8_t kphD = 3;
const static uint8_t kphE = 4;
const static uint8_t kphF = 5;
const static uint8_t kphG = 6;
const static uint8_t kphDP = 7;
const static uint8_t kmPin0 = 0;
const static uint8_t kmPin1 = 1;
const static uint8_t kmPin2 = 4;
const static uint8_t kmPin3 = 5;
const static uint8_t kmPin4 = 6;
const static uint8_t kmPin5 = 7;
const static uint8_t kmPins[6] = {0, 1, 4, 5, 6, 7};
const static uint8_t kphPin0 = A1;
const static uint8_t kphPin1 = A2;
const static uint8_t kphPin2 = A3;
const static uint8_t kphPins[6] = {A1, A2, A3};
const static uint8_t buttonPin = 12;
const static uint8_t pulseInputPin = 2;
const static uint8_t dimPin = A0;
//don't use the next 10 adresses after these
const static uint8_t kmstandAddress = 0x60;
const static uint8_t kmstandAddressBackup = 0x70;
const static uint8_t pulsesAddress = 0x80;
const static uint8_t pulsesAddressBackup = 0x90;
//value from 0 to 4095
int brightness = 4000;
int r = 255;
int g = 255;
int b = 255;
int kph = 0;
int kphString[3];
int kmDigit = 0;
int kphDigit = 0;
int shortpresses = 0;
int longpresses = 0;
uint32_t kmstand = 0;
int kmstandString[6];
uint32_t kmstandBackup = 0;
int pulsecounter = 0;
int pulsesPerKm = 0;
float dimFactor = 0.3;
unsigned long timer = 0;
unsigned long last_timer = 0;
unsigned long debouncer_timer = 0;
unsigned long pressstart = 0;
unsigned long tenPulseTimer = 0;
unsigned long digitTimer = 0;
unsigned long pressTimer = 0;
boolean displaychange = false;
boolean debouncer = false;
boolean pressactivated = false;
boolean longpress = false;
boolean shortpress = false;
boolean calibrationActivated = false;
boolean menuactivated = false;
int t2 = 0;
int t1 = 0;
void display_all(int kphData[3], int kmData[6]) {
/*
kmData[0] = 1;
kmData[1] = 2;
kmData[2] = 3;
kmData[3] = 4;
kmData[4] = 5;
kmData[5] = 6;
kmData[6] = "\0";
kphData[0] = 5;
kphData[1] = 0;
kphData[2] = "\0";*/
if(kphDigit == 0){
t1 = 2;
} else {
t1 = kphDigit - 1;
}
if(kmDigit == 0){
t2 = 5;
} else {
t2 = kmDigit - 1;
}
digitalWrite(kphPins[t1], HIGH);
digitalWrite(kmPins[t2], HIGH);
Tlc.clear();
if (kphData[0] == 0) {
kphData[0] = 99;
if (kphData[1] == 0) {
kphData[1] = 99;
}
}
if (kmData[0] == 0) {
kmData[0] = 99;
if (kmData[1] == 0) {
kmData[1] = 99;
if (kmData[2] == 0) {
kmData[2] = 99;
if (kmData[3] == 0) {
kmData[3] = 99;
if (kmData[4] == 0) {
kmData[4] = 99;
if (kmData[5] == 0) {
kmData[5] = 99;
}
}
}
}
}
}
int value[2];
value[0] = kphData[kphDigit];
value[1] = kmData[kmDigit];
switch (value[0]) {
case 0:
Tlc.set(kphA, brightness);
Tlc.set(kphB, brightness);
Tlc.set(kphC, brightness);
Tlc.set(kphD, brightness);
Tlc.set(kphE, brightness);
Tlc.set(kphF, brightness);
break;
case 1:
Tlc.set(kphB, brightness);
Tlc.set(kphC, brightness);
break;
case 2:
Tlc.set(kphA, brightness);
Tlc.set(kphB, brightness);
Tlc.set(kphG, brightness);
Tlc.set(kphE, brightness);
Tlc.set(kphD, brightness);
break;
case 3:
Tlc.set(kphA, brightness);
Tlc.set(kphB, brightness);
Tlc.set(kphG, brightness);
Tlc.set(kphC, brightness);
Tlc.set(kphD, brightness);
break;
case 4:
Tlc.set(kphC, brightness);
Tlc.set(kphB, brightness);
Tlc.set(kphG, brightness);
Tlc.set(kphF, brightness);
break;
case 5:
Tlc.set(kphA, brightness);
Tlc.set(kphC, brightness);
Tlc.set(kphD, brightness);
Tlc.set(kphG, brightness);
Tlc.set(kphF, brightness);
break;
case 6:
Tlc.set(kphA, brightness);
Tlc.set(kphC, brightness);
Tlc.set(kphD, brightness);
Tlc.set(kphE, brightness);
Tlc.set(kphF, brightness);
Tlc.set(kphG, brightness);
break;
case 7:
Tlc.set(kphA, brightness);
Tlc.set(kphB, brightness);
Tlc.set(kphC, brightness);
break;
case 8:
Tlc.set(kphA, brightness);
Tlc.set(kphB, brightness);
Tlc.set(kphC, brightness);
Tlc.set(kphD, brightness);
Tlc.set(kphE, brightness);
Tlc.set(kphF, brightness);
Tlc.set(kphG, brightness);
break;
case 9:
Tlc.set(kphA, brightness);
Tlc.set(kphB, brightness);
Tlc.set(kphC, brightness);
Tlc.set(kphD, brightness);
Tlc.set(kphF, brightness);
Tlc.set(kphG, brightness);
break;
case 10:
Tlc.set(kphA, brightness);
Tlc.set(kphE, brightness);
Tlc.set(kphD, brightness);
Tlc.set(kphF, brightness);
break;
case 11:
Tlc.set(kphA, brightness);
Tlc.set(kphB, brightness);
Tlc.set(kphC, brightness);
Tlc.set(kphE, brightness);
Tlc.set(kphF, brightness);
Tlc.set(kphG, brightness);
break;
case 12:
Tlc.set(kphF, brightness);
Tlc.set(kphE, brightness);
Tlc.set(kphD, brightness);
break;
}
switch (value[1]) {
case 0:
Tlc.set(kmA, brightness);
Tlc.set(kmB, brightness);
Tlc.set(kmC, brightness);
Tlc.set(kmD, brightness);
Tlc.set(kmE, brightness);
Tlc.set(kmF, brightness);
break;
case 1:
Tlc.set(kmB, brightness);
Tlc.set(kmC, brightness);
break;
case 2:
Tlc.set(kmA, brightness);
Tlc.set(kmB, brightness);
Tlc.set(kmG, brightness);
Tlc.set(kmE, brightness);
Tlc.set(kmD, brightness);
break;
case 3:
Tlc.set(kmA, brightness);
Tlc.set(kmB, brightness);
Tlc.set(kmG, brightness);
Tlc.set(kmC, brightness);
Tlc.set(kmD, brightness);
break;
case 4:
Tlc.set(kmC, brightness);
Tlc.set(kmB, brightness);
Tlc.set(kmG, brightness);
Tlc.set(kmF, brightness);
break;
case 5:
Tlc.set(kmA, brightness);
Tlc.set(kmC, brightness);
Tlc.set(kmD, brightness);
Tlc.set(kmG, brightness);
Tlc.set(kmF, brightness);
break;
case 6:
Tlc.set(kmA, brightness);
Tlc.set(kmC, brightness);
Tlc.set(kmD, brightness);
Tlc.set(kmE, brightness);
Tlc.set(kmF, brightness);
Tlc.set(kmG, brightness);
break;
case 7:
Tlc.set(kmA, brightness);
Tlc.set(kmB, brightness);
Tlc.set(kmC, brightness);
break;
case 8:
Tlc.set(kmA, brightness);
Tlc.set(kmB, brightness);
Tlc.set(kmC, brightness);
Tlc.set(kmD, brightness);
Tlc.set(kmE, brightness);
Tlc.set(kmF, brightness);
Tlc.set(kmG, brightness);
break;
case 9:
Tlc.set(kmA, brightness);
Tlc.set(kmB, brightness);
Tlc.set(kmC, brightness);
Tlc.set(kmD, brightness);
Tlc.set(kmF, brightness);
Tlc.set(kmG, brightness);
break;
}
Tlc.update();
delayMicroseconds(900);
digitalWrite(kphPins[kphDigit], LOW);
digitalWrite(kmPins[kmDigit], LOW);
kphDigit++;
if (kphDigit >= 3) {
kphDigit = 0;
}
kmDigit++;
if (kmDigit >= 6) {
kmDigit = 0;
}
}
void calibrationMode() {
kphString[0] = 10;
kphString[1] = 11;
kphString[2] = 12;
display_all(kphString, kmstandString);
if (longpress) {
pulsesPerKm = pulsecounter;
fram.write16(pulsesAddress, pulsecounter);
fram.write16(pulsesAddressBackup, pulsecounter);
calibrationActivated = false;
}
}
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS); // GRB ordering is assumed
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(0, OUTPUT);
pinMode(1, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
dimFactor = analogRead(dimPin) / 1024;
//start and check fram
Wire.begin();
int rv = fram.begin(0x50);
uint8_t test = fram.read8(0x50);
if (test != 0) {
leds[0] = CRGB::Red;
FastLED.show();
delay(100);
FastLED.clear();
FastLED.show();
}
//read out kmstand from fram
kmstand = fram.read32(kmstandAddress);
//test
if (kmstand == 0) {
kmstand = 123456;
}
kmstandBackup = fram.read32(kmstandAddressBackup);
pulsesPerKm = fram.read16(pulsesAddress);
int temp = fram.read16(pulsesAddressBackup);
//compare normal value to backup value
if (kmstand != kmstandBackup) {
leds[1] = CRGB::Red;
FastLED.show();
delay(100);
FastLED.clear();
FastLED.show();
}
if (temp != pulsesPerKm) {
leds[2] = CRGB::Red;
FastLED.show();
delay(100);
FastLED.clear();
FastLED.show();
}
//Interrupt catches signals from transmission
attachInterrupt(0, pulsedetector, RISING);
//segmentdisplay numbers off
digitalWrite(kmPin0, HIGH);
digitalWrite(kmPin1, HIGH);
digitalWrite(kmPin2, HIGH);
digitalWrite(kmPin3, HIGH);
digitalWrite(kmPin4, HIGH);
digitalWrite(kmPin5, HIGH);
digitalWrite(kphPin0, HIGH);
digitalWrite(kphPin1, HIGH);
digitalWrite(kphPin2, HIGH);
Tlc.init();
//Serial.begin(9600);
//Clearing 7 segment displays
Tlc.clear();
Tlc.update();
//Setting km stand
//Cycling through at leds at beginning
for (int i = 0; i <= 22; i++) {
leds[i].setRGB(r,g,b);;
FastLED.show();
delay(200);
leds[i] = CRGB::Black;
FastLED.show();
}
FastLED.clear();
FastLED.show();
last_timer = millis();
leds[21].setRGB(r,g,b);
leds[22].setRGB(r,g,b);
FastLED.show();
delay(500);
tenPulseTimer = millis();
}
void loop() {
timer = millis();
//check for rollover with millis function
if (last_timer >= timer) {
last_timer = timer;
timer = millis();
}
if ((timer - pressTimer) >= 5000) {
menuactivated = false;
shortpresses = 0;
}
//menu
if (shortpress && !calibrationActivated) {
shortpresses++;
menuactivated = true;
switch (shortpresses) {
case 1:
if (longpress) {
pulsecounter = 0;
longpress = false;
calibrationActivated = true;
}
break;
}
}
//button debouncer
if (debouncer) {
if (debouncer_timer = 0) {
debouncer_timer = timer;
}
if (timer - debouncer_timer > 200) {
debouncer = false;
debouncer_timer = 0;
}
}
//check button presses
if (!debouncer) {
if (digitalRead(buttonPin)) {
if (!pressactivated) {
pressactivated = true;
pressstart = timer;
}
}
if (!digitalRead(buttonPin)) {
if (pressactivated) {
if (timer - pressstart > 2000) {
longpress = true;
} else {
shortpress = true;
}
pressTimer = millis();
}
}
}
//do not change postition of this code!
if (calibrationActivated) {
calibrationMode();
return 0;
}
//read out kph
/*if (pulsecounter == 10) {
unsigned long tenPulseTime = millis() - tenPulseTimer;
tenPulseTimer = millis();
float factor1 = pulsesPerKm / 10;
float tempOneKm = factor1*tenPulseTime;
kph = round(3600000/tempOneKm);*/
kph = 53;
//displaying speed on round bar graph
//int barleds = round(kph / 10);
int barleds = 5;
for (int i = 0; i <= 20; i++) {
leds[i] = CRGB::Black;
}
for (int i = 0; i <= barleds; i++) {
leds[22 - i].setRGB(r,g,b);;
}
//uint8_t temp = 255;
//FastLED.setBrightness(temp);
FastLED.show();
//test
kmstand = 123456;
//displaying kmstand
if (!menuactivated) {
kphString[0] = kph / 100 ;
kphString[1] = (kph % 100) / 10;
kphString[2] = kph % 10;
kmstandString[0] = kmstand / 100000;
kmstandString[1] = (kmstand % 100000) / 10000 ;
kmstandString[2] = (kmstand % 10000) / 1000 ;
kmstandString[3] = (kmstand % 1000) / 100 ;
kmstandString[4] = (kmstand % 100) / 10 ;
kmstandString[5] = kmstand % 10;
display_all(kphString, kmstandString);
}
last_timer = timer;
//check if dimmer is on
//dimFactor = analogRead(dimPin) / 1024;
dimFactor = 0.3;
uint8_t dimFactorInt = round(255*dimFactor);
byte dimFactorByte = dimFactorInt;
//FastLED.setBrightness(dimFactorInt);
r = dimFactorInt;
g = dimFactorInt;
b = dimFactorInt;
//check if kilometre was driven and update
if (pulsecounter > pulsesPerKm) {
kmstand++;
pulsecounter = pulsecounter - pulsesPerKm;
fram.write32(kmstandAddress, kmstand);
fram.write32(kmstandAddressBackup, kmstand);
}
//delay(1);
/*leds[0] = CRGB::Red;
FastLED.show();
delay(200);
leds[0] = CRGB::Black;
FastLED.show();*/
}
//detects and counts incoming pulses from transmission
void pulsedetector() {
pulsecounter++;
} />
Wiring diagramm:
