I'm making a tachometer for my car that uses a string of LED's. I have 2 problems.
-
readings are erratic so display junps around. I thought I'd just average several readings but that leads me to the next problem.
-
The LED's are in an array so while reading freq they blink off (every 1/4 sec.) I think the problem is that I'm working with very low frequencies (30 - 200 hz) and it takes too long to wait for the on/off.
If I could multi-task...
I'm using interrupts to time several tasks. I don't understand part of the code (TCCR2A = 0;TIMSK2 |= (1 << OCIE2A); etc). I just copied it and modified it til it did what I wanted.
So this is where I need counsel. Speed it up and make it steady.
When I write code, I first make it work no matter how ugly, then I try to make it more eficient, then I try to make it pretty. I'm in the middle of the process. I still think BASIC so, forgive me. I accept any KIND suggestions on than part too.
Here's the code.
//lightbar LED tach fo VW
//pin 2-5 group
//pins 6-10 bulb
//pin 13 RPM input
//v3 re-work timers and add dimming
unsigned long
PulseTHi,
PulseTLo;
//slightly simpler code, poss. mixed pin order
int Neg[ 21 ] = { 0,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4,5,5,5,5,5 } ;
int Pos[ 21 ] = { 0,6,7,10,8,9,6,7,10,8,9,6,7,10,8,9,6,7,10,8,9};
// if mod positon 3, mod Standby: skip
int
ReadNowTimer = 0,
HiRangeTimer = 0,
MemTimer = 0,
intHold,
intMem,
intPeak = 1; //1 or LED test is LLLOOONNNGG
bool
ReadNowFlag = true,
HiRangeFlag = false,
MemFlag = false,
BlinkFlag=false,
DimFlag=false;
const int SignalPin =11, DimmerPin = 12;
void setup() {
for (int i=1;i<=5;i++){ //see v2 dfor old loop
if (i<5){ //contortion bc numbers repeat
pinMode(Neg[i*5], OUTPUT);
digitalWrite(Neg[i*5], HIGH);
}
pinMode(Pos[i], OUTPUT);
digitalWrite(Pos[i], LOW);
}
pinMode(SignalPin, INPUT_PULLUP); //_PULLUP);
//LED test - turn all on
for (int j = 1;j<75;j++){
for (int i=1;i<21;i++){
FlashLED (Neg[i], Pos[i]);
}
}
// ----- configure Timer 2 to generate a compare-match interrupt every 1mS
noInterrupts(); // disable interrupts
TCCR2A = 0; // clear control registers
TCCR2B = 0;
TCCR2B |= (1 << CS22) | // 16MHz/128=8uS
(1 << CS20) ;
TCNT2 = 0; // clear counter
OCR2A = 125 - 1; // 8uS*125=1mS (allow for clock propagation)
TIMSK2 |= (1 << OCIE2A); // enable output compare interrupt
interrupts(); // enable interrupts
}
void loop()
{
if (ReadNowFlag) {intPeak = ReadSpeed();}
if (intPeak==0) {StandBy();}
do{ // see v2 for old loop
if (BlinkFlag==false){
for(int Cnt=1;Cnt<=intPeak;Cnt++){
FlashLED (Neg[Cnt], Pos[Cnt]);
}
}
else {delay(1);} //give loop something to take up its time
if (MemFlag){ //flash mem light
//int Neg=(intHold-1)/5+GroupStart; //-1)/4+1;
//int Pos=(intHold-1)%5+BulbStart; //1)%4+6;
FlashLED (Neg[intHold], Pos[intHold]);
}
if (HiRangeFlag){ //lite last LED if Hi range
FlashLED (Neg[20], Pos[20]);
}
}while (ReadNowFlag==false); //read every 1/4 sec
}
void FlashLED (int N, int P){
digitalWrite(N, LOW);
digitalWrite(P, HIGH); //this was delay(1), changed to try dimming.
delayMicroseconds(400); //700&100 w 200us delay?
if (intPeak==0){delay(50);} // longer for standby - 2 50 ms, the 40 micros won't matter
digitalWrite(N, HIGH);
digitalWrite(P, LOW);
if (DimFlag){delayMicroseconds(600);}
}
int ReadSpeed(){
int x;
/*
1000RPM=500*4=2000 pulse/min=33.33pulse/sec (hz)
new lay-out oo0oooo0oooo0oooo0oo
1k 1.5 2k 2.5
1k 2 3 4
Lo 1-2.5k, ea LED=100 RPM =3.33hz: start 800 rpm, 27hz
Hi 1-4k, ea LED=200 RPM =6.67hz: start 600 RPM, 53hz // Hi 2-5k, ea LED=200 RPM =6.67hz: start 1600 RPM, 53hz overlap 1600-2700
*/
PulseTHi=pulseIn(SignalPin,HIGH,100000); //rem'd for test
PulseTLo=pulseIn(SignalPin,LOW,100000);
x=1080000/(PulseTHi+PulseTLo);//in hz
if(x<0){x=0;} //elim -1
// fix, 999 RPM truncates to lower rather than round up
if (x !=0) { // 100,10 to do float math w/ int
x=(((x*100)/33)+5)/10; // hz>100rpm (+.5 to rnd up) //x=x/4-1; //in LEDs
if (x>27|| HiRangeFlag) { // if is or was HI
if (x>27) { // if still Hi re-set timer
HiRangeTimer=0;
HiRangeFlag=true;
}
x=x/2-2; //re-scale, RPM>LEDs (-2, LEDs start @600, <------------------------ ****change here to go 2000-5000 scale**** --------------------------
}
else {
x=x-7; //LEDs start @800
if (HiRangeFlag) {
intMem=intMem/2;//-.5; //re-scale if down scaled
}
}
if (x<1) {x=1; BlinkFlag = !BlinkFlag;} // always have at least 1 lit, blink if off scale //toggling flag gives 1/2" blink
else if (x>20) {x=20; BlinkFlag = !BlinkFlag;}
else {
BlinkFlag=false;
if (x<intMem-2){ //2 LEDs less
MemFlag=true;
intHold=intMem;
}
intMem=x;
}
}
ReadNowFlag=false;
DimFlag=digitalRead(DimmerPin);
return x;
}
void StandBy(){
//cylon effect
while (intPeak==0){
for(int Cnt=2;Cnt<=20;Cnt++){ //2,19: skip first/last for better effect
if (Pos[Cnt]!=10){ //skip off set LED for better effect
FlashLED (Neg[Cnt], Pos[Cnt]);
}
}
for(int Cnt=19;Cnt>=1;Cnt--){
if (Pos[Cnt]!=10){
FlashLED (Neg[Cnt], Pos[Cnt]);
}
}
//intPeak=ReadSpeed(); don't need. on timer
}
}
// -------------------------------
// task scheduler (1mS interrupt)
// -------------------------------
ISR(TIMER2_COMPA_vect)
{
// ----- timers
/*
Each timer counts the number of milliseconds since its associated task was
last performed. Each additional task requires another timer and flag.
*/
// ----- task1
ReadNowTimer++;
if (ReadNowTimer > 125 - 1) { // read @ 1/8 sec. (was 250ms
ReadNowTimer = 0;
ReadNowFlag = true;
}
// ----- task2
if (HiRangeFlag){
HiRangeTimer++;
if (HiRangeTimer > 5000 - 1) { // change range
HiRangeTimer = 0;
HiRangeFlag = false;
}
}
// ----- task3
if (MemFlag){
MemTimer++;
if (MemTimer > 1500 - 1) { // Mem lite
MemTimer = 0;
MemFlag = false;
intHold=0;
intMem=0;
}
}
}