Arduino代码优化的多路复用LED矩阵

Arduino Code optimization for multiplexing LED Matrix

本文关键字:LED 矩阵 复用 多路 代码优化 Arduino      更新时间:2023-10-16

我已经构建了一个10x10RGB(没有WS2811…LED矩阵有5个移位寄存器和1个arduino微处理器。

我的问题是现在我的代码似乎很慢或arduino与它的16Mhz只是不能处理一个体面的赫兹率。当我使用下面的代码时,我得到了一些闪烁/滞后。我认为大约60Hz-100Hz的频率会很好。我已经将Arduino IDE编译器设置从- o更改为-O3以获得更好的速度(它确实有效)。

该代码具有用于亮度控制的位角调制和多路复用功能。

所以我的问题:是否值得创建一个数组,其中所有可能的值(10个值,只有int <10)是预定义的,然后在第312行使用它们:

BitMapR1[intLayerSel / 10] = _byte;

我搜索了互联网,我发现一些文章告诉arduinos(或微控制器)的划分是非常缓慢的。

setBitMaps()是位角调制发生的地方Myloop()是发生多路复用的地方

代码: http://pastebin.com/tkFZsVxS <——最好看这里

class FLED {
private:
bool b;
public:
FLED();
void show();
};
FLED::FLED() : b(false) {
}
void FLED::show() {
}

class LED {
private:
uint8_t LEDname;
uint8_t R;
uint8_t G;
uint8_t B;
public:
LED();
uint8_t getR();
uint8_t getG();
uint8_t getB();
void setR(uint8_t _R);
void setG(uint8_t _G);
void setB(uint8_t _B);
};
LED::LED() : R(0), G(0), B(0) {
}
uint8_t LED::getR() {
return R;
}
uint8_t LED::getG() {
return G;
}
uint8_t LED::getB() {
return B;
}
void LED::setR(uint8_t _R) {
R = _R;
}
void LED::setG(uint8_t _G) {
G = _G;
}
void LED::setB(uint8_t _B) {
B = _B;
}
LED leds[100];
FLED FastLED;

void setup() {
//set pins to output so you can control the shift register
pinMode(2, OUTPUT);
pinMode(4, OUTPUT);
pinMode(3, OUTPUT);
pinMode(5, OUTPUT);
//Serial.begin(250000);
//noInterrupts();
}
unsigned long lngLast = 0;

uint8_t BitMapR1[10] = {
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000
};
uint8_t BitMapR2[10] = {
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000
};
uint8_t BitMapR3[10] = {
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000
};
uint8_t BitMapR4[10] = {
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000
};
LED CRGB(byte _R, byte _G, byte _B) {
LED _LED = LED();
_LED.setR(constrain(_R / 16, 0, 15));
_LED.setG(constrain(_G / 16, 0, 15));
_LED.setB(constrain(_B / 16, 0, 15));
return _LED;
}
void loop() {

//Serial.print(micros()); Serial.println(" Start");
leds[0] = CRGB(36, 0, 0);
leds[1] = CRGB(103, 0, 0);
leds[2] = CRGB(170, 0, 0);
leds[3] = CRGB(255, 0, 0);
leds[4] = CRGB(255, 0, 0);
leds[5] = CRGB(170, 0, 0);
..........
leds[96] = CRGB(103, 0, 0);
leds[97] = CRGB(36, 0, 0);
leds[98] = CRGB(0, 0, 0);
leds[99] = CRGB(0, 0, 0);

//Serial.print(micros()); Serial.println(" Objekte");
BAM();
//Serial.print(micros()); Serial.println(" BAM");
}
void BAM() {
for (byte cycle = 1; cycle <= 15; cycle++) {
//Serial.print(micros()); Serial.println(" bSetBitMaps");
setBitMaps(cycle, 1);
//Serial.print(micros()); Serial.println(" aSetBitMaps");
lngLast = micros();
myloop();
delayMicroseconds(50);
turnoff();


//Serial.print(micros()); Serial.println(" aMyloop");

}

}
void turnoff() {
PORTD &= ~_BV(PORTD2);
ShiftOut(B00000000);
ShiftOut(B00000000);
ShiftOut(B00000000);
ShiftOut(B00000000);
ShiftOut(B00000000);
PORTD |= _BV(PORTD2);//LatchPin
}
void setBitMaps(byte cycle, byte pos) {
//Register 1
for (byte intLayerSel = 0; intLayerSel < 100; intLayerSel += 10){        
byte _byte = 0;
for (byte i = intLayerSel; i < intLayerSel + 8; i++) {
  if (cycle == 1 && (leds[i].getR() & (1 << pos - 1)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if ((cycle == 2 || cycle == 3) && (leds[i].getR() & (1 << pos)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if (cycle >= 4 && cycle <= 7 && (leds[i].getR() & (1 << pos + 1 )) != 0)  {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if (cycle >= 8 && cycle <= 15 && (leds[i].getR() & (1 << pos + 2)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else {
    _byte = _byte << 1;
    _byte = _byte + B00000000;
  }
}
BitMapR1[intLayerSel / 10] = _byte;
}
for (byte intLayerSel = 0; intLayerSel < 100; intLayerSel += 10) { 
byte _byte = 0;
for (byte i = intLayerSel + 8; i < intLayerSel + 10; i++) {
  if (cycle == 1 && (leds[i].getR() & (1 << pos - 1)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if ((cycle == 2 || cycle == 3) && (leds[i].getR() & (1 << pos)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if (cycle >= 4 && cycle <= 7 && (leds[i].getR() & (1 << pos + 1 )) != 0)  {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if (cycle >= 8 && cycle <= 15 && (leds[i].getR() & (1 << pos + 2)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else {
    _byte = _byte << 1;
    _byte = _byte + B00000000;
  }
}
for (byte i = intLayerSel; i < intLayerSel + 6; i++) {
  if (cycle == 1 && (leds[i].getG() & (1 << pos - 1)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if ((cycle == 2 || cycle == 3) && (leds[i].getG() & (1 << pos)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if (cycle >= 4 && cycle <= 7 && (leds[i].getG() & (1 << pos + 1 )) != 0)  {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if (cycle >= 8 && cycle <= 15 && (leds[i].getG() & (1 << pos + 2)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else {
    _byte = _byte << 1;
    _byte = _byte + B00000000;
  }
}
BitMapR2[intLayerSel / 10] = _byte;
}
}

void myloop() {
byte bLayerA;
byte bLayerB;

for (byte bLayerTop = 1; bLayerTop <= 10; bLayerTop++) {
//Serial.print(micros()); Serial.println(" startML");
bLayerA = B00000000;
bLayerB = B00000000;
switch (bLayerTop) {
  case 1:
    bLayerA = B10000000;
    break;
  case 2:
    bLayerA = B01000000;
    break;
  case 3:
    bLayerA = B00100000;
    break;
  case 4:
    bLayerA = B00010000;
    break;
  case 5:
    bLayerA = B00001000;
    break;
  case 6:
    bLayerA = B00000100;
    break;
  case 7:
    bLayerA = B00000010;
    break;
  case 8:
    bLayerA = B00000001;
    break;
  case 9:
    bLayerB = B00000010;
    break;
  case 10:
    bLayerB = B00000001;
    break;
  }
/*
  if (bLayerTop == 1) {
  bLayerA = B10000000;
  } else if (bLayerTop == 2) {
  bLayerA = B01000000;
  } else if (bLayerTop == 3) {
  bLayerA = B00100000;
  } else if (bLayerTop == 4) {
  bLayerA = B00010000;
  } else if (bLayerTop == 5) {
  bLayerA = B00001000;
  } else if (bLayerTop == 6) {
  bLayerA = B00000100;
  } else if (bLayerTop == 7) {
  bLayerA = B00000010;
  } else if (bLayerTop == 8) {
  bLayerA = B00000001;
  } else if (bLayerTop == 9) {
  bLayerB = B00000010;
  } else if (bLayerTop == 10) {
  bLayerB = B00000001;
  }
*/

//Serial.print(micros()); Serial.println(" bWait");
while (micros() - lngLast < 50) {
  //Serial.println("call");
}
//Serial.print(micros()); Serial.println(" aWait");
turnoff();
PORTD &= ~_BV(PORTD2); //Latch LOW
//OutPut Enable = False
PORTD |= _BV(PORTD5);
byte bLayer = bLayerTop - 1;
ShiftOut(bLayerA);                     //Register 5
ShiftOut(bLayerB + BitMapR4[bLayer]);  //Register 4
ShiftOut(BitMapR3[bLayer]);            //Register 3
ShiftOut(BitMapR2[bLayer]);            //Register 2
ShiftOut(BitMapR1[bLayer]);            //Register 1
//take the latch pin high so the LEDs will light up:
PORTD |= _BV(PORTD2);//Latch High
//OutPut Enable = True
PORTD &= ~_BV(PORTD5);
// pause before next value:
//delay(1);
//delayMicroseconds(100);
// Serial.print(micros()); Serial.println(" end");
lngLast = micros();
}
}
void ShiftOut(byte myDataOut) {
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low
//internal function setup
byte i = 0;
//clear everything out just in case to
//prepare shift register for bit shifting
PORTD &= ~_BV(PORTD3);//Data off
PORTD &= ~_BV(PORTD4);//Clock off
//for each bit in the byte myDataOutï
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i = 0; i <= 7; i++)  {
PORTD &= ~_BV(PORTD4);//Clock aus
//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.

/*
    //00001010 - 00000010 = true
    switch (myDataOut & (1 << i)) {
      case 0:
        Serial.println("0");
        PORTD &= ~_BV(PORTD3);//Data aus
        break;
      case 1: //case true
        Serial.println("1");
        PORTD |= _BV(PORTD3);//Data an
        break;
    }
*/
/*
  digitalWrite(3, myDataOut & (1 << i));
*/

if ( myDataOut & (1 << i) ) {
  PORTD |= _BV(PORTD3);//Data an
} else {
  PORTD &= ~_BV(PORTD3);//Data aus
}
//register shifts bits on upstroke of clock pin
PORTD |= _BV(PORTD4);//Clock an
//zero the data pin after shift to prevent bleed through
PORTD &= ~_BV(PORTD3);//Data aus
}
}

有很多问题,比如:

leds[0] = CRGB(36, 0, 0);
这意味着

:

  • 将参数复制到堆栈
  • 调用CRBG函数
  • 创建本地LED对象
  • setR通过调用约束
  • setG…
  • setB…
  • 返回本地对象的副本
  • 复制赋值操作符[0]

同样使用8b宽变量12b的颜色有点多余。所以在开始的时候,我建议这样写:

class LED {
  public:
    uint16_t rgb;
    LED(uint8_t r=0, uint8_t g=0, uint8_t b=0) {
      setRGB(r,g,b);
    }
    void setRGB(uint8_t r=0, uint8_t g=0, uint8_t b=0) {
      r = r >> 4; 
      g = g&0xF0;
      rgb = b&0xF0;
      rgb = (rgb<<4) | g | r;
    }
    bool getBit(uint16_t mask) {
      return rgb & mask;
    }
};
LED leds[100];
void setup() {
  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  Serial.begin(250000);
}
void loop() {
  leds[0].setRGB(36, 0, 0);
  leds[1].setRGB(103, 0, 0);
  leds[2].setRGB(170, 0, 0);
  leds[3].setRGB(255, 0, 0);
  leds[4].setRGB(255, 0, 0);
  leds[5].setRGB(170, 0, 0);
  leds[6].setRGB(103, 0, 0);
  leds[7].setRGB(36, 0, 0);
  leds[8].setRGB(0, 0, 0);
  leds[9].setRGB(0, 0, 0);
  leds[10].setRGB(36, 0, 0);
  leds[11].setRGB(103, 0, 0);
  leds[12].setRGB(170, 0, 0);
  leds[13].setRGB(255, 0, 0);
  leds[14].setRGB(255, 0, 0);
  leds[15].setRGB(170, 0, 0);
  leds[16].setRGB(103, 0, 0);
  leds[17].setRGB(36, 0, 0);
  leds[18].setRGB(0, 0, 0);
  leds[19].setRGB(0, 0, 0);
  leds[20].setRGB(36, 0, 0);
  leds[21].setRGB(103, 0, 0);
  leds[22].setRGB(170, 0, 0);
  leds[23].setRGB(255, 0, 0);
  leds[24].setRGB(255, 0, 0);
  leds[25].setRGB(170, 0, 0);
  leds[26].setRGB(103, 0, 0);
  leds[27].setRGB(36, 0, 0);
  leds[28].setRGB(0, 0, 0);
  leds[29].setRGB(0, 0, 0);
  leds[30].setRGB(36, 0, 0);
  leds[31].setRGB(103, 0, 0);
  leds[32].setRGB(170, 0, 0);
  leds[33].setRGB(255, 0, 0);
  leds[34].setRGB(255, 0, 0);
  leds[35].setRGB(170, 0, 0);
  leds[36].setRGB(103, 0, 0);
  leds[37].setRGB(36, 0, 0);
  leds[38].setRGB(0, 0, 0);
  leds[39].setRGB(0, 0, 0);
  leds[40].setRGB(36, 0, 0);
  leds[41].setRGB(103, 0, 0);
  leds[42].setRGB(170, 0, 0);
  leds[43].setRGB(255, 0, 0);
  leds[44].setRGB(255, 0, 0);
  leds[45].setRGB(170, 0, 0);
  leds[46].setRGB(103, 0, 0);
  leds[47].setRGB(36, 0, 0);
  leds[48].setRGB(0, 0, 0);
  leds[49].setRGB(0, 0, 0);
  leds[50].setRGB(36, 0, 0);
  leds[51].setRGB(103, 0, 0);
  leds[52].setRGB(170, 0, 0);
  leds[53].setRGB(255, 0, 0);
  leds[54].setRGB(255, 0, 0);
  leds[55].setRGB(170, 0, 0);
  leds[56].setRGB(103, 0, 0);
  leds[57].setRGB(36, 0, 0);
  leds[58].setRGB(0, 0, 0);
  leds[59].setRGB(0, 0, 0);
  leds[60].setRGB(36, 0, 0);
  leds[61].setRGB(103, 0, 0);
  leds[62].setRGB(170, 0, 0);
  leds[63].setRGB(255, 0, 0);
  leds[64].setRGB(255, 0, 0);
  leds[65].setRGB(170, 0, 0);
  leds[66].setRGB(103, 0, 0);
  leds[67].setRGB(36, 0, 0);
  leds[68].setRGB(0, 0, 0);
  leds[69].setRGB(0, 0, 0);
  leds[70].setRGB(36, 0, 0);
  leds[71].setRGB(103, 0, 0);
  leds[72].setRGB(170, 0, 0);
  leds[73].setRGB(255, 0, 0);
  leds[74].setRGB(255, 0, 0);
  leds[75].setRGB(170, 0, 0);
  leds[76].setRGB(103, 0, 0);
  leds[77].setRGB(36, 0, 0);
  leds[78].setRGB(0, 0, 0);
  leds[79].setRGB(0, 0, 0);
  leds[80].setRGB(36, 0, 0);
  leds[81].setRGB(103, 0, 0);
  leds[82].setRGB(170, 0, 0);
  leds[83].setRGB(255, 0, 0);
  leds[84].setRGB(255, 0, 0);
  leds[85].setRGB(170, 0, 0);
  leds[86].setRGB(103, 0, 0);
  leds[87].setRGB(36, 0, 0);
  leds[88].setRGB(0, 0, 0);
  leds[89].setRGB(0, 0, 0);
  leds[90].setRGB(36, 0, 0);
  leds[91].setRGB(103, 0, 0);
  leds[92].setRGB(170, 0, 0);
  leds[93].setRGB(255, 0, 0);
  leds[94].setRGB(255, 0, 0);
  leds[95].setRGB(170, 0, 0);
  leds[96].setRGB(103, 0, 0);
  leds[97].setRGB(36, 0, 0);
  leds[98].setRGB(0, 0, 0);
  leds[99].setRGB(255, 255, 255);

// show context
  for (uint16_t bitmask = 1U; bitmask < 0x400; bitmask <<= 1) {
    for (LED & led : leds) {
      Serial.print(led.getBit(bitmask), HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
  do_cycle();
}
void do_cycle() {
  uint16_t bitmask_r = 0;  
  uint16_t bitmask_g = 0;  
  uint16_t bitmask_b = 0;  
  for (byte mag = 1; mag < 16; ++mag) { // magnitude
    for (byte row = 0; row < 10; ++row) { // mistake #2
      //uint32_t us = micros();
      if ((mag & (mag-1)) == 0) { // Is it power of two? Change bitmask
        bitmask_r = mag;
        bitmask_g = bitmask_r << 4;
        bitmask_b = bitmask_g << 4;
      }
      // shift out init:
      PORTD &= ~_BV(PD3); //Data aus
      PORTD &= ~_BV(PD4); //Clock aus
      for (int8_t cnt = 9; cnt >= 0; --cnt) {
        //Serial.print(cnt==row?1:0);
        shift1bit(cnt==row); // mistake #1
      }
      for (int8_t col = 9; col >= 0; --col) {
        //Serial.print(leds[row*10+col].getBit(bitmask_b));
        shift1bit(leds[row*10+col].getBit(bitmask_b));
      }
      for (int8_t col = 9; col >= 0; --col) {
        //Serial.print(leds[row*10+col].getBit(bitmask_g));
        shift1bit(leds[row*10+col].getBit(bitmask_g));
      }
      for (int8_t col = 9; col >= 0; --col) {
        //Serial.print(leds[row*10+col].getBit(bitmask_r));
        shift1bit(leds[row*10+col].getBit(bitmask_r));
      }
      PORTD |=  _BV(PD2); // LatchPin
      PORTD &= ~_BV(PD2); // disable LatchPin
      //Serial.println(micros()-us);
      delayMicroseconds(50);
    }
  }
}
inline void shift1bit (bool b) {
  // set data:
  if (b) {
    PORTD |= _BV(PD3);
  } else {
    PORTD &= ~_BV(PD3);
  }
  // clock pulse:
  PORTD |=  _BV(PD4);
  PORTD &= ~_BV(PD4);
}

你可以考虑:

  • 使用HW SPI
  • 使用/MR输入通过一个脉冲清除所有寄存器(比shiftOut快得多)
  • 使用约翰逊计数器(4017)为行驱动程序并保存一个移位寄存器(也缓冲区适合一个uint32_t)。以前你可以使用Q7S输出和MSB设置为逻辑1更新计数器。