每個595的Q0~Q7分別接LED點陣的列陰極(因為列低電平點亮)。
- #include <reg52.h>
- #include <intrins.h>
- // ===================== 引腳定義 =====================
- sbit DS = P2^5; // 595 數據輸入
- sbit SH = P2^4; // 595 移位時鐘
- sbit ST = P2^6; // 595 鎖存時鐘
- // 行選宏:P2.0~P2.3 控制 74HC154,輸出低電平,經反相器后行實際為高電平點亮
- #define SetRow(n) do { P2 = (P2 & 0xF0) | ((n) & 0x0F); } while(0)
- // ===================== 發送一個字節 =====================
- void SendByte(unsigned char dat) {
- unsigned char i;
- for (i = 0; i < 8; i++) {
- DS = (dat & 0x80) ? 1 : 0;
- SH = 0;
- SH = 1;
- dat <<= 1;
- }
- }
- // ===================== 發送一行的128位列數據 =====================
- // row_data: 指向16字節數組,每個字節代表8列(低電平有效)
- void SendRowData(unsigned char *row_data) {
- unsigned char i;
- // 發送順序:先發最后一片(最右邊8列),再發第一片(最左邊8列)
- // 若您的級聯順序相反,請將循環改為 for(i=0; i<16; i++)
- for (i = 16; i > 0; i--) {
- SendByte(row_data[i-1]); // 直接發送,因為列低電平亮,0點亮
- }
- ST = 0;
- ST = 1;
- ST = 0;
- }
- // ===================== 微秒延時(調節亮度) =====================
- void delay_us(unsigned int t) {
- while (t--) _nop_();
- }
- // ===================== 字模定義(16×16,列格式) =====================
- // 這里以“Hello”的字模示例,實際使用時可用取模軟件生成
- code unsigned char font_Hello[][32] = {
- // 'H' (0)
- {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x82,0x00, 0x82,0x00, 0x82,0x00, 0x82,0x00, 0xFE,0x00,
- 0xFE,0x00, 0x82,0x00, 0x82,0x00, 0x82,0x00, 0x82,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00},
- // 'e' (1)
- {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x3C,0x00, 0x42,0x00, 0x80,0x00,
- 0xFC,0x00, 0x82,0x00, 0x42,0x00, 0x3C,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00},
- // 'l' (2)
- {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00,
- 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x7E,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00},
- // 'l' (3) 同上
- {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00,
- 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x7E,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00},
- // 'o' (4)
- {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x3C,0x00, 0x42,0x00, 0x82,0x00,
- 0x82,0x00, 0x42,0x00, 0x3C,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00}
- };
- #define CHAR_NUM 5 // 顯示字符個數
- #define CHAR_WIDTH 16 // 每個字符列數
- #define BLANK_COLS 32 // 左右空白列數
- #define TOTAL_COLS (BLANK_COLS + CHAR_NUM*CHAR_WIDTH + BLANK_COLS)
- #define SCREEN_COLS 128
- #define ROWS 16
- // ===================== 顯存(16行 × 16字節) =====================
- unsigned char display_buf[ROWS][16];
- // ===================== 更新顯存 =====================
- // offset: 當前窗口在總內容中的起始列索引
- void UpdateBuffer(unsigned int offset) {
- unsigned char row, col_byte, bit_pos;
- unsigned int src_col;
- unsigned char char_idx, col_in_char;
- unsigned char byte0, byte1;
- // 1. 清空顯存(默認全滅,即所有位為1)
- for (row = 0; row < ROWS; row++)
- for (col_byte = 0; col_byte < 16; col_byte++)
- display_buf[row][col_byte] = 0xFF;
- // 2. 填充屏幕內的有效列
- for (col_byte = 0; col_byte < 16; col_byte++) {
- for (bit_pos = 0; bit_pos < 8; bit_pos++) {
- src_col = offset + col_byte*8 + bit_pos;
- if (src_col >= TOTAL_COLS) continue;
- if (src_col < BLANK_COLS) continue;
- char_idx = (src_col - BLANK_COLS) / CHAR_WIDTH;
- col_in_char = (src_col - BLANK_COLS) % CHAR_WIDTH;
- if (char_idx >= CHAR_NUM) continue;
- // 從字模中獲取該列數據
- byte0 = font_Hello[char_idx][col_in_char*2];
- byte1 = font_Hello[char_idx][col_in_char*2 + 1];
- // 將該列數據寫入每一行的對應列(注意:低電平亮,位0表示點亮)
- for (row = 0; row < 8; row++) {
- if ((byte0 >> row) & 0x01)
- display_buf[row][col_byte] &= ~(0x80 >> bit_pos);
- }
- for (row = 0; row < 8; row++) {
- if ((byte1 >> row) & 0x01)
- display_buf[row+8][col_byte] &= ~(0x80 >> bit_pos);
- }
- }
- }
- }
- // ===================== 顯示一幀(逐行掃描) =====================
- void DisplayFrame(void) {
- unsigned char row;
- for (row = 0; row < ROWS; row++) {
- SetRow(row);
- SendRowData(display_buf[row]);
- delay_us(300); // 調節亮度,總周期 < 16*300us ≈ 4.8ms,流暢無閃爍
- }
- }
- // ===================== 定時器及滾動控制 =====================
- unsigned int offset = 0;
- unsigned char speed_cnt = 0;
- #define SPEED 8 // 速度值,越大越慢
- bit update_flag = 0;
- void Timer0_Init(void) {
- TMOD = 0x01;
- TH0 = (65536 - 10000) / 256; // 10ms定時
- TL0 = (65536 - 10000) % 256;
- TR0 = 1;
- ET0 = 1;
- EA = 1;
- }
- void Timer0_ISR(void) interrupt 1 {
- TH0 = (65536 - 10000) / 256;
- TL0 = (65536 - 10000) % 256;
- speed_cnt++;
- if (speed_cnt >= SPEED) {
- speed_cnt = 0;
- offset++;
- if (offset >= TOTAL_COLS - SCREEN_COLS) offset = 0;
- update_flag = 1;
- }
- }
- // ===================== 主函數 =====================
- void main(void) {
- UpdateBuffer(0);
- Timer0_Init();
- while (1) {
- DisplayFrame();
- if (update_flag) {
- update_flag = 0;
- UpdateBuffer(offset);
- }
- }
- }
復制代碼