dimming LED matrix

I'm not exactly a newbie, but I'm probably a dumbie. I've searched but can't find the hint I need to get this rolling. I thot I had it a couple of times but . . .

I made an LED tachometer for my car. It's a 4x5 matrix but its linear, not square. Everything works fine, but I realized that at night it's going to blind me. I was going to just make the 4 side PWM and the 5 side digital HIGH/LOW. Seems logical to me. A goes 50% PWM and 1 to 5 cycle HIGH/LOW. Since it's a diode it won't backflow on the opposite side of the wave. Couldn't make it work and then I read that it doesn't work.

I've tried reducing the on time but that didn't seem to work. Increasing the off time makes it flicker.

The problem is, at my level, I never know if it can't be done, or if I just don't know how to do it. Anybody want to point me north?

Post your code and, probably, your circuit.

Here's the circuit. I'm a little hesitant to post code. I can't remember the secret handshake and if you do it wrong somebody yells at you.

It's a nested loop with PWM pins 3 9 10 11 in outer loop and 4-8 in inner. I pinmoded 4-8.

Untitled.jpg

bwaii:
I'm a little hesitant to post code. I can't remember the secret handshake and if you do it wrong somebody yells at you.

It's hardly that difficult. :roll_eyes:

But unless you post it, we haven't the faintest idea of what you are doing, right or wrong.

Here's my advice:


Just buy two or three of these kits:

Or these ones

which used to be more expensive but are now actually cheaper and more useful if you wish to stack matrix arrays.

The point is that you do not install the matrix arrays from the kits themselves - or their socket pins, but just solder to the positions on the PCB and you have a durable and reliable assembly to drive your own matrix arrays or in this case, linear display in custom mounting.

Why did I say two or three? Well, you can fully assemble the first one as the matrix with which it comes and practice programming it. Then the second one for your current project and the third one - for the next! :grinning:

Considering the cost, it makes no sense to just buy one!

The MAX7219 provides sixteen hardware dimming steps of the whole array.

That's a nice idea. I hadn't thought of that, but my problem is dimming for night time use. The program works fine. I just want to add a new "feature". Due to space constraints, I need to drive them directly off the board. (Uno clone for testing, mini for final product).

I can re-write the code if I can find a concept that works well.

OK. Went and looked it up again. This is the working version. No dimming, but I changed the delay times.

it's set up to take simulated input from monitor. I'm still trying to convert from BASIC so some things are still a little odd.

//lightbar LED tach fo VW
//pin 2-5 group
//pins 6-10 bulb
//pin 13 RPM input
//v3 re-work timers

unsigned long 
  MemTime,
  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,8,9,10,6,7,8,9,10,6,7,8,9,10,6,7,8,9,10};

int
  ReadNowTimer = 0,
  HiRangeTimer = 0,
  MemTimer = 0,

  intPeak,
  intHold,
  intMem,
  intPower; //not yet used

bool
  ReadNowFlag = true,
  HiRangeFlag = false,
  MemFlag = false,
  BlinkFlag=false,
  DimFlag=false;//not yet used

const int SignalPin =13, DimmerPin = 12; 

void setup() {
  for (int i=1;i<=5;i++){  //see v2 dfor old loop
    if (i<5){
    pinMode(Neg[i*5], OUTPUT);
    digitalWrite(Neg[i*5], HIGH);
    }
    pinMode(Pos[i], OUTPUT);
    digitalWrite(Pos[i], LOW);  
  }  

//LED test
  for (int j = 1;j<75;j++){
    for (int i=1;i<21;i++){
      digitalWrite(Neg[i], LOW);
      digitalWrite(Pos[i], HIGH);
        delay(1);
      digitalWrite(Neg[i], HIGH);
      digitalWrite(Pos[i], LOW);
    }  
  }

// ----- 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

// prep monitor REM it out
  Serial.begin(9600);
  Serial.println ("input value in hz 0-165 (+ enter)");
  Serial.setTimeout(10);
}

 
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++){
        digitalWrite(Neg[Cnt], LOW);
        digitalWrite(Pos[Cnt], HIGH);   //this was delay(1), changed totry dimming.
          delayMicroseconds(700);  //700&100 w 200us delay?
        digitalWrite(Neg[Cnt], HIGH);
        digitalWrite(Pos[Cnt], LOW); 
          delayMicroseconds(200);

      }
    }
   
      if (MemFlag){                           //flash mem light
        //int Neg=(intHold-1)/5+GroupStart;            //-1)/4+1; 
        //int Pos=(intHold-1)%5+BulbStart;            //1)%4+6;  
        digitalWrite(Neg[intHold], LOW);
        digitalWrite(Pos[intHold], HIGH);
        delay(1);
        digitalWrite(Neg[intHold], HIGH);
        digitalWrite(Pos[intHold], LOW);
      }
    
    if (HiRangeFlag){  //lite last LED if Hi range
      digitalWrite(Neg[20], LOW);
      digitalWrite(Pos[20], HIGH);
      delay(1);
      digitalWrite(Neg[20], HIGH);
      digitalWrite(Pos[20], LOW); 
    } 
  }while (ReadNowFlag==false);  //read every 1/4 sec
  
}

int ReadSpeed(){
  int x;
  static int intOldInput;
  /*
  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(13,HIGH,100000); //rem'd for test
  //PulseTLo=pulseIn(13,LOW,100000);
  //x=1080000/(PulseTHi+PulseTLo);//in hz
    // fix, 999 RPM truncates to lower rather than round up
  
  //temp for test
  if (Serial.available() > 0) {
    x = Serial.parseInt();
    intOldInput=x;
    Serial.print("new input ");
    Serial.println(x);
  }
  else {
    x=intOldInput;
  }  
  Serial.print("a ");
  Serial.println(x); 
  
  if (x !=0) {  
  x=(x/3.3)+.5;     // hz>100rpm (+.5 to rnd up)  //x=x/4-1;           //in LEDs
        //Serial.print("aa ");
  //Serial.println(x);
    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, bink 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;
  //Serial.print("c ");
  //Serial.println(x);
  return x;
   
}

void StandBy(){
  //EndlessLoop: //cylon effect
  while (intPeak==0){ 
    for(int Cnt=2;Cnt<=20;Cnt++){  //2,19: skip first/last for better effect
      digitalWrite(Neg[Cnt], LOW);  //see v2 dfor old loops
      digitalWrite(Pos[Cnt], HIGH);
        delay(50);  //delay ok here as prog isn't doing anything.
      digitalWrite(Neg[Cnt], HIGH);
      digitalWrite(Pos[Cnt], LOW); 
    }
      for(int Cnt=19;Cnt>=1;Cnt--){
      digitalWrite(Neg[Cnt], LOW);
      digitalWrite(Pos[Cnt], HIGH);
        delay(50);
      digitalWrite(Neg[Cnt], HIGH);
      digitalWrite(Pos[Cnt], LOW); 
    }
    intPeak=ReadSpeed();
  }
  //goto EndlessLoop;
 // return;
}

// -------------------------------
// 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.
  */
  ReadNowTimer++;
  if (HiRangeFlag){HiRangeTimer++;}
  if (MemFlag){MemTimer++;}


  // ----- task1
  if (ReadNowTimer > 125 - 1) { // read @ 1/8 sec. (was 250ms
    ReadNowTimer = 0;
    ReadNowFlag = true;
  }

  // ----- task2
  if (HiRangeTimer > 5000 - 1) {  // change range
    HiRangeTimer = 0;
    HiRangeFlag = false;
  }

  // ----- task3
  if (MemTimer > 1500 - 1) {  // Mem lite
    MemTimer = 0;
    MemFlag = false;
    intHold=0;
    intMem=0;
  }
  
}

/*RPM HZ  leds
 500  17   0      1700  57   10      3000  100   22
 600  20          1800  60   11      3200  107   23
 700  23          1900  63   12      3400  113   24
 800  27   1      2000  67   13*     3600  120   25
 900  30   2      2100  70   14      3800  127   26
1000  33   3*     2200  73   15      4000  133   24
1100  37   4      2300  77   16      4200  140
1200  40   5      2400  80   17      4400  147
1300  43   6      2500  83   18*     4600  153
1400  47   7      2600  87   19      4800  160
1500  50   8*     2700  90   20      5000  167
1600  53   9      2800  93   21 
 
 
 
  old lay-out   o o 0 o o o 0 o o o 0 o o o 0 o o o 0 o
                  1000    1250    1500    1750    2000
                  1000    2000    3000    4000    5000
  Hi 5k, ea LED=250RPM =8.3hz: start 750 RPM, 25hz  
  Lo 2k, ea LED=62.5RPM =2.08hz:start 875(1) or 940(2)
    or 500-2500rpm (halve it?
  Med(?) 3k led=125RPM = 4.17hz: start 750(1) or 875(2)
  */