簡體   English   中英

用於多路復用LED矩陣的Arduino代碼優化

[英]Arduino Code optimization for multiplexing LED Matrix

我建立了一個帶有5個移位寄存器和1個arduino micro的10x10RGB(沒有WS2811 ...,普通的)LED矩陣。

我的問題是,我的代碼現在似乎變慢了,或者其16Mhz的arduino不能處理適當的Hz速率。 現在,當我使用下面的代碼時,我會有些閃爍/滯后。 我認為大約60Hz-100Hz的Hz頻率會很好。 我已經將Arduino IDE編譯器設置從-Os更改為-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
  • 設置...
  • setB ...
  • 返回本地對象的副本
  • 在led [0]上復制分配操作符

對於12b顏色也使用8b寬的變量有點多余。 因此,一開始我會推薦類似的東西:

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);
}

您可以考慮:

  • 使用硬件SPI
  • 使用/MR輸入以一個脈沖清除所有寄存器(比shiftOut快得多)
  • 對行驅動器使用Johnson計數器( 4017 )並保存一個移位寄存器(緩沖區也適合一個uint32_t )。 與以前的版本一樣,您可以使用Q7S輸出並將MSB設置為邏輯1來更新計數器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM