實現一個從左向右橫向滾動的"吉祥如意"顯示效果。
arduino r4 WiFi滾動顯示16*16led
#include <SPI.h>// 引腳定義
const int RowA = 2, RowB = 3, RowC = 4, RowD = 5;
const int OE = 6;
const int LATCH = 10;// 字模數據 (吉祥如意)
const PROGMEM byte characterData[4][32] = {// 吉{0x01,0x00,0x01,0x00,0x01,0x04,0xFF,0xFE,0x01,0x00,0x01,0x00,0x01,0x10,0x3F,0xF8,0x00,0x00,0x00,0x10,0x1F,0xF8,0x10,0x10,0x10,0x10,0x10,0x10,0x1F,0xF0,0x10,0x10},// 祥{0x22,0x08,0x11,0x10,0x10,0xA0,0xFB,0xFC,0x08,0x40,0x10,0x40,0x3B,0xF8,0x54,0x40,0x94,0x40,0x10,0x44,0x17,0xFE,0x10,0x40,0x10,0x40,0x10,0x40,0x10,0x40,0x10,0x40},// 如{0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x04,0xFE,0xFE,0x22,0x84,0x22,0x84,0x22,0x84,0x22,0x84,0x42,0x84,0x24,0x84,0x14,0x84,0x08,0x84,0x14,0xFC,0x22,0x84,0x40,0x00},// 意{0x01,0x00,0x3F,0xF8,0x08,0x20,0x04,0x44,0xFF,0xFE,0x00,0x00,0x1F,0xF0,0x10,0x10,0x1F,0xF0,0x10,0x10,0x1F,0xF0,0x02,0x08,0x51,0x04,0x51,0x24,0x90,0x20,0x0F,0xE0}
};SPISettings spiSettings(10000000, MSBFIRST, SPI_MODE0);// 橫向滾動緩沖區 (64列 x 16行)
byte scrollBuffer[16][8]; // 每行8字節=64位 (4個漢字)// 滾動狀態
int scrollOffset = 0;
unsigned long lastScrollTime = 0;
const int scrollDelay = 50; // 滾動速度 (毫秒)// 顯示控制
unsigned long lastFrameTime = 0;
const int targetFPS = 200; // 目標幀率 (200幀/秒)
const int frameInterval = 1000 / targetFPS; // 5ms/幀void setup() {// 初始化引腳pinMode(RowA, OUTPUT); pinMode(RowB, OUTPUT);pinMode(RowC, OUTPUT); pinMode(RowD, OUTPUT);pinMode(OE, OUTPUT); pinMode(LATCH, OUTPUT);digitalWrite(OE, HIGH);digitalWrite(LATCH, HIGH);SPI.begin();// 初始化橫向滾動緩沖區initializeScrollBuffer();Serial.begin(115200);Serial.println("橫向滾動顯示器準備就緒");
}// 設置行選擇
void setRow(byte row) {digitalWrite(RowA, row & 0x01);digitalWrite(RowB, (row >> 1) & 0x01);digitalWrite(RowC, (row >> 2) & 0x01);digitalWrite(RowD, (row >> 3) & 0x01);
}// 初始化橫向滾動緩沖區
void initializeScrollBuffer() {// 將四個漢字轉換為橫向排列的緩沖區for (int row = 0; row < 16; row++) {for (int charIndex = 0; charIndex < 4; charIndex++) {// 獲取每個漢字的左右字節byte leftByte = pgm_read_byte(&characterData[charIndex][row * 2]);byte rightByte = pgm_read_byte(&characterData[charIndex][row * 2 + 1]);// 將每個漢字的16位分為兩個字節存儲scrollBuffer[row][charIndex * 2] = leftByte;scrollBuffer[row][charIndex * 2 + 1] = rightByte;}}
}// 橫向滾動內容
void scrollContent() {scrollOffset++;if (scrollOffset >= 64) { // 64列 = 4漢字 * 16列scrollOffset = 0;}
}// 獲取當前列的數據
byte getColumnData(byte row, int column) {int byteIndex = column / 8;int bitIndex = 7 - (column % 8); // 高位在前return (scrollBuffer[row][byteIndex] >> bitIndex) & 0x01;
}// 顯示單幀內容
void displayFrame() {// 確保固定幀率unsigned long currentTime = micros();unsigned long elapsed = currentTime - lastFrameTime;if (elapsed < frameInterval * 1000) {delayMicroseconds(frameInterval * 1000 - elapsed);}lastFrameTime = micros();// 逐行顯示for (byte row = 0; row < 16; row++) {digitalWrite(OE, HIGH); // 關閉顯示// 準備SPI傳輸SPI.beginTransaction(spiSettings);// 構建當前行的16位數據 (從右向左排列)uint16_t rowData = 0;// 從滾動偏移位置開始,取16列數據for (int col = 0; col < 16; col++) {int actualCol = (scrollOffset + col) % 64;byte pixel = getColumnData(row, actualCol);// 設置位 (從最高位開始)rowData = (rowData << 1) | pixel;}// 發送數據 (高8位和低8位)SPI.transfer(~(rowData >> 8)); // 高8位SPI.transfer(~(rowData & 0xFF)); // 低8位// 結束SPI傳輸SPI.endTransaction();// 設置當前行setRow(row);// 鎖存數據digitalWrite(LATCH, LOW);digitalWrite(LATCH, HIGH);// 開啟顯示digitalWrite(OE, LOW);// 行顯示時間 (100μs)delayMicroseconds(100);}// 所有行顯示完畢后立即關閉顯示digitalWrite(OE, HIGH);
}void loop() {// 滾動控制if (millis() - lastScrollTime > scrollDelay) {scrollContent();lastScrollTime = millis();}// 顯示當前幀displayFrame();
}
橫向滾動實現原理
數據結構設計
圖表
橫向滾動過程
-
緩沖區初始化:
-
將四個漢字按順序排列在64列×16行的緩沖區中
-
每個漢字占據16列空間
-
-
滾動顯示:
圖表
-
取數據邏輯:
-
從
scrollOffset
位置開始取16列 -
構建16位行數據
-
發送給74HC595
-
關鍵優化
-
高效數據結構:
-
使用16×8字節緩沖區存儲64列數據
-
直接訪問列數據,無需實時計算
-
-
平滑滾動:
arduino
-
const int scrollDelay = 50; // 每50ms滾動1列
-
視覺效果優化:
-
從左向右滾動符合閱讀習慣
-
完整顯示每個漢字的時間:16列 × 50ms = 800ms
-
四個漢字完整顯示時間:3.2秒
-
-
亮度均衡:
arduino
-
delayMicroseconds(100); // 每行顯示時間一致
參數調整指南
-
滾動速度:
arduino
-
// 較慢速度 (約每秒10列) const int scrollDelay = 100;// 中等速度 (約每秒20列) const int scrollDelay = 50;// 較快速度 (約每秒33列) const int scrollDelay = 30;
-
顯示亮度:
arduino
-
// 較低亮度 delayMicroseconds(80);// 中等亮度 delayMicroseconds(100);// 較高亮度 delayMicroseconds(120);
-
刷新率:
arduino
-
// 減少閃爍 (推薦) const int targetFPS = 200;// 更高刷新率 (需要更快的硬件) const int targetFPS = 300;
常見問題解決
-
顯示方向反了:
如果文字從右向左滾動,修改數據構建方式:arduino
-
// 原代碼 (從左向右) rowData = (rowData << 1) | pixel;// 改為從右向左 rowData = (rowData >> 1) | (pixel << 15);
-
亮度不均勻:
-
檢查OE信號是否在每行結束后立即拉高
-
確保每行顯示時間嚴格一致
-
增加幀間延時:
arduino
-
-
-
const int frameInterval = 1000 / 150; // 降低刷新率
-
-
漢字顯示不完整:
-
確認緩沖區初始化正確
-
檢查字模數據是否正確加載
-
增加滾動延遲:
arduino
-
-
-
const int scrollDelay = 80; // 更慢的滾動
-
擴展功能
-
添加新文字:
arduino
-
// 添加第五個字 const PROGMEM byte characterData[5][32] = {// 原有四個字...// 新字數據... };// 更新緩沖區大小 byte scrollBuffer[16][10]; // 5漢字 * 16列/8 = 10字節
-
雙向滾動:
arduino
-
bool scrollDirection = true; // true=向右, false=向左void scrollContent() {if(scrollDirection) {scrollOffset++;} else {scrollOffset--;}// 邊界檢查... }
-
暫停功能:
arduino
-
const int pauseButton = 7;void setup() {pinMode(pauseButton, INPUT_PULLUP); }void loop() {if (digitalRead(pauseButton) == LOW) {// 顯示當前幀但不滾動while (digitalRead(pauseButton) == LOW) {displayFrame();}}// 正常滾動... }
這個橫向滾動方案解決了之前縱向滾動時文字看不清的問題,同時保持了流暢的動畫效果和均衡的亮度顯示。每個漢字都有足夠的時間完整顯示,便于觀看。