新手入门
积分 4
金钱 4
注册时间 2026-8-3
在线时间 1 小时
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 );
}
}
}
我来回答