如何在单片机上实现跑马灯

按照图中编程方式当ledIndex为零时这个灯不亮,转向最后一个灯进入一个新的循环,怎么改能让所有灯依次点亮?

在51单片机上实现跑马灯可以使用C语言的编程方式。你可以使用延时函数和位运算来实现灯的循环点亮。

以下是一个示例代码,实现所有灯依次点亮的跑马灯效果:

#include <reg51.h>

// 定义灯的个数和初始亮灯索引
#define NUM_LEDS  8
#define INITIAL_LED_INDEX 0

// 定义LED口线对应的端口和引脚号
sbit LED_PORT = P1;
#define LED_PIN_START 0

// 延时函数
void delay(unsigned int ms) {
    unsigned int i, j;
    for (i = 0; i < ms; i++) {
        for (j = 0; j < 130; j++);
    }
}

int main() {
    unsigned int ledIndex = INITIAL_LED_INDEX;
    unsigned int ledsMask = 1 << LED_PIN_START;

    while (1) {
        // 点亮当前灯
        LED_PORT = ledsMask;

        // 将灯的掩码左移一位
        ledsMask <<= 1;

        // 判断是否超过最后一个灯的位置
        if (ledIndex >= NUM_LEDS) {
            ledIndex = 0; // 重置为第一个灯的索引
            ledsMask = 1 << LED_PIN_START; // 重置灯的掩码为第一个灯
        }

        // 延时一段时间
        delay(1000);
    }

    return 0;
}

在上述代码中,我们使用 LED_PORTLED_PIN_START 定义了LED控制口线对应的端口和引脚号。通过控制 LED_PORT 端口的引脚状态来点亮或熄灭LED。

通过对 ledsMask 的位运算操作实现灯的循环点亮效果。开始时 ledsMask 的初始值为第一个灯的掩码,然后每次循环将其左移一位,直到超过最后一个灯的位置时,将 ledIndexledsMask 重置为0,重新从第一个灯开始循环。

你需要根据你的硬件连接情况和引脚定义进行适当的修改。在主函数中的 delay() 函数可以通过具体需求调整延时的时间,控制灯的点亮速度。

希望这个示例代码能帮助到你在51单片机上实现跑马灯效果!

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这篇博客: 蓝桥杯比赛单片机设计与开发 工程创建和点亮LED中的 对文件工程的创建方法: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    (1)多文件创建有两个要点:
    1.以.h开头文件的包括;
    2…c文件的添加
    (2)1.首先创建文件夹“点亮LED”,并且在文件夹内创建者三个文件夹
    用来存储工程文件,.c和.h文件夹存储在命名为FWLIB文件夹内部。工程生成的HEX文件存储在OBJ中,main.c和主头文件村吹在USER中。

    2.打开keil 5,创建工程,命名后保存在USER文件夹下在这里插入图片描述
    保存后会出现mcu的选择界面:在这里插入图片描述在选择框中选择 STC MCU Database 中search ST15F2K60S,点击OK。

    3 . 在这里插入图片描述
    点击keil中这个图标并在其中添加这三个文件夹
    在这里插入图片描述
    点击OK。
    然后点击这个图标,在这里插入图片描述
    选择Output界面,勾选Creat HEX File,选择select folder for objects,然后选择创建的文件夹OBJ,用于存储生成的HEX文件。
    此时工程创建已经基本完毕,下面是文件的添加
    4.点击keil中的NEW或者(CTRL+N)创建代码编辑页面命名为main.c点击保存,保存在USER文件夹下在这里插入图片描述
    再利用同样方法创建命名为include.h也保存在USER文件夹下。(名字可以自由命名,不一定非要按照我写的)在这里插入图片描述
    保存后在这里插入图片描述
    双击USER文件夹将main.c添加入工程中。
    重磅来啦~~~~~
    .h的文件的添加在这里插入图片描述
    点击这个图标选择C51,选择include paths在这里插入图片描述
    选择保存.h文件夹的路径(!注意这里必须是保存.h的文件夹,不能是文件夹的上一层)。
    所有的.h文件添加方法都可以参照这个方法
    main.c中可以写

    # include "include.h"
    
    
    
    void main()
    {
    	while(1)
    	{
    		
    	}
    	
    }
    

    include.h中写

    #ifndef _INCLUDE_H_
    #define _INCLUDE_H_
    
    
    
    #include "STC15F2K60S.h"
    #include "intrins.h"
    
    
    
    #endif
    

    在以同样的方法创建两个空白编辑页面命名为enable138.c和.h保存在FWLIB中创建的enable138文件夹下在这里插入图片描述
    点击工程中的FWLIB将enable138.c添加入工程中,再以同样的方法在C51中添加.h文件。
    74HC138的封装程序:
    enable.c 文件

    #include "enable138.h"
    
    void enable138(uchar x)
    {
    	P2&=0X1f;    //先将138 A B C 置位0 0 0输出Y0为低,其他为高
    	P2|=(x<<5); //X左移5位后通过或非门对对应的74HC573送入数据
    	
    	_nop_();
    	_nop_();
    	P2&=0X1f;//在此将P2置位
    }
    

    enable.h文件

    #ifndef _ENABLE_H_
    #define _ENABLE_H_
    
    
    #include "include.h"
    #define LED 4
    #define DU 7
    #define WE 6
    #define ULN2003  5
    
    extern void enable138(uchar x);
    
    #endif
    
    

    上边程序可作为蓝桥杯中74HC138的封装程序,直接调用即可。
    下边为include.h文件

    #ifndef _INCLUDE_H_
    #define _INCLUDE_H_
    
    #define uchar unsigned char 
    #define uint unsigned int
    
    #include "STC15F2K60S2.h"
    #include "intrins.h"
    #include "enable138.h"
    #endif
    

    点亮所有led,所有外设初始化:

    # include "include.h"
    void suoyouwaishe_Init()
    {
    
    	P0=0xff;
    	enable138(LED);
    	P0=0x00;
    	enable138(ULN2003);
    	P0=0x00;
    	enable138(WE);
    	P0=0xff;
    	enable138(DU);
    
    }
    
    
    void main()
    {
    	suoyouwaishe_Init();
    	while(1)
    	{
    		P0=0x00;//点亮所有led
    		enable138(4);
    		
    	}
    	
    }
    

    解释:138封装中定义的DU位数码管段选,WE为数码管位选。

    写文章真的好难,哈哈!!我以后会坚持与大家分享各种蓝桥杯的程序写法,欢迎各位吐槽与提问,大家一起进步!!

  • 以下回答来自chatgpt:

    要实现跑马灯效果,可以使用定时器和标志位来控制LED的亮灭顺序。下面是一个示例的解决方案,使用C语言编写代码来实现跑马灯效果:

    #include <reg51.h>      // 单片机头文件,根据实际使用的单片机型号进行更改
    
    #define LED_COUNT 8     // LED灯的数量
    #define DELAY_MS 100    // 每个LED灯的显示时间间隔,单位为毫秒
    
    sbit led = P1^0;        // LED灯的引脚
    
    void delay(unsigned int ms) {
        unsigned int i, j;
        for (i = ms; i > 0; i--) {
            for (j = 110; j > 0; j--);   // 这里的延迟时间根据实际情况进行调整
        }
    }
    
    void main() {
        unsigned int ledIndex = 0;      // 当前亮起的LED灯的索引
    
        TMOD = 0x01;    // 设置定时器0为模式1,使用定时器0的第一个外部中断(INT0)
        TH0 = (65536 - 50000) / 256;    // 定时器0计数初值,根据实际情况进行调整
        TL0 = (65536 - 50000) % 256;
        ET0 = 1;        // 允许定时器0中断
        EA = 1;         // 允许全局中断
        TR0 = 1;        // 启动定时器0
    
        while (1) {
            if (ledIndex == LED_COUNT) {
                ledIndex = 0;   // 如果已经是最后一个LED灯,则重置索引回到第一个灯
            }
    
            // 依次点亮LED灯
            switch (ledIndex) {
                case 0: led = 1; break;
                case 1: led = 2; break;
                case 2: led = 4; break;
                case 3: led = 8; break;
                case 4: led = 16; break;
                case 5: led = 32; break;
                case 6: led = 64; break;
                case 7: led = 128; break;
            }
    
            delay(DELAY_MS);
    
            ledIndex++;     // 索引递增,准备点亮下一个LED灯
        }
    }
    
    // 定时器0的中断处理函数
    void timer0_interrupt() interrupt 1 {
        TH0 = (65536 - 50000) / 256;    // 定时器0计数初值,根据实际情况进行调整
        TL0 = (65536 - 50000) % 256;
    
        led = 0;        // 熄灭当前LED灯
    }
    

    在上面的代码中,定时器0的中断周期为50ms,每个LED灯的显示时间间隔为100ms。其中,ledIndex变量用来记录当前亮起的LED灯的索引。在中断处理函数中,先熄灭当前亮起的LED灯,然后在主循环中按顺序点亮下一个LED灯。

    请注意,上述代码是一个示例,具体的调整和修改取决于您所使用的单片机型号和开发工具。如果您使用的是其他单片机平台,需要根据具体的硬件和软件编程规范进行相应的调整。另外,由于您没有提供具体的单片机型号和您目前的编程方式,以上代码仅供参考。

    如果您对单片机编程、定时器和中断等概念不熟悉,建议您先学习相关的基础知识,然后参考单片机的技术文档和开发工具提供的示例代码进行实践。如果您仍然遇到问题或需要进一步的帮助,请提供更多的详细信息,以便我能够更准确地为您解答。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^