[经验分享] 51单片机中断系统与8×8 LED点阵扫描显示

[复制链接]
247|0
八层楼 发表于 2025-10-13 13:18 | 显示全部楼层 |阅读模式
一、51单片机引脚位操作 —— sbit 关键字
作用
sbit 是专用于 51 单片机架构的 C 语言扩展关键字,用于定义特殊功能寄存器(SFR)中的某一位,从而实现对单个 I/O 引脚的直接位操作。

示例代码
#include <reg51.h>  // 包含51单片机寄存器定义头文件

// 定义74HC595芯片控制引脚
sbit SER   = P3^4;    // 串行数据输入引脚,连接P3.4
sbit RCLK  = P3^5;    // 存储寄存器时钟引脚,连接P3.5
sbit SRCLK = P3^6;    // 移位寄存器时钟引脚,连接P3.6


SER = P3^4:将 P3 端口第 4 位(即 P3.4 引脚)命名为 SER,后续可直接用 SER = 1; 或 SER = 0; 控制电平。
RCLK = P3^5:控制 74HC595 的存储寄存器锁存时钟。
SRCLK = P3^6:控制 74HC595 的移位寄存器时钟。

应用场景:精准控制单个引脚,如驱动外设芯片、LED、按键检测等。

二、74HC595 串转并芯片工作原理
功能概述
74HC595 是一个 8 位串行输入、并行输出的移位寄存器芯片,通过 3 根控制线(SER、SRCLK、RCLK)即可控制 8 路输出,极大节省单片机 I/O 资源。

关键引脚说明



行选通函数实现
/**
* 选择8*8点阵的行
* @param num 要选择的行号(0-7)
* 通过74HC595串行输入数据,控制对应行的选通
*/
void led_rect_select(unsigned char num)
{
        unsigned char i = 0;
        RCLK = 0;  // 拉低存储寄存器时钟,准备接收数据
        SRCLK = 0; // 拉低移位寄存器时钟,准备移位操作
       
        // 循环8次,串行输入8位数据
        for(i = 0; i < 8; i++)
        {
                SRCLK = 0;  // 拉低移位时钟,准备输入数据
                // 当i等于要选择的行号时,SER置1,否则置0
                (num == i) ? (SER = 1) : (SER = 0);
                SRCLK = 1;  // 拉高移位时钟,将SER数据移入移位寄存器
        }
        RCLK = 1;  // 拉高存储寄存器时钟,将移位寄存器数据锁存到输出寄存器
}



运行理想结果:调用 led_rect_select(3) 时,74HC595 输出端口第 3 位为高电平,其余为低,即选通第 3 行 LED。
三、8×8 LED点阵扫描显示原理
硬件结构
8 行 × 8 列共 64 个 LED,采用“行选通 + 列数据”方式控制。
本例使用共阴极点阵:行选通为低电平有效,列数据为高电平时对应 LED 点亮。
逐行扫描 + 视觉暂留
原理:每次只选通一行,输出该行的列数据,快速循环扫描 8 行(每行约 1ms),利用人眼视觉暂留效应(约 10~20ms)形成完整稳定图像。
优势:节省 I/O 资源,仅需 3 个引脚(74HC595)控制 8 行 + 8 个引脚(P0)控制 8 列。
显示函数实现
/**
* 在8*8点阵上显示图案
* 通过逐行扫描的方式,显示预设的图案(此处为数字"1")
*/
void led_8_8_show(void)
{
        // 存储8*8点阵每行要显示的数据,对应显示数字"1"
        unsigned char led_1_array[8] = {0x0, 0x10, 0x30, 0x10, 0x10, 0x10, 0x38, 0x0};
           unsigned char i = 0;

        // 逐行扫描显示
        for(i = 0; i < 8; i++)
        {         
                P0 = 0xff;  // 关闭当前行显示,避免串扰(共阴极,全高电平熄灭)
                led_rect_select(i);  // 选择第i行
                P0 = ~led_1_array;  // 输出第i行的列数据(取反是因为共阴极点阵:数据1=高电平=点亮)
                delay(1);  // 延时1ms,保持当前行显示,利用视觉暂留形成稳定图像
        }
}





图案数组说明:
led_1_array[8] = {0x0, 0x10, 0x30, 0x10, 0x10, 0x10, 0x38, 0x0};
例如 0x10 = 00010000B,表示该行第 5 列 LED 点亮。
取反原因:共阴极点阵中,列需输出高电平才能点亮 LED,而数组中 1 表示“点亮”,故需 ~ 取反后送 P0 口。
理想运行结果:点阵稳定显示数字“1”的图案。
四、延时函数实现与作用
功能
通过空循环消耗 CPU 时间,实现软件延时,用于控制扫描频率、稳定显示亮度。

实现代码
/**
* 延时函数
* @param i 延时参数,控制延时时间长短
* 通过双重循环实现延时,外层循环10次,内层循环由i控制
*/
void delay(unsigned int i)
{
        unsigned int num = i;
        int j = 0;
        for(j = 0; j < 10; j++)
        {
                num = i;
                while(num--);  // 内层循环,通过递减计数实现延时
        }
}






调节方式:增大 i 值可延长延时。
应用场景:
点阵扫描中,每行延时约 1ms(delay(1)),总周期约 8ms,刷新率约 125Hz,远高于视觉暂留阈值(约 50Hz),显示稳定无闪烁。
延时过短 → 亮度不足;过长 → 闪烁明显。
五、数组在硬件控制中的应用
1. 数码管段码数组(备用)
/**
* 共阴极数码管段码数组
* 索引0-9分别对应数字0-9的十六进制段码
*/
unsigned char digit_data[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};


虽未在主逻辑中使用,但体现“用数组存储固定硬件控制数据”的设计思想。
2. 点阵图案数组
unsigned char led_1_array[8] = {0x0, 0x10, 0x30, 0x10, 0x10, 0x10, 0x38, 0x0};


每个元素对应一行 LED 的亮灭状态。
修改数组即可切换显示图案,如改为 0x7F, 0x49, 0x49, 0x49, 0x36, 0x0, 0x0, 0x0 可显示字母“E”。
六、中断系统详解
中断基本概念
中断源:引起中断产生的事件(如外部信号、定时器溢出、串口接收完成等)。
中断服务程序(ISR):中断产生后 CPU 跳转执行的处理函数。
程序计数器(PC):指向当前执行指令地址,中断发生时自动压栈保存,中断返回时恢复。
中断系统作用
使 CPU 具备实时响应外部紧急事件的能力,提高系统效率与实时性。

中断响应流程
当前指令执行完毕。
PC 值压入堆栈。
现场保护(可选,由程序员实现)。
屏蔽同级/低级中断。
PC 装载中断向量地址(跳转至 ISR)。
执行中断服务程序。
RETI 指令返回:恢复 PC,恢复中断设置,继续原程序。

中断服务程序特点:无参数、无返回值、执行要快、尽量简短。

七、STC89C51RC/RD+ 中断系统特性
中断源(共8个)



中断优先级
支持 4 级优先级(通过 IPH 寄存器设置)。
若仅使用 IP 或 XICON,则为传统 8051 的 2 级优先级。
高优先级可打断低优先级 → 支持中断嵌套。
同级中断按查询次序响应。
中断控制寄存器
EA (IE.7):总中断允许位,置 1 开启全局中断。
EX0 (IE.0):外部中断 0 允许位。
IT0 (TCON.0):外部中断 0 触发方式(0=低电平,1=下降沿)。
八、C语言中断编程示例
初始化与主函数
// 外部中断0初始化函数
void eint0_init(void)
{
    IT0 = 1;  // 设置外部中断0为边沿触发方式(下降沿触发)
    EX0 = 1;  // 使能外部中断0
    EA = 1;   // 使能总中断
}

// 主函数
void main(void)
{
    unsigned char i = 0;
    eint0_init();  // 调用外部中断0初始化函数
    while(1)  // 无限循环,等待中断发生
    {
        // 主程序可执行其他任务,中断发生时自动跳转处理
    }
}




中断服务程序(ISR)
// 外部中断0处理函数,interrupt 0 表示该函数为外部中断0的中断服务程序
void eint0_handler(void) interrupt 0
{
    P2 = 0xaa;  // 中断发生时,P2口输出0xAA(10101010B),控制外部LED或指示灯
}


interrupt 0:指定该函数为中断号 0(外部中断 0)的服务程序。
理想运行结果:当外部中断 0 引脚(P3.2)检测到下降沿,CPU 跳转执行 eint0_handler(),P2 口输出 0xAA,之后自动返回主循环。

注意:ISR 中避免使用延时函数或复杂操作,防止阻塞其他中断。

九、中断向量表与响应机制图示



中断向量表:包含各中断服务函数入口地址(如 fun0() interrupt 0 对应 0003H)。
CPU 响应中断时,根据中断源自动跳转至对应向量地址。



中断响应步骤:
当前指令执行完。
PC 压栈。
现场保护(程序员手动)。
屏蔽同级中断。
PC = 中断向量地址。
执行 ISR。
RETI 返回,恢复现场。



中断触发流程:中断源(如 eint0)→ CPU 查询中断向量表 → 跳转 ISR(如 eint0_handler())→ 执行 → RETI 返回。
十、总结
本节内容涵盖 51 单片机两大核心模块:

1. 硬件驱动层
使用 sbit 精准控制 I/O 引脚。
驱动 74HC595 实现串转并,节省 I/O。
8×8 LED 点阵逐行扫描 + 视觉暂留显示技术。
延时函数调节扫描频率。
数组存储硬件控制数据,便于图案切换。
2. 中断系统层
中断源、中断向量、中断优先级机制。
中断响应流程与现场保护。
C 语言中断服务程序编写规范(interrupt n)。
外部中断初始化与触发方式设置。
支持中断嵌套与多级优先级。
————————————————
版权声明:本文为CSDN博主「cellurw」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/oareen/article/details/151723819

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

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

本版积分规则

131

主题

4396

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部