学习水果 2024-04-12 10:50 采纳率: 84%
浏览 43
已结题

用keil5仿真8个LED从上到下流水灯

用keil5仿真8个LED从上到下流水灯,要三种方法,给出具体的代码

  • 写回答

5条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-04-12 10:50
    关注

    引自免费微信小程序:皆我百晓生

    当然可以,我会为你提供三种方法实现8个LED从上到下流水灯的C语言代码,并在Keil5环境下进行仿真。这里假设我们使用STM32系列的微控制器,因为Keil5通常与这类开发板配合使用。

    方法一:使用位操作(位移)

    #include "stm32f10x.h"
    
    // LED定义,假设GPIOA为输出
    GPIO_InitTypeDef GPIO_InitStructure;
    
    void delay_ms(uint32_t ms) {
        uint32_t start = HAL_GetTick();
        while ((HAL_GetTick() - start) < ms);
    }
    
    int main(void) {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // 配置GPIOA时钟
    
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 |
                                      GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 输出推挽模式
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        for (;;) {
            GPIOA->ODR ^= (1 << 7); // 将最高位LED点亮,然后逐位向左移位
            delay_ms(100); // 灯光间隔100ms
        }
    
        return 0;
    }
    

    方法二:使用数组和循环

    #include "stm32f10x.h"
    
    // LED定义,假设GPIOA为输出
    GPIO_InitTypeDef GPIO_InitStructure;
    uint8_t led_array[8] = {GPIO_Pin_0, GPIO_Pin_1, GPIO_Pin_2, GPIO_Pin_3,
                             GPIO_Pin_4, GPIO_Pin_5, GPIO_Pin_6, GPIO_Pin_7};
    
    void delay_ms(uint32_t ms) {
        // ...
    }
    
    int main(void) {
        // ...
        for (int i = 7; i >= 0; --i) {
            HAL_GPIO_WritePin(GPIOA, led_array[i], GPIO_PIN_SET); // 设置当前LED高电平
            delay_ms(100);
            HAL_GPIO_WritePin(GPIOA, led_array[i], GPIO_PIN_RESET); // 清零当前LED
        }
        // ...
    }
    

    方法三:使用中断(仅适用于有足够中断资源的情况)

    #include "stm32f10x.h"
    
    // LED定义,假设GPIOA为输出
    GPIO_InitTypeDef GPIO_InitStructure;
    uint8_t led_index = 7;
    
    // 中断相关宏定义
    #define LED_COUNT 8
    #define DELAY_MS 100
    #define PERIOD_US (DELAY_MS * 1000)
    
    void EXTI0_IRQHandler(void) {
        if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
            EXTI_ClearITPendingBit(EXTI_Line0); // 处理中断后清零
            if (led_index > 0) {
                led_index--;
                HAL_GPIO_WritePin(GPIOA, GPIO_Pin_7, GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOA, GPIO_Pin_0, GPIO_PIN_SET);
            } else {
                led_index = LED_COUNT - 1;
            }
        }
    }
    
    int main(void) {
        // ...
        HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); // 设置中断优先级
        HAL_NVIC_EnableIRQ(EXTI0_IRQn); // 开启中断
    
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        while (1) {
            // 不使用中断时,手动控制LED
            if (led_index == LED_COUNT) {
                led_index = 0;
            }
            HAL_GPIO_WritePin(GPIOA, GPIO_Pin_7, GPIO_Pin_RESET);
            HAL_GPIO_WritePin(GPIOA, GPIO_Pin_0, GPIO_Pin_SET);
            led_index++;
            __HAL_DELAY(PERIOD_US / LED_COUNT);
        }
        // ...
    }
    

    以上代码分别展示了位操作、数组循环和中断驱动三种实现方式。在Keil5中,你需要将这些代码放入一个新建的.c文件中,然后配置对应的STM32设备和GPIO口。记得在项目设置中选择正确的CPU和外设库。然后通过点击仿真按钮进行调试和观察流水灯效果。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(4条)

报告相同问题?

问题事件

  • 系统已结题 6月7日
  • 已采纳回答 5月30日
  • 专家修改了标签 4月12日
  • 创建了问题 4月12日