疾风17 发表于 2024-4-14 16:32:24

全彩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_PORTPORTC
#define I2C_PORTPORTD

#define LED_SELECT 0x01
#define LED_LATCH0x02
#define LED_RESET0x04

#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;
byte matrixDataB;
byte defaultCorrection[3] = {25, 63, 63};

bool matrixWriteA = true;// 'A' is the one being written to
intmatrixRow = 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;

bytefastCommandBuffer[12];
byte* fastCommandPtr = NULL;
boolprocessFast = 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 >> 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;
byte G = fastCommandBuffer;
byte B = fastCommandBuffer;

byte F = fastCommandBuffer;
// 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;
    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
}


木子呢 发表于 2024-4-15 11:44:16

有演示图或者视频吗

疾风17 发表于 2024-4-20 13:22:07

木子呢 发表于 2024-4-15 11:44
有演示图或者视频吗

【全彩8*8点阵屏动态霓虹灯】 https://www.bilibili.com/video/BV1Dw4m117rZ/?share_source=copy_web&vd_source=73065ad2a92df7535b0d65ddc215c2bd
页: [1]
查看完整版本: 全彩8*8点阵屏实现霓虹灯效果