LED基本原理

Tutorial: 电子电路 Category: 嵌入式 Published: 2026-08-29 08:09:36 Views: 1 Likes: 0 Comments: 0

031.2.1 LED基本原理

#include "reg52.h"
#include <intrins.h>

sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;

int i;

void Delay1000ms(void) //@11.0592MHz
{
    unsigned char data i, j, k;

    _nop_();
    i = 8;
    j = 1;
    k = 243;
    do
    {
        do
        {
            while (--k);
        } while (--j);
    } while (--i);
}

void main()
{
    while(1)
    {
//      P1 = 0xfe; //11111110
//      Delay1000ms();
//      P1 = 0xfd; //11111101
//      Delay1000ms();
//      P1 = 0xfb; //11111011
//      Delay1000ms();
//      P1 = 0xf7; //11110111
//      Delay1000ms();

//      P1 = 0xff;
//      Delay1000ms();
//      for(i=0; i<4; i++)
//      {
//          P1 = P1 << 1;
//          Delay1000ms();
//      }

//      LED1 = 0;
//      LED3 = 0;
//      Delay1000ms();
//      LED1 = 1;
//      LED3 = 1;
//      Delay1000ms();

        LED2 = ~LED2;
        LED4 = ~LED4;
        Delay1000ms();
    }
}

一、硬件知识

  • 本节演示单片机的引脚输出:开发板上的四个蓝色 LED 按约 1 秒的间隔依次点亮,看起来像灯光在流动。要理解代码,必须先弄清 LED 的方向、限流电阻、P1 端口以及“低电平点亮”的含义。
  • 配套 2LED/main.c 的完整源码列在标题下方。课程先演示其中第一段流水灯写法;源码还保留了循环移位、位操作和 LED2/LED4 同步闪烁写法,其中被 // 注释的语句不会参与当前编译。

1.1 发光二极管

  • LED 是 Light Emitting Diode(发光二极管)的缩写。它首先是二极管,具有明显方向性;在允许的正向电流流过时才发光。
  • LED 的两个电极应称为阳极 A(Anode)阴极 K(Cathode)。正常点亮时,电流从阳极流入、从阴极流出,即 A → K。原理图中的二极管竖线一端代表阴极。
阳极 A                         阴极 K
  ────────────────|>|──────────────
                   ↗ ↗
                 发出的光

正常点亮方向:较高电位 → A → LED → K → 较低电位
  • LED 不能只看“两端有电压”就判断会亮,还要同时满足:方向接对、正向压差足够、存在闭合回路、电流受到限制。如果反接,通常不会亮;LED 的允许反向电压往往不高,不能随意长期反向加压。
  • 视频建议通过百科资料扩展 LED 的理论与应用。实际选型和设计时,更可靠的依据是具体 LED 型号的数据手册,其中会给出正向压降、推荐电流、最大反向电压、亮度、波长、功耗和封装尺寸。
1.1.1 贴片LED
  • 本开发板的四个用户 LED 是贴片 LED,原理图标为 LED1~LED4、0805_B0805 表示贴片封装规格,B 表示蓝色。贴片器件直接焊在 PCB 表面,体积小、适合机器装配。
  • 视频还列举了 0402、0603、0805、1206 等常见贴片封装。数字越大,器件通常越大,但这些代号采用英制尺寸习惯,不能直接当作毫米数读取。例如 0805 约为 2.0mm × 1.25mm。
  • 贴片 LED 仍然分阳极和阴极,但不同厂家可能使用缺角、绿点、色带、底部符号等不同极性标记。不能只背一种外观,应同时查看 PCB 丝印、原理图和器件数据手册,必要时用万用表二极管挡确认。
  • “封装不同、原理相同”指二者都利用半导体结的电致发光效应,不表示所有参数都相同。不同封装的允许电流、散热、亮度、视角和焊接方式可能差别很大。
1.1.2 直插LED
  • 直插 LED 通常有两根金属引脚,可插入面包板或通孔 PCB。新器件且引脚尚未剪短时,一般可用以下方法判断极性:
观察位置阳极 A(正极)阴极 K(负极)
引脚长度较长较短
内部金属电极通常较小通常较大,像“小碗”
塑料外壳边缘通常为圆边常有一处平边
  • 引脚一旦被剪齐,“长正短负”的方法就失效;透明或特殊封装的内部结构也可能不易观察。最稳妥的方法是查数据手册,或用万用表二极管挡低电流测试:表笔方向正确时 LED 可能微亮,同时显示正向压降。
  • 对普通单向 LED,可用“阳极/阴极”判断方向。视频中的“所有二极管都分正负极”适合作为入门记忆,但工程上还存在双向 TVS、交流指示灯组件等特殊器件,仍应以具体符号和手册为准。

1.2 电阻

  • LED 的伏安特性很陡:超过正向导通电压后,电流可能因很小的电压变化而迅速增大。因此不能把普通 LED 直接跨接在 5V 与 GND 之间,必须使用串联电阻或恒流驱动器限制电流。
  • 本板四路用户 LED 的连接完全相同:LED1~LED4 分别串联 R8~R11(10kΩ),再连接 P1.0~P1.3。LED 阳极侧接 +5V,单片机引脚位于阴极一侧,所以它们是低电平点亮、低电平有效
开发板 LED1 的实际回路

+5V ──► LED1(A → K)──► R8 10kΩ ──► P1.0 ──► MCU 内部下拉管 ──► GND
                                              │
                                  P1.0 = 0 时导通并吸收电流
  • P1.0 输出低电平时,LED 左侧约为 +5V,右侧经 R8 和单片机输出级接近 GND,形成 +5V → LED → R8 → P1.0 → GND 的闭合回路,LED 点亮。这里常说引脚“吸收”或“灌入”电流,更准确的英文概念是 sink current(灌电流/吸电流)
  • P1.0 输出高电平时,引脚也接近 +5V,LED 两端几乎没有足够的正向压差,电流接近零,LED 熄灭。因此不能只凭“输出 1 就是开、输出 0 就是关”判断外设状态,必须先读电路连接方式。
P1.x 输出LED 阳极电位LED 阴极侧电位是否形成明显正向压差LED 状态
0,约 0V+5V接近 0V
1,接近 +5V+5V接近 +5V
  • 忽略引脚低电平残余电压时,LED 电流可粗略估算为 I_LED ≈ (5V - V_F) / 10kΩ。若蓝色 LED 的正向压降约为 3V,则电流约为 0.2mA。实际电流还受 LED 批次、温度和 P1.x 输出电压影响。
  • 设计其他 LED 电路时,可按 R ≈ (V_CC - V_F - V_OL) / I_LED 初步选择电阻,再校验 LED、I/O 引脚和电阻功耗是否满足手册限制。电阻越小,电流通常越大;不能为了更亮无限减小电阻。
  • 高电平点亮采用相反的供电位置:单片机引脚从高电平向外提供电流,LED 阴极最终接 GND,这叫 source current(拉电流/源电流)
低电平点亮(本开发板)               高电平点亮(视频中的对比电路)

+5V ─ LED ─ R ─ P1.0              P1.5 ─ R ─ LED ─ GND
                    │                 │
           P1.0=0 时亮              P1.5=1 时亮

前者由 MCU 引脚吸收电流;后者由 MCU 引脚提供电流。
  • 电流不仅需要电压差,还需要闭合回路。水压差与水流的类比可以帮助入门,但电压是两点间的电势差,本身不会像水一样“流动”;真正沿闭合回路运动的是电荷形成的电流。

二、代码编写

  • 本节代码的目标是通过 P1 寄存器改变 P1.0~P1.3 的高低电平,从而控制四个低电平有效 LED。整体关系为:
C 语句写 P1 寄存器
        │
        ▼
P1 锁存器的 8 个数据位
        │
        ├── bit0 ──► P1.0 ──► LED1
        ├── bit1 ──► P1.1 ──► LED2
        ├── bit2 ──► P1.2 ──► LED3
        ├── bit3 ──► P1.3 ──► LED4
        └── bit4~bit7 ──► P1.4~P1.7

2.1 引脚控制

  • 对本实验所用的 P1 口,可先按课程模型理解:向对应寄存器位写 1,引脚接近高电平;写 0,引脚内部下拉晶体管导通,把引脚拉向 GND。
                P1.x 的简化输出模型

                       +5V
                        │
                 弱上拉/输出结构
                        │
P1 锁存位 ──► 控制逻辑 ─┼────────► P1.x 引脚
                        │
                 下拉晶体管开关
                        │
                       GND

写 1:下拉关闭,引脚被拉高;写 0:下拉导通,引脚被强力拉低。
  • 真实 8051 端口并不是所有口、所有模式都等价于理想推挽输出。例如经典 P0 口通常为开漏结构,作为普通 I/O 输出高电平时需要外部上拉;本板的 RN1、RN2 正是 P0 口的上拉排阻。P1 口适合本节的直接输出实验。
  • 软件开发者不必在第一节课就掌握 I/O 单元的所有晶体管,但必须理解三个工程概念:高低电平有允许范围、引脚能提供或吸收的电流有限、外部电路决定逻辑是高有效还是低有效。

2.2 寄存器

  • P0、P1、P2、P3 都是 8 位特殊功能寄存器,每一位与相应端口引脚对应。例如 P1 的 bit0~bit7 对应 P1.0~P1.7。
  • P0 与 P2 两个寄存器合计对应 16 个端口位;P1 与 P3 也合计对应 16 个端口位。P3.0、P3.1 在板上还承担 RXD、TXD 串口复用功能,所以实物位置可能与 P3.2~P3.7 分开。
  • 四个 8 位端口寄存器共有 32 个数据位,但不能简单认为任何型号都一定提供 32 个完全独立、没有复用功能的普通引脚;还要看芯片封装、P4 扩展口以及各引脚的第二功能。
  • 本节只需控制 P1 的低四位:
P1 位物理引脚网络板载负载写 0写 1
bit0P1.0LED1
bit1P1.1LED2
bit2P1.2LED3
bit3P1.3LED4
  • 给 P1 一次赋一个 8 位数,会同时更新 8 个端口位。位序从右向左是 bit0~bit7,因此二进制数最右边的一位控制 P1.0,而不是最左边的一位。

2.3 写代码

  • 视频通过复制已有 Keil 工程建立 2LED 工程,这样可保留芯片、启动文件、晶振和输出文件等配置。复制后必须确认工程路径、目标芯片与输出 HEX 文件确实属于新工程,避免修改 A 工程却烧录 B 工程。

  • 8051 复位后先执行启动文件中的初始化代码,再进入 main,因此从应用程序角度可以把 main 理解为主要入口,但它并不是 CPU 复位后执行的第一条机器指令。

  • 程序必须包含 reg52.h,其中声明了 P0、P1 等 51 特殊功能寄存器;否则编译器会报告 P1: undefined identifier 或类似错误。

  • 配套延时函数调用 _nop_(),它由 Keil C51 的 intrins.h 声明。缺少该头文件时,编译器会报告:

    '_nop_': missing function-prototype / '_nop_': declaration/activation error

    解决方法就是加入源码第二行的 #include <intrins.h>。出现编译错误时不会生成新的有效 HEX 文件,必须先修复并重新编译,不能继续烧录旧文件冒充新结果。

2.3.1 示例代码
  • 视频首先写出 P1 = 0xff;0x 表示十六进制,每个十六进制位对应 4 个二进制位;F = 15 = 8 + 4 + 2 + 1,所以:

    0xFF = 1111 1111B

  • P1 的 8 位全为 1,P1.0~P1.3 都输出高电平。由于本板 LED 低电平点亮,四个用户 LED 此时全部熄灭。

  • 把数据改为 0xFE 后:

    0xFE = 1111 1110B

    只有 bit0 为 0,即 P1.0 输出低电平,所以只有 LED1 点亮。

  • 配套源码顶部还用 sbit 分别为 P1.0~P1.3 定义了 LED1~LED4。sbit LED1 = P1^0; 中的 ^ 是 Keil C51 的位地址语法,不是普通 C 表达式中的异或运算。

  • 当前配套源码最后实际参与编译的是 LED2 = ~LED2;LED4 = ~LED4;,作用是每隔约 1 秒翻转 LED2、LED4 的状态,使它们同步闪烁。上方由 // 开头的几组代码均为注释,用于保留不同实验写法,不会同时执行。

2.3.2 烧写程序
  • 在 Keil 中修改代码后,先执行编译/构建,并检查 Build Output。只有确认 0 Error(s) 且 HEX 文件更新时间与本次编译相符,才进入下载软件。
  • 下载软件中选择与实物一致的 STC89C52RC 系列型号和正确串口。串口号应与 Windows 设备管理器中 CH340 对应的 COM 口一致,不能照抄视频中的端口号。
  • 点击“打开程序文件”选择 2LED 工程最新生成的 HEX 文件,再点击“下载/编程”。若板载自动下载电路未触发,可按软件提示重新上电;成功后再观察 LED,而不是只看下载按钮是否点过。
  • P1 = 0xFF 烧入后四灯全灭、P1 = 0xFE 烧入后 LED1 点亮,正好反向验证了原理图中的低电平有效连接。若现象相反,应优先核对是不是另一种开发板或不同 LED 接法。
  • 常见的“代码改了但现象没变”原因包括:编译失败后仍烧录旧 HEX、选错工程输出文件、串口选择错误、下载未完成、板子未重新上电,以及代码修改处仍被 // 注释。
2.3.3 应用案例
  • 流水灯的本质不是“同时让灯亮”,而是让唯一的低电平位按 P1.0 → P1.1 → P1.2 → P1.3 的顺序移动,并在每个状态之间保留人眼可见的时间。
  • 四个关键数据如下:
P1 十六进制值二进制值为 0 的端口位点亮的 LED
0xFE1111 1110P1.0LED1
0xFD1111 1101P1.1LED2
0xFB1111 1011P1.2LED3
0xF71111 0111P1.3LED4
  • 十六进制转换应以每 4 位二进制为一组:1110 = E1101 = D1011 = B0111 = 7,所以四个状态依次是 FE、FD、FB、F7。只观察低四位可以说明四盏 LED 的状态;书写完整 P1 值时,还必须保留高四位 1111
2.3.3.1 例题: 流水灯效果实现
  • 把四次赋值放入 while (1),程序执行完 LED4 后会回到 LED1,形成无限循环。嵌入式主程序通常需要持续响应硬件,因此常见永久循环;但并非所有 MCU 程序都只能用这一种结构,事件、中断和操作系统任务也是常见实现方式。
        ┌──────────────────────────────────────┐
        │                                      │
        ▼                                      │
P1=0xFE ─延时→ P1=0xFD ─延时→ P1=0xFB ─延时→ P1=0xF7 ─延时
 LED1亮          LED2亮          LED3亮          LED4亮
  • 如果没有延时,51 单片机会在极短时间内反复切换四个状态。由于视觉暂留,人眼可能觉得多个灯同时常亮,无法分辨顺序;这不是赋值没有生效,而是刷新速度远高于人眼可辨速度。
  • 视频使用下载软件自带的延时计算器,在 11.0592MHz、STC89 指令集条件下生成 Delay1000ms()。这类函数通过 CPU 空循环消耗时间,属于忙等待:延时期间 CPU 不能做其他工作,精度还会受时钟、指令周期、编译器和优化设置影响,适合入门演示,不适合高精度或多任务场景。
  • 调用函数时写 Delay1000ms();,不能写成 void Delay1000ms();。前者是执行函数,后者在语法上是函数声明;每条调用语句末尾要有分号。
  • 使用包含 _nop_() 的延时函数时必须同时包含 <intrins.h>,否则编译会失败。加入该头文件并重新编译,确认错误数为零后,才能生成可供烧录的 HEX 文件。
  • 后续可用定时器中断代替软件忙等待:定时器周期到达时再切换 LED,主循环可以同时处理按键、串口等任务。其工作关系可先理解为:
硬件定时器计数 ──► 到达设定时间 ──► 产生中断 ──► 切换下一个 LED
       ▲                                             │
       └──────────────── 重新计时 ◄──────────────────┘

主循环在等待期间仍可执行其他任务,不必卡在空循环中。