2024-4-14 16:32:24 [显示全部楼层]
189浏览
查看: 189|回复: 2

[入门] 全彩8*8点阵屏实现霓虹灯效果

[复制链接]

全彩8*8点阵屏动态显示变换,实现霓虹灯效果。
全彩8*8点阵屏实现霓虹灯效果图1

一、简介
该款 RGB 点阵驱动板控制器我们采用的是 ATMEGA 328P,驱动使用的是 DM163,它是一款 8*3 通道的恒流 LED 驱动芯片,而且电流大小可以很方便的通过外接电阻调节, 另外它还可以实现 PWM 控制 LED,这样就能释放 MCU,方便用户设计其他的应用程序。
还有在模块中还加了缓冲器 M54564FP,这样增加了 RGB 点阵的显示效果。可以说这款 产品很方便用户在 Arduino IDE 环境下实现 RGB 点阵的控制。
二、产品特点
16 位颜色支持;
2)支持硬件 16MHZ PWM
3)没有任何外加的电路
4)专用 GPIO ADC 接口
5)支持硬件 URAT IIC 通信方式
624 路恒流通道每一通道电流可达 100mA
78 路源驱动恒流通道每一通道电流可达 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  
}


木子呢  管理员

发表于 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
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
关于楼主
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail