1044| 2
|
[入门] 全彩8*8点阵屏实现霓虹灯效果 |
全彩8*8点阵屏动态显示变换,实现霓虹灯效果。 一、简介 该款 RGB 点阵驱动板控制器我们采用的是 ATMEGA 328P,驱动使用的是 DM163,它是一款 8*3 通道的恒流 LED 驱动芯片,而且电流大小可以很方便的通过外接电阻调节, 另外它还可以实现 PWM 控制 LED,这样就能释放 MCU,方便用户设计其他的应用程序。 还有在模块中还加了缓冲器 M54564FP,这样增加了 RGB 点阵的显示效果。可以说这款 产品很方便用户在 Arduino IDE 环境下实现 RGB 点阵的控制。 二、产品特点 1)6 位颜色支持; 2)支持硬件 16MHZ PWM 3)没有任何外加的电路 4)专用 GPIO 和 ADC 接口 5)支持硬件 URAT 和 IIC 通信方式 6)24 路恒流通道每一通道电流可达 100mA 7)8 路源驱动恒流通道每一通道电流可达 500mA 三、使用说明 这个模块我们要结合 FT232 USB 适配器(我们也有对应的模块)来使用,需要用它来烧写我们的应用程序 原代码如下: #include <Wire.h> #define DEMO // enable demo #define MATRIX_ROWS 8 #define MATRIX_COLS 8 #define MATRIX_CHANNELS 3 #define MATRIX_LEDS MATRIX_ROWS*MATRIX_COLS #define MATRIX_ROW_CHANNELS MATRIX_COLS*MATRIX_CHANNELS #define WIRE_DEVICE_ADDRESS 0x70 #define ROW_PORT1 PORTB #define ROW_PORT2 PORTD #define LED_PORT PORTC #define I2C_PORT PORTD #define LED_SELECT 0x01 #define LED_LATCH 0x02 #define LED_RESET 0x04 #define I2C_SCL 0x40 #define I2C_SDA 0x80 #define SET( _reg, _bits) (_reg) |= (_bits) #define CLEAR(_reg, _bits) (_reg) &= ~(_bits) // Two copies of the LED data, one being read from to drive the LEDs in an ISR, another being written to, via I2C byte matrixDataA[MATRIX_ROWS*MATRIX_ROW_CHANNELS]; byte matrixDataB[MATRIX_ROWS*MATRIX_ROW_CHANNELS]; byte defaultCorrection[3] = {25, 63, 63}; bool matrixWriteA = true; // 'A' is the one being written to int matrixRow = 0; bool processBalance = false; bool balanceRecieved = false; // true when we've rx'd a white balance command byte* wire_DataPtr = NULL; // the write pointer int wire_DataCount = 0; // bytes received bool processClear = false; byte fastCommandBuffer[12]; byte* fastCommandPtr = NULL; bool processFast = false; // timer ISR byte timerCounter2 = 0; #ifdef DEMO unsigned long demoTimeout = 5000UL; // wait 5s after startup with no balance command before running demo. unsigned long demoTimestamp; // rolling palette: unsigned long demoR = 0xFF0000FFUL; unsigned long demoG = 0xFF00FF00UL; unsigned long demoB = 0xFFFF0000UL; unsigned long demoStep = 0; #endif inline void i2c_Write(byte value, byte mask) { // I2C write to other chip on this board, msb first while (mask) { if (value & mask) SET(I2C_PORT, I2C_SDA); else CLEAR(I2C_PORT, I2C_SDA); mask >>= 1; CLEAR(I2C_PORT, I2C_SCL); SET(I2C_PORT, I2C_SCL); } } void wire_Request(void) { // ISR to process request for bytes over I2C from external master byte response = wire_DataCount; // write MUST be a byte buffer Wire.write(&response, 1); } void wire_Receive(int numBytes) { // ISR to process receipt of bytes over I2C from external master // Get out quickly! if (numBytes == 1) // a command { byte command = Wire.read(); if (command == 0x00) // start frame { wire_DataPtr = (matrixWriteA)?matrixDataA:matrixDataB; wire_DataCount = 0; } else if (command == 0x01) // show frame { matrixWriteA = !matrixWriteA; // atomic } else if (command == 0x02) // set colour balance { processBalance = true; } else if (command == 0x03) // set TCNT2 { byte* ptr = (matrixWriteA)?matrixDataA:matrixDataB; if (ptr[1] == 16 && ptr[2] == 128) timerCounter2 = *ptr; } else if (command == 0x10) // clear to black { processClear = true; } else if (command == 0x11) // fast fill from bitmasks { fastCommandPtr = fastCommandBuffer; wire_DataPtr = NULL; wire_DataCount = 0; } return; } else if (wire_DataPtr && ((numBytes % MATRIX_CHANNELS) == 0)) // read channel (RGB) data { while (Wire.available() && wire_DataCount < MATRIX_ROWS*MATRIX_ROW_CHANNELS) { *(wire_DataPtr++) = Wire.read(); wire_DataCount++; } } else if (fastCommandPtr && ((numBytes % MATRIX_CHANNELS) == 0)) // read triplets for fast cmd { while (Wire.available() && wire_DataCount < sizeof(fastCommandBuffer)) { *(fastCommandPtr++) = Wire.read(); wire_DataCount++; } if (wire_DataCount == sizeof(fastCommandBuffer)) { // process the cmd (outside the Wire handler) processFast = true; } } // discard extras while (Wire.available()) Wire.read(); } // white balance void setCorrection(byte* pChannel, int dim) { if (*pChannel == 0x80) return; // Ignore (0x80, x, y) cli(); CLEAR(LED_PORT, LED_SELECT); // bank 0, 6-bit SET(LED_PORT, LED_LATCH); for (int ctr = 0; ctr < MATRIX_COLS; ctr++) for (int chan = MATRIX_CHANNELS - 1; chan >= 0; chan--) i2c_Write(pChannel[chan] >> dim, 0x20); // 6- bit values // latches BOTH banks CLEAR(LED_PORT, LED_LATCH); sei(); } void doFastCommand() { // r,g,b, flags,row0,row1, row2,row3,row4, row5,row6,row7 int Idx = 0; fastCommandPtr = NULL; byte R = fastCommandBuffer[Idx++]; byte G = fastCommandBuffer[Idx++]; byte B = fastCommandBuffer[Idx++]; byte F = fastCommandBuffer[Idx++]; // F=flags, B000000xy, if x is set, use black as background (otherwise leave as-is), if y is set, show buffer at end bool flagSetBackground = F & B00000010; byte* ptr = (matrixWriteA)?matrixDataA:matrixDataB; for (int row = 0; row < MATRIX_ROWS; row++) { byte mask = fastCommandBuffer[Idx++]; for (int col = 0; col < MATRIX_COLS; col++) { if (mask & 0x01) // set the colour { (*ptr++) = R; (*ptr++) = G; (*ptr++) = B; } else if (flagSetBackground) // write black { (*ptr++) = 0x00; (*ptr++) = 0x00; (*ptr++) = 0x00; } else // leave colour as-is { ptr += 3; } mask >>= 1; } } if (F & B00000001) // start displaying { matrixWriteA = !matrixWriteA; } } ISR(TIMER2_OVF_vect) { TCNT2 = timerCounter2; // all rows off ROW_PORT1 = ROW_PORT2 = 0x00; SET(LED_PORT, LED_SELECT); // bank 1, 8-bit SET(LED_PORT, LED_LATCH); byte* pChannel = (!matrixWriteA)?matrixDataA:matrixDataB; // (READING this time) // clock in the channel data for the columns in the current row. REVERSE ORDER! pChannel += matrixRow*MATRIX_ROW_CHANNELS + MATRIX_ROW_CHANNELS - 1; for (int ctr = 0; ctr < MATRIX_ROW_CHANNELS; ctr++,pChannel--) i2c_Write(*pChannel, 0x80); // latches BOTH banks CLEAR(LED_PORT, LED_LATCH); // turn on this row if (matrixRow < 6) { SET(ROW_PORT1, 0x01 << matrixRow++); } else if (matrixRow == 6) { SET(ROW_PORT2, 0x08); matrixRow = 7; } else { SET(ROW_PORT2, 0x10); matrixRow = 0; } } void setup() { // clear to black memset(matrixDataA, 0x00, sizeof(matrixDataA)); memset(matrixDataB, 0x00, sizeof(matrixDataB)); DDRB = DDRC = DDRD = 0xFF; // ALL ports to OUTPUT ROW_PORT1 = ROW_PORT2 = 0x00; // reset the DM163 driver CLEAR(LED_PORT, LED_RESET); SET(LED_PORT, LED_RESET); // default white balance setCorrection(defaultCorrection, 0); // configure timer2 to service LED row updates at ~800Hz ASSR = _BV(AS2); // Internal Calibrated clock source 16MHz TCCR2A = 0x00; // Normal mode TCCR2B = _BV(CS22) | _BV(CS20); // clk/128 TIMSK2 = _BV(TOIE2); // Overflow interrupt only unsigned long timerFrequencyHz = 800UL; // sweet spot for brightness and steadyness, even when dimmed unsigned long clockFrequencyHz = 16000000UL; clockFrequencyHz /= 128UL; // clock cycles to get the desired period: unsigned long clockCyclesForTimerPeriod = clockFrequencyHz / timerFrequencyHz; // overflow the 8-bit counter: timerCounter2 = 255 - clockCyclesForTimerPeriod; TCNT2 = timerCounter2; sei(); Wire.begin(WIRE_DEVICE_ADDRESS); Wire.onRequest(wire_Request); Wire.onReceive(wire_Receive); #ifdef DEMO demoTimestamp = millis(); #endif } void loop() { if (processBalance) { setCorrection((matrixWriteA)?matrixDataA:matrixDataB, 0); processBalance = false; balanceRecieved = true; } else if (processFast) { doFastCommand(); processFast = false; } else if (processClear) { memset((matrixWriteA)?matrixDataA:matrixDataB, 0x00, MATRIX_ROWS*MATRIX_ROW_CHANNELS); processClear = false; } #ifdef DEMO else if (!balanceRecieved) { unsigned long now = millis(); if (now - demoTimestamp >= demoTimeout) { // kick demo animation demoTimestamp = now; byte* pChannel = (matrixWriteA)?matrixDataA:matrixDataB; if (demoStep < 20) // first frames are solid/dimmed setCorrection(defaultCorrection, 4-(demoStep%5)); for (int row = 0; row < MATRIX_ROWS; row++) for (int col = 0; col < MATRIX_COLS; col++) { if (demoStep < 20) { int index = 8*(demoStep/5); *(pChannel++) = demoR >> index; *(pChannel++) = demoG >> index; *(pChannel++) = demoB >> index; } else { int index = 8*min(min(MATRIX_ROWS - row - 1, row), min(MATRIX_COLS - col - 1, col)); *(pChannel++) = demoR >> index; *(pChannel++) = demoG >> index; *(pChannel++) = demoB >> index; } } demoStep++; matrixWriteA = !matrixWriteA; if (demoR == 0xFF0000FFUL) demoTimeout = 500UL; // dwell on first frames else demoTimeout = 200UL; if (demoStep > 20) { demoR = (demoR >> 8) | (random(0xFF) << 24); demoG = (demoG >> 8) | (random(0xFF) << 24); demoB = (demoB >> 8) | (random(0xFF) << 24); } } } #endif } |
© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed