OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 55|回复: 1

鹿小班51单片机,8*8点阵模块亮点失败

[复制链接]

1

主题

1

帖子

0

精华

新手入门

积分
4
金钱
4
注册时间
2026-8-3
在线时间
1 小时
发表于 昨天 18:52 | 显示全部楼层 |阅读模式
1金钱
弄了之后,现象是数码管第一个数字亮,其他数字闪烁,然后LED流水灯d3d4d5一直闪烁8×8点,这模块一点都没有亮,按其他按键也没有反应
#include <REGX52.H>
#include <string.h>

/* ================================================================
*                          类型定义
* ================================================================ */
typedef unsigned char u8;
typedef unsigned int u16;

/* ================================================================
*                          常量定义
* ================================================================ */
#define PAGE_SIZE  8

/* ================================================================
*                      74HC595点阵驱动引脚
* ================================================================ */
sbit SER_595    = P3^4;  // 串行数据输入
sbit SRCLK_595  = P3^6;  // 移位时钟
sbit RCLK_595   = P3^5;  // 锁存时钟

/* ================================================================
*                    矩阵按键引脚定义
* ================================================================ */
#define ROW1    P1_7
#define ROW2    P1_6
#define ROW3    P1_5
#define ROW4    P1_4

#define COL1    P1_3
#define COL2    P1_2
#define COL3    P1_1
#define COL4    P1_0

/* ================================================================
*                     I2C通信引脚定义(P2.0/P2.1)
* ================================================================ */
sbit SCL     = P2^0;
sbit SDA     = P2^1;

/* ================================================================
*                      EEPROM设备地址
* ================================================================ */
#define EEPROM_ADDR_WRITE   0xA0
#define EEPROM_ADDR_READ    0xA1

/* ================================================================
*                        按键返回值
* ================================================================ */
#define KEY_NONE    0xFF
#define KEY_0       0
#define KEY_1       1
#define KEY_2       2
#define KEY_3       3
#define KEY_4       4
#define KEY_5       5
#define KEY_6       6
#define KEY_7       7
#define KEY_8       8
#define KEY_9       9
#define KEY_A       10
#define KEY_B       11
#define KEY_C       12
#define KEY_D       13
#define KEY_STAR    14
#define KEY_POUND   15

/* ================================================================
*                    8x8点阵字模数据(逐列式高位在上)
* ================================================================ */
// "OK" 8x16字模 O(前8字节) K(后8字节)
u8 code OK_Logo[16] =
{
    0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C,  // O
    0x42,0x44,0x48,0x50,0x68,0x44,0x42,0x42   // K
};

// "HELLO" 5个8x8字符,共40字节
u8 code HELLO_Logo[40] =
{
    0x7E,0x40,0x40,0x7E,0x40,0x40,0x40,0x7E,  // H
    0x7E,0x40,0x40,0x7C,0x40,0x40,0x40,0x7E,  // E
    0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7E,  // L
    0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7E,  // L
    0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C   // O
};

/* ================================================================
*                      全局状态变量
* ================================================================ */
u8 displayMode = 0;   // 0空闲 1显示OK 2滚动HELLO
u8 dispCnt = 0;       // 显示计时计数器
u8 scrollOff = 0;     // HELLO滚动偏移量

/* ================================================================
*                        基础延时函数
* ================================================================ */
void DelayMs(u8 t)
{
    u8 i, j;
    while(t--)
        for(i = 5; i > 0; i--)
            for(j = 199; j > 0; j--);
}

void DelayUs(u8 t)
{
    while(t--);
}

/* ================================================================
*                    74HC595驱动函数
* ================================================================ */
void HC595_WriteByte(u8 dat)
{
    u8 i;
    SRCLK_595 = 0;
    RCLK_595  = 0;
    for(i = 0; i < 8; i++)
    {
        SER_595 = dat >> 7;
        dat <<= 1;
        SRCLK_595 = 1;
        DelayUs(1);
        SRCLK_595 = 0;
    }
    RCLK_595 = 1;
    DelayUs(1);
    RCLK_595 = 0;
}

/* ================================================================
*             74HC138 行选通函数(用P2.2/P2.3/P2.4)
* ================================================================ */
void SelectRow(u8 row)
{
    // 保留 P2.0, P2.1 (I2C) 不变,清空 P2.2, P2.3, P2.4
    P2 = (P2 & 0xE3) | (row << 2);
}

/* ================================================================
*              点阵单行扫描(配合74HC595 + 74HC138)
* ================================================================ */
void Matrix_ScanOneLine(u8 row, u8 colData)
{
    HC595_WriteByte(colData); // 595输出列数据
    SelectRow(row);           // 138选通当前行
    DelayUs(40);
    HC595_WriteByte(0x00);    // 消影防拖尾
    SelectRow(7);             // 选通第7行(或者关闭全部行)
}

/* ================================================================
*                      I2C通信函数
* ================================================================ */
void IIC_Start(void)
{
    SCL = 1; SDA = 1; SDA = 0; SCL = 0;
}
void IIC_Stop(void)
{
    SDA = 0; SCL = 1; SDA = 1;
}
void IIC_SendByte(u8 byte)
{
    u8 i;
    for(i = 0; i < 8; i++)
    {
        SDA = (byte & (0x80 >> i)) ? 1 : 0;
        SCL = 1; SCL = 0;
    }
}
bit IIC_ReceiveAck(void)
{
    u8 i = 0; SDA = 1; SCL = 1;
    while(SDA) { i++; if(i > 200) { SCL = 0; return 1; } }
    SCL = 0; return 0;
}
void IIC_SendAck(bit ack)
{
    SDA = ack; SCL = 1; SCL = 0;
}
u8 IIC_ReadByte(void)
{
    u8 i, dat = 0; SDA = 1;
    for(i = 0; i < 8; i++)
    { dat <<= 1; SCL = 1; if(SDA) dat |= 1; SCL = 0; }
    return dat;
}

/* ================================================================
*                    EEPROM读写函数
* ================================================================ */
void EEPROM_WritePage(u8 addr, u8 bytes[], u8 len)
{
    u8 i; IIC_Start();
    IIC_SendByte(EEPROM_ADDR_WRITE); IIC_ReceiveAck();
    IIC_SendByte(addr);
    IIC_ReceiveAck();
    for(i = 0; i < len; i++)
     {
        IIC_SendByte(bytes[i]);
         IIC_ReceiveAck();
        }
    IIC_Stop();
    DelayMs(10);
}
void EEPROM_ReadBytes(u8 addr, u8 bytes[], u8 len)
{
    u8 i; IIC_Start();
    IIC_SendByte(EEPROM_ADDR_WRITE);
    IIC_ReceiveAck();
    IIC_SendByte(addr);
    IIC_ReceiveAck();
    IIC_Start();
    IIC_SendByte(EEPROM_ADDR_READ);
    IIC_ReceiveAck();
    for(i = 0; i < len; i++)
    {
        bytes[i] = IIC_ReadByte();
        if(i < len - 1) IIC_SendAck(0);
        else IIC_SendAck(1);
    }
    IIC_Stop();
}
void Int_EEPROM_WriteBytes(u8 addr, u8 bytes[], u8 len)
{
    u8 page_remain, offset = 0, cur_addr = addr;
    if(len == 0) return;
    while(offset < len)
    {
        page_remain = PAGE_SIZE - (cur_addr % PAGE_SIZE);
        if(len - offset <= page_remain)
        { EEPROM_WritePage(cur_addr, bytes + offset, len - offset); offset = len; }
        else
        { EEPROM_WritePage(cur_addr, bytes + offset, page_remain); DelayMs(10); offset += page_remain; cur_addr += page_remain; }
    }
}

/* ================================================================
*          矩阵按键扫描(彻底移除死循环,不再卡死屏幕)
* ================================================================ */
u8 KeyScan(void)
{
    P1 = 0xF0; DelayMs(1);
    if((P1 & 0x0F) == 0x0F) return KEY_NONE;
    DelayMs(20);
    if((P1 & 0x0F) == 0x0F) return KEY_NONE;

    // ★ 已经把所有的 while(COL1==0); 删除了,按什么键都不会卡死 ★
    P1 = 0x70; DelayMs(1);
    if(COL1 == 0) return KEY_1;
    if(COL2 == 0) return KEY_2;
    if(COL3 == 0) return KEY_3;
    if(COL4 == 0) return KEY_A;

    P1 = 0xB0; DelayMs(1);
    if(COL1 == 0) return KEY_4;
    if(COL2 == 0) return KEY_5;
    if(COL3 == 0) return KEY_6;
    if(COL4 == 0) return KEY_B;

    P1 = 0xD0; DelayMs(1);
    if(COL1 == 0) return KEY_7;
    if(COL2 == 0) return KEY_8;
    if(COL3 == 0) return KEY_9;
    if(COL4 == 0) return KEY_C;

    P1 = 0xE0; DelayMs(1);
    if(COL1 == 0) return KEY_STAR;
    if(COL2 == 0) return KEY_0;
    if(COL3 == 0) return KEY_POUND;
    if(COL4 == 0) return KEY_D;

    return KEY_NONE;
}

/* ================================================================
*                          主函数
* ================================================================ */
void main(void)
{
    u8 keyValue = KEY_NONE, lastKey = KEY_NONE;
    u8 eepromData[16] = {0};
    u8 i, row;
    u8 frameBuf[8] = {0};

    // 硬件初始化
    SCL = 1; SDA = 1;
    SER_595 = 0; SRCLK_595 = 0; RCLK_595 = 0;
    P1  = 0xFF;

    // ★ 解决每次按电源键灯随机闪:刚上电先把点阵全灭并延时200毫秒 ★
    HC595_WriteByte(0x00);
    SelectRow(0);
    DelayMs(200);

    // 上电读取EEPROM
    EEPROM_ReadBytes(0x00, eepromData, 4);

    while(1)
    {
        // 1. 扫描按键(不会卡死屏幕)
        keyValue = KeyScan();
        if(keyValue != KEY_NONE && keyValue != lastKey)
        {
            lastKey = keyValue;
            eepromData[0] = keyValue;
            switch(keyValue)
            {
                case KEY_0: Int_EEPROM_WriteBytes(0x00, eepromData, 4); break;
                case KEY_1: displayMode = 1; dispCnt = 0; scrollOff = 0; break;
                case KEY_2: displayMode = 2; dispCnt = 0; scrollOff = 0; break;
                case KEY_A: for(i=0;i<4;i++) eepromData[i=0; Int_EEPROM_WriteBytes(0x00, eepromData, 4); break;
            }
        }
        if(keyValue == KEY_NONE) lastKey = KEY_NONE;

        // 2. 点阵刷屏逻辑
        if(displayMode == 1)
        {
            if(dispCnt < 200) memcpy(frameBuf, OK_Logo, 8);
            else memcpy(frameBuf, OK_Logo+8, 8);
            
            for(row=0; row<8; row++) Matrix_ScanOneLine(row, frameBuf[row]);
            dispCnt++;
            if(dispCnt >= 400) dispCnt = 0;
        }
        else if(displayMode == 2)
        {
            memset(frameBuf, 0, 8);
            for(i=0;i<8;i++) if((scrollOff+i) < 40) frameBuf[i] = HELLO_Logo[scrollOff+i];
            for(row=0; row<8; row++) Matrix_ScanOneLine(row, frameBuf[row]);
            
            dispCnt++;
            if(dispCnt > 30)
            {
                dispCnt = 0;
                scrollOff++;
                if(scrollOff >= 48) scrollOff = 0;
            }
        }
        else
        {
            // 空闲状态直接关闭点阵
            HC595_WriteByte(0x00);
            SelectRow(0);
        }
    }
}


鹿小班51开天原理图.pdf

1001.32 KB, 下载次数: 1

回复

使用道具 举报

0

主题

107

帖子

0

精华

高级会员

Rank: 4

积分
545
金钱
545
注册时间
2026-1-29
在线时间
37 小时
发表于 11 小时前 | 显示全部楼层
从你描述的现象和代码来看,问题可能出现在多个模块的初始化、硬件连接、驱动函数或资源冲突等方面。以下是针对你的现象进行的详细分析与排查步骤,帮助你定位并解决问题。

一、现象拆解与初步判断
1. 数码管:第一个数字亮,其他数字闪烁
原因可能:
数码管位选信号异常:只有第一位被持续选中,其他位选信号未正确切换。
段选信号驱动问题:段码未正确输出,或者驱动芯片(如74HC595或74HC138)未正常工作。
数码管驱动电路电源/接地问题:导致某些位无法稳定点亮。
刷新频率问题:如果是动态扫描,刷新频率不对会导致部分位闪烁。
2. LED流水灯(d3d4d5一直闪烁)
原因可能:
流水灯驱动IO口存在干扰或软件逻辑错误:导致这部分LED不受控,持续闪烁。
软件冲突:可能有多个任务同时操作了同一个端口,导致状态不稳定。
3. 8×8点阵模块完全没有亮
原因可能:
8×8点阵驱动(如74HC595)未正确初始化或数据未正确发送。
74HC595的时钟、数据、锁存信号连接错误或未连接好。
点阵模块供电不足或连接松动。
代码中点阵显示函数未正确调用或循环逻辑有问题。
4. 按键无反应
原因可能:
矩阵按键扫描程序存在逻辑错误或IO口配置错误。
按键硬件连接有问题(如上拉电阻未接、按键引脚未初始化为输入)。
按键扫描被阻塞或优先级过高的其他任务抢占了CPU资源,导致按键无法及时响应。
二、代码层面排查
1. 硬件初始化检查
确保所有与数码管、LED流水灯、8×8点阵、按键相关的IO口在系统启动时已正确初始化。尤其是矩阵按键的行列引脚,必须设置为正确的输入输出模式。

2. 74HC595驱动函数
你的代码中 HC595_WriteByte 用于驱动74HC595,但这个函数只发送一个字节。点阵显示通常需要同时控制行和列,可能需要多个74HC595级联。

建议检查:

确认级联数量是否正确。
确认所有时钟、数据、锁存信号连接正确。
确认在主循环中正确调用了刷新函数。
示例级联发送两个字节(行+列)的驱动函数:

      

void HC595_SendTwoBytes(u8 dat1, u8 dat2)
{
    u8 i;
    SRCLK_595 = 0;
    RCLK_595 = 0;
    for(i = 0; i < 8; i++)
    {
        SER_595 = (dat1 >> 7) & 0x01;
        dat1 <<= 1;
        SRCLK_595 = 1;
        DelayUs(1);
        SRCLK_595 = 0;
    }
    for(i = 0; i < 8; i++)
    {
        SER_595 = (dat2 >> 7) & 0x01;
        dat2 <<= 1;
        SRCLK_595 = 1;
        DelayUs(1);
        SRCLK_595 = 0;
    }
    RCLK_595 = 1;
    DelayUs(1);
    RCLK_595 = 0;
}

      
3. 数码管驱动逻辑
数码管一般采用动态扫描,确保你正确实现了动态扫描函数,并且刷新频率合理(一般在50Hz以上,防止闪烁)。

检查点:

位选信号是否在每个数码管之间切换。
段选信号是否正确发送。
数码管公共端(共阴/共阳)和驱动电路是否匹配。
4. 8×8点阵驱动逻辑
点阵显示通常采用行列扫描,确保你正确控制了行列信号。

示例点阵刷新函数:

      
void Matrix8x8_Refresh(u8 row, u8 col)
{
    u8 i;
    // 清除所有行
    HC595_SendTwoBytes(0x00, 0xFF); // 假设第一字节控制列,第二字节控制行
    DelayUs(1);
    // 选中当前行
    HC595_SendTwoBytes(OK_Logo[row] | (1 << col), row);
    // 这里假设OK_Logo是存储的列数据,行通过移位选择
    DelayUs(1);
}

      
5. 矩阵按键扫描逻辑
确保矩阵按键扫描正确,按键扫描应放在主循环中,并去抖。

建议检查:

行列引脚初始化正确(行输出高,列输入上拉)。
扫描逻辑是否正确,比如逐行扫描,检测列是否有按下。
按键消抖延时是否合理。
示例按键扫描函数:


u8 Matrix_KeyScan()
{
    u8 key = KEY_NONE;
    ROW1 = 0; ROW2 = ROW3 = ROW4 = 1;
    if(COL1 == 0) { DelayMs(10); if(COL1 == 0) key = KEY_1; }
    if(COL2 == 0) { DelayMs(10); if(COL2 == 0) key = KEY_2; }
    if(COL3 == 0) { DelayMs(10); if(COL3 == 0) key = KEY_3; }
    if(COL4 == 0) { DelayMs(10); if(COL4 == 0) key = KEY_4; }
    // 继续其他行扫描
    return key;
}

      
6. 主循环逻辑与资源冲突
检查主循环中是否同时运行了多个任务(数码管刷新、LED流水灯、点阵刷新、按键扫描)而没有合理调度,导致任务互相抢占资源。

建议:

使用状态机或分时复用机制,确保每个任务有合理的时间片。
避免长时间阻塞操作,如长时间延时,会阻塞其他任务。
三、硬件层面排查
1. 连接检查
74HC595连接:检查SER、SRCLK、RCLK是否正确连接到对应的IO口。
数码管连接:确认段选和位选信号连接正确,特别是共阴/共阳选择。
点阵连接:确认行列连接正确,没有反接。
按键连接:检查行列连接是否正确,按键的上拉电阻是否接好。
2. 电源与接地
确保所有模块的电源和接地连接良好,特别是点阵模块和数码管可能需要较大电流,电源不足会导致工作异常。
检查是否有虚焊或接触不良的问题。
3. 模块独立测试
单独测试74HC595:编写一个简单的测试程序,控制74HC595输出特定数据,确认74HC595本身没有问题。
单独测试数码管:编写程序只驱动数码管,确认数码管显示正常。
单独测试点阵:编写程序只驱动点阵模块,确认点阵能正常显示。
单独测试按键:编写程序只扫描按键,确认按键输入正常。
四、具体建议与解决方案
1. 简化程序,逐步调试
步骤1:只点亮数码管,确认数码管驱动正常。
步骤2:只驱动LED流水灯,确认流水灯控制正常。
步骤3:只驱动8×8点阵,确认点阵显示正常。
步骤4:只进行按键扫描,确认按键输入正常。
步骤5:逐步增加功能,确保每个模块在集成后仍能正常工作。
2. 增加调试输出
使用简单的LED或串口输出,标记各个模块的工作状态,帮助判断问题出在哪个环节。
3. 检查中断和延时
确保没有中断冲突,尤其是定时器中断可能影响到扫描任务。
避免在主循环中使用长时间的延时,导致其他任务无法执行。
4. 优化刷新逻辑
使用定时器中断进行动态刷新,例如定时2ms进行数码管和点阵刷新,保证刷新频率稳定。
主循环只进行按键扫描和状态处理,提高响应速度。
五、示例优化后的主循环结构
      

void main()
{
    // 初始化所有硬件,包括数码管、点阵、按键、LED等
    // 初始化定时器中断用于动态刷新
    while(1)
    {
        u8 key = Matrix_KeyScan();
        if(key != KEY_NONE)
        {
            // 按键处理逻辑
        }
        // 处理其他状态逻辑
        // 确保主循环不阻塞,有较短的延时即可
        DelayMs(10);
    }
}

// 定时器中断函数
void Timer0_ISR(void) interrupt 1
{
    TH0 = 0xFC;
    TL0 = 0x66; // 定时2ms
    // 数码管刷新
    // 点阵刷新
    // LED流水灯刷新
}

      
六、总结
综合你的现象,问题主要集中在以下几个方面:

硬件连接和驱动芯片(74HC595)驱动不正常,导致点阵不亮和数码管异常。
软件逻辑中各模块未合理调度,导致资源冲突和任务阻塞,尤其是按键无响应。
初始化和刷新机制存在缺陷,导致模块无法正常稳定工作。
通过逐步排查硬件、优化软件逻辑、增加调试手段,你可以逐步定位问题根源并解决。建议先从硬件连接和单一模块的独立测试入手,确保每个模块功能正常后再集成,以确保系统整体稳定运行。
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-8-4 23:21

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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