找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3|回复: 0
打印 上一主题 下一主题
收起左侧

基于51单片机的16×128 LED点阵滚动显示系统(74HC154+595)

[复制链接]
跳转到指定楼层
楼主
这个项目最初是为一个客户定制的——采用51单片机驱动 16行 × 128列(8块16×16点阵拼接)的LED点阵屏,实现文字滚动显示。期间经历了硬件搭建、驱动调试,最终成功实现了稳定的显示效果。虽然由于某些原因项目未能最终交付(客户原因),但我决定将整个工程开源,供有需要的电子爱好者、学生或创客参考、使用和改进,为真正进步的人提供资源
开源的意义:让更多人能低成本玩转大屏点阵,同时避免后来者踩我踩过的坑。如果你觉得有用,欢迎留言,或提出改进建议
不要黑币,为技术发热

  • 显示尺寸:128列 × 16行(相当于8个16×16模块水平拼接)
  • 驱动方式:动态扫描(逐行扫描),列数据串行移位
  • 主控芯片:STC89C52(或任何标准51单片机)
  • 行扫描:1片74HC154(4-16译码器),输出经反相器后驱动行(高电平有效)
  • 列数据:16片74HC595级联(每片控制8列,共128列),数据输出低电平点亮
  • 显示内容:支持任意16×16点阵字模(或更大),可自定义字符、汉字、图形
  • 滚动效果:支持从左向右、从右向左、上下滚动等,速度可调

    [td]
    单片机引脚
    功能
    连接对象
    P2.0 ~ P2.3行选择(4位地址)74HC154的A、B、C、D
    P2.4595移位时钟(SH_CP)所有595的SH_CP并联
    P2.5595数据输入(DS)第一片595的DS
    P2.6595锁存时钟(ST_CP)所有595的ST_CP并联



行扫描部分:
  • 74HC154的E0、E1接地(使能有效)。
  • 输出端Y0~Y15分别接 反相器(如74HC04或三极管),反相器输出接LED点阵的行公共端。
  • 原因:74HC154为低电平有效,而我们需要的行驱动是高电平有效(点亮行),因此必须加反相器。

列驱动部分:
  • 16片74HC595级联:第一片的Q7'接第二片的DS,依次类推。
  • 所有595的OE脚接地(使能输出),MR脚接VCC(禁止复位)。
  • 每个595的Q0~Q7分别接LED点阵的列阴极(因为列低电平点亮)。
    1. #include <reg52.h>
    2. #include <intrins.h>

    3. // ===================== 引脚定义 =====================
    4. sbit DS  = P2^5;   // 595 数据输入
    5. sbit SH  = P2^4;   // 595 移位时钟
    6. sbit ST  = P2^6;   // 595 锁存时钟

    7. // 行选宏:P2.0~P2.3 控制 74HC154,输出低电平,经反相器后行实际为高电平点亮
    8. #define SetRow(n)  do { P2 = (P2 & 0xF0) | ((n) & 0x0F); } while(0)

    9. // ===================== 发送一个字节 =====================
    10. void SendByte(unsigned char dat) {
    11.     unsigned char i;
    12.     for (i = 0; i < 8; i++) {
    13.         DS = (dat & 0x80) ? 1 : 0;
    14.         SH = 0;
    15.         SH = 1;
    16.         dat <<= 1;
    17.     }
    18. }

    19. // ===================== 发送一行的128位列数据 =====================
    20. // row_data: 指向16字节数组,每个字节代表8列(低电平有效)
    21. void SendRowData(unsigned char *row_data) {
    22.     unsigned char i;
    23.     // 发送顺序:先发最后一片(最右边8列),再发第一片(最左边8列)
    24.     // 若您的级联顺序相反,请将循环改为 for(i=0; i<16; i++)
    25.     for (i = 16; i > 0; i--) {
    26.         SendByte(row_data[i-1]);   // 直接发送,因为列低电平亮,0点亮
    27.     }
    28.     ST = 0;
    29.     ST = 1;
    30.     ST = 0;
    31. }

    32. // ===================== 微秒延时(调节亮度) =====================
    33. void delay_us(unsigned int t) {
    34.     while (t--) _nop_();
    35. }

    36. // ===================== 字模定义(16×16,列格式) =====================
    37. // 这里以“Hello”的字模示例,实际使用时可用取模软件生成
    38. code unsigned char font_Hello[][32] = {
    39.     // 'H' (0)
    40.     {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x82,0x00, 0x82,0x00, 0x82,0x00, 0x82,0x00, 0xFE,0x00,
    41.      0xFE,0x00, 0x82,0x00, 0x82,0x00, 0x82,0x00, 0x82,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00},
    42.     // 'e' (1)
    43.     {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x3C,0x00, 0x42,0x00, 0x80,0x00,
    44.      0xFC,0x00, 0x82,0x00, 0x42,0x00, 0x3C,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00},
    45.     // 'l' (2)
    46.     {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00,
    47.      0x40,0x00, 0x40,0x00, 0x40,0x00, 0x7E,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00},
    48.     // 'l' (3) 同上
    49.     {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00, 0x40,0x00,
    50.      0x40,0x00, 0x40,0x00, 0x40,0x00, 0x7E,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00},
    51.     // 'o' (4)
    52.     {0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x3C,0x00, 0x42,0x00, 0x82,0x00,
    53.      0x82,0x00, 0x42,0x00, 0x3C,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00}
    54. };

    55. #define CHAR_NUM  5          // 显示字符个数
    56. #define CHAR_WIDTH 16        // 每个字符列数
    57. #define BLANK_COLS 32        // 左右空白列数
    58. #define TOTAL_COLS (BLANK_COLS + CHAR_NUM*CHAR_WIDTH + BLANK_COLS)
    59. #define SCREEN_COLS 128
    60. #define ROWS 16

    61. // ===================== 显存(16行 × 16字节) =====================
    62. unsigned char display_buf[ROWS][16];

    63. // ===================== 更新显存 =====================
    64. // offset: 当前窗口在总内容中的起始列索引
    65. void UpdateBuffer(unsigned int offset) {
    66.     unsigned char row, col_byte, bit_pos;
    67.     unsigned int src_col;
    68.     unsigned char char_idx, col_in_char;
    69.     unsigned char byte0, byte1;

    70.     // 1. 清空显存(默认全灭,即所有位为1)
    71.     for (row = 0; row < ROWS; row++)
    72.         for (col_byte = 0; col_byte < 16; col_byte++)
    73.             display_buf[row][col_byte] = 0xFF;

    74.     // 2. 填充屏幕内的有效列
    75.     for (col_byte = 0; col_byte < 16; col_byte++) {
    76.         for (bit_pos = 0; bit_pos < 8; bit_pos++) {
    77.             src_col = offset + col_byte*8 + bit_pos;
    78.             if (src_col >= TOTAL_COLS) continue;
    79.             if (src_col < BLANK_COLS) continue;
    80.             char_idx = (src_col - BLANK_COLS) / CHAR_WIDTH;
    81.             col_in_char = (src_col - BLANK_COLS) % CHAR_WIDTH;
    82.             if (char_idx >= CHAR_NUM) continue;

    83.             // 从字模中获取该列数据
    84.             byte0 = font_Hello[char_idx][col_in_char*2];
    85.             byte1 = font_Hello[char_idx][col_in_char*2 + 1];
    86.             // 将该列数据写入每一行的对应列(注意:低电平亮,位0表示点亮)
    87.             for (row = 0; row < 8; row++) {
    88.                 if ((byte0 >> row) & 0x01)
    89.                     display_buf[row][col_byte] &= ~(0x80 >> bit_pos);
    90.             }
    91.             for (row = 0; row < 8; row++) {
    92.                 if ((byte1 >> row) & 0x01)
    93.                     display_buf[row+8][col_byte] &= ~(0x80 >> bit_pos);
    94.             }
    95.         }
    96.     }
    97. }

    98. // ===================== 显示一帧(逐行扫描) =====================
    99. void DisplayFrame(void) {
    100.     unsigned char row;
    101.     for (row = 0; row < ROWS; row++) {
    102.         SetRow(row);
    103.         SendRowData(display_buf[row]);
    104.         delay_us(300);   // 调节亮度,总周期 < 16*300us ≈ 4.8ms,流畅无闪烁
    105.     }
    106. }

    107. // ===================== 定时器及滚动控制 =====================
    108. unsigned int offset = 0;
    109. unsigned char speed_cnt = 0;
    110. #define SPEED 8         // 速度值,越大越慢
    111. bit update_flag = 0;

    112. void Timer0_Init(void) {
    113.     TMOD = 0x01;
    114.     TH0 = (65536 - 10000) / 256;   // 10ms定时
    115.     TL0 = (65536 - 10000) % 256;
    116.     TR0 = 1;
    117.     ET0 = 1;
    118.     EA = 1;
    119. }

    120. void Timer0_ISR(void) interrupt 1 {
    121.     TH0 = (65536 - 10000) / 256;
    122.     TL0 = (65536 - 10000) % 256;
    123.     speed_cnt++;
    124.     if (speed_cnt >= SPEED) {
    125.         speed_cnt = 0;
    126.         offset++;
    127.         if (offset >= TOTAL_COLS - SCREEN_COLS) offset = 0;
    128.         update_flag = 1;
    129.     }
    130. }

    131. // ===================== 主函数 =====================
    132. void main(void) {
    133.     UpdateBuffer(0);
    134.     Timer0_Init();
    135.     while (1) {
    136.         DisplayFrame();
    137.         if (update_flag) {
    138.             update_flag = 0;
    139.             UpdateBuffer(offset);
    140.         }
    141.     }
    142. }
    复制代码



3b6045c49916eb2d3c95444e3e670e0c.png (1007.29 KB, 下载次数: 0)

行跑马灯演示

行跑马灯演示

16方点阵滚动显示.zip

145.89 KB, 下载次数: 0, 下载积分: 黑币 -5

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表