单片机跑马灯C语言程序如何实现?

99ANYc3cd6
预计阅读时长 19 分钟
位置: 首页 C语言 正文

硬件准备

在编写代码之前,你需要准备以下硬件:

单片机跑马灯程序c语言
(图片来源网络,侵删)
  1. 单片机最小系统板:包含STC89C52芯片、晶振(通常11.0592MHz或12MHz)、复位电路。
  2. LED灯:8个(或其他数量)。
  3. 电阻:8个,阻值通常为220Ω - 1kΩ,用于限流,防止LED烧坏。
  4. 杜邦线:若干,用于连接。
  5. 下载器:如CH340/CP2102模块,用于将程序烧录到单片机。

硬件连接图:

将8个LED的正极(长脚)通过限流电阻连接到单片机的 P0口 (P0.0, P0.1, ..., P0.7),LED的负极(短脚)连接到 GND(地)

      +5V
       |
     [电阻 R]
       |
P0.0 --|>|-- GND  (LED1)
P0.1 --|>|-- GND  (LED2)
...
P0.7 --|>|-- GND  (LED8)

注意:STC89C52的P0口是开漏输出,作为输出时通常需要外接上拉电阻才能正常驱动高电平,如果你的开发板已经集成了上拉电阻,则无需额外处理,如果没有,你可以在P0口和VCC之间接一个排阻(如10kΩ)。


程序实现

我们将从最基础的代码开始,逐步优化。

单片机跑马灯程序c语言
(图片来源网络,侵删)

基础版 - 逐个点亮,不带延时函数

这个版本最直观,通过循环依次让每个LED亮起,然后熄灭。

#include <reg52.h> // 包含STC89C52的头文件
// 定义LED连接的端口,使用P0口
#define LED_PORT P0
void main(void)
{
    // 初始化P0口为输出模式(STC89C52上电后默认为弱上拉输入模式,最好手动设置)
    // P0 = 0xFF; // 将P0口所有位设置为1,LED熄灭(共阴极接法)
    while(1) // 主循环,让程序跑起来
    {
        // 第一步:点亮第一个LED (P0.0输出低电平)
        LED_PORT = 0xFE; // 二进制 1111 1110,P0.0为0,其余为1
        // 这里没有延时,所以你会看到所有LED几乎同时闪烁,效果不佳
        // 第二步:点亮第二个LED (P0.1输出低电平)
        LED_PORT = 0xFD; // 二进制 1111 1101
        // 第三步:点亮第三个LED (P0.2输出低电平)
        LED_PORT = 0xFB; // 二进制 1111 1011
        // 第四步:点亮第四个LED (P0.3输出低电平)
        LED_PORT = 0xF7; // 二进制 1111 0111
        // 第五步:点亮第五个LED (P0.4输出低电平)
        LED_PORT = 0xEF; // 二进制 1110 1111
        // 第六步:点亮第六个LED (P0.5输出低电平)
        LED_PORT = 0xDF; // 二进制 1101 1111
        // 第七步:点亮第七个LED (P0.6输出低电平)
        LED_PORT = 0xBF; // 二进制 1011 1111
        // 第八步:点亮第八个LED (P0.7输出低电平)
        LED_PORT = 0x7F; // 二进制 0111 1111
        // 然后循环回去
    }
}

问题分析: 这个程序虽然能实现“跑”的效果,但速度太快,肉眼只能看到所有LED在闪烁,我们必须加入 延时函数


标准版 - 带有延时函数

这是最常用、最经典的跑马灯实现方式,我们加入一个简单的延时函数来控制速度。

#include <reg52.h>
#define LED_PORT P0
// 简单的延时函数
// 注意:这是一个粗略的延时,其精确时间与编译器优化、晶振频率有关
void Delay(unsigned int t) // t 是一个无符号整型,用于控制延时长短
{
    unsigned int i, j;
    for (i = 0; i < t; i++)
        for (j = 0; j < 120; j++); // 内层循环,通过调整j的值来改变延时
}
void main(void)
{
    while(1)
    {
        // 从右向左逐个点亮
        LED_PORT = 0xFE; // 1111 1110
        Delay(500);      // 延时约500ms
        LED_PORT = 0xFD; // 1111 1101
        Delay(500);
        LED_PORT = 0xFB; // 1111 1011
        Delay(500);
        LED_PORT = 0xF7; // 1111 0111
        Delay(500);
        LED_PORT = 0xEF; // 1110 1111
        Delay(500);
        LED_PORT = 0xDF; // 1101 1111
        Delay(500);
        LED_PORT = 0xBF; // 1011 1111
        Delay(500);
        LED_PORT = 0x7F; // 0111 1111
        Delay(500);
        // 从左向右逐个熄灭 (或者反向跑)
        LED_PORT = 0xBF; // 1011 1111
        Delay(500);
        LED_PORT = 0xDF; // 1101 1111
        Delay(500);
        LED_PORT = 0xEF; // 1110 1111
        Delay(500);
        LED_PORT = 0xF7; // 1111 0111
        Delay(500);
        LED_PORT = 0xFB; // 1111 1011
        Delay(500);
        LED_PORT = 0xFD; // 1111 1101
        Delay(500);
        LED_PORT = 0xFE; // 1111 1110
        Delay(500);
        // 全部熄灭一下
        LED_PORT = 0xFF;
        Delay(500);
    }
}

代码解释

单片机跑马灯程序c语言
(图片来源网络,侵删)
  1. #include <reg52.h>:引入了STC89C52寄存器定义的头文件,这样我们才能使用 P0 等端口。
  2. #define LED_PORT P0:使用宏定义,方便以后修改端口,只需改这一行即可。
  3. void Delay(unsigned int t):延时函数。
    • 它通过一个 for 循环来消耗时间。
    • t 是一个参数,我们可以传入不同的值来控制延时的长短。
    • 注意:这种延时并不精确,但对于跑马灯这种应用完全足够,如果需要精确延时,需要使用定时器/计数器。
  4. main() 函数:程序的入口。
    • while(1):创建一个无限循环,保证程序持续运行。
    • LED_PORT = ...:给P0端口赋值,我们赋的是十六进制数,它对应8个二进制位。0 代表低电平,LED点亮;1 代表高电平,LED熄灭。
    • Delay(500):调用延时函数,让LED的亮灭状态持续一段时间,形成视觉暂留效果。

进阶版 - 使用移位和循环优化代码

方案二的代码虽然能工作,但太冗长,我们可以用 位操作 来优化,让代码更简洁、更专业。

#include <reg52.h>
#include <intrins.h> // 包含了_nop_()函数和循环左移/右移函数的头文件
#define LED_PORT P0
void Delay(unsigned int t)
{
    unsigned int i, j;
    for (i = 0; i < t; i++)
        for (j = 0; j < 120; j++);
}
void main(void)
{
    unsigned char led_pattern = 0xFE; // 初始模式,1111 1110,最右边LED亮
    while(1)
    {
        // 从右向左循环移位
        for(int i = 0; i < 8; i++)
        {
            LED_PORT = led_pattern; // 输出当前模式
            Delay(300);             // 延时
            // 将led_pattern的值循环左移一位
            //  1111 1110 -> 1111 1101 -> 1111 1011 ...
            led_pattern = _crol_(led_pattern, 1);
        }
        // 从左向右循环移位
        for(int i = 0; i < 8; i++)
        {
            LED_PORT = led_pattern; // 输出当前模式
            Delay(300);             // 延时
            // 将led_pattern的值循环右移一位
            //  0111 1111 -> 1011 1111 -> 1101 1111 ...
            led_pattern = _cror_(led_pattern, 1);
        }
    }
}

代码解释

  1. #include <intrins.h>:这个头文件是Keil C51编译器特有的,提供了一些编译器内置函数。
  2. unsigned char led_pattern = 0xFE;:我们用一个变量 led_pattern 来存储当前LED的亮灭状态。
  3. _crol_(led_pattern, 1):这是 intrins.h 中的 循环左移 函数。
    • 它将 led_pattern 的所有位向左移动1位,最左边移出的位会补到最右边。
    • _crol_(0xFE, 1) 的结果是 0xFD
    • _crol_(0x7F, 1) 的结果是 0xFE
  4. _cror_(led_pattern, 1):这是 循环右移 函数,原理与左移相反。

这个版本的代码量大大减少,逻辑也更清晰,是实际开发中更推荐的做法。


如何编译和下载

  1. 编译:使用Keil μVision等集成开发环境(IDE),将上面的代码保存为 .c 文件(led.c),然后新建一个工程,将此文件添加进去,编译生成 .hex 文件。
  2. 下载:使用STC-ISP等下载软件,将生成的 .hex 文件烧录到你的STC89C52单片机中。
  3. 运行:烧录成功后,给单片机上电,你就能看到跑马灯效果了。

希望这个详细的教程能帮助你理解单片机跑马灯的原理和实现!

-- 展开阅读全文 --
头像
织梦自定义支付接口如何安全高效集成?
« 上一篇 04-26
dede如何修改栏目名称?
下一篇 » 04-26

相关文章

取消
微信二维码
支付宝二维码

目录[+]