沥沥小鱼 2024-04-18 11:50 采纳率: 45.5%
浏览 219
已结题

stm32流水灯+呼吸灯+外部中断按键

使用stm32来完成 花样流水灯
(1)LED灯从中间向两边依次点亮,每次点亮时间间隔不低于 500ms,到还剩最高位和最低位的 灯不亮时,显示5次呼吸灯,最后点亮全部灯(呼吸时间可调节)。
(2)待LED灯全部点亮后,再向两边往中间熄灭,每次熄灭时间间隔不低于 500ms,到中间熄灭 时,最后显示6次呼吸灯,全部熄灭(呼吸时间可调节)。
(3)在暂停后,按下另一个独立按键,可以增加 LED点亮和熄灭的时间间隔,按下一次增加时间 不少于 500ms.同时,当LED灯点亮和熄灭的时间间隔过长时,按下另外一个独立可以减小时间间隔,减少时间不少于500ms。
(4)用独立按键使 LED流水灯效果暂停,再次按下后 LED灯流水灯效果继续,必须从暂停处开始 运行(在呼吸灯状态下也同样暂停)。
我写的代码思路:用16进制控制8个LED灯达到循环效果 接下来用while循环嵌套实现呼吸灯次数控制
按键外部中断封装在Key.c里面 key模块会返回延时时间i
问题:代码现象是只有流水灯(中间往两边点亮 两边往中间熄灭) 没有呼吸灯的现象 按键也不能控制流水灯延时时间 按键按下去没反应 但是把流水灯代码注释之后又有呼吸灯的现象 我觉得不是流水灯把呼吸灯覆盖了 因为呼吸灯先 流水灯后 也还是没有呼吸灯现象
以下是重要模块代码
main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "PWM.h"
#include "Key.h"
//Ҫͨ¹ý°´¼üº¯Êý²ÎÊý¸Ästm32f10x_rcc
int i=500;
int j;
int count2=0;
int main(void)
{
  
  PWM_Init();
    Key_Init();
    Key_Get_Time();
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    while (1)
    {
        GPIO_Write(GPIOA, ~0x18);    //0000 0000 0000 0001
        Delay_ms(i); 
        GPIO_Write(GPIOA, ~0x3C);    //0000 0000 0000 0010
        Delay_ms(i);
        GPIO_Write(GPIOA, ~0x7E);    //0000 0000 0000 0100
        Delay_ms(i);
        GPIO_Write(GPIOA, ~0xFF);    //0000 0000 0000 1000
        Delay_ms(i);
        //ÏÔʾ5´ÎºôÎüµÆ
        while(count2<=5)
        {
        for (j = 0; j <= 100; j++)
        {
            PWM_SetCompare1(j);
            Delay_ms(10);
        }
        for (j = 0; j <= 100; j++)
        {
            PWM_SetCompare1(100 - j);
            Delay_ms(10);
            count2++;
        }
        }
        
        GPIO_Write(GPIOA, ~0x7E);    //0000 0000 0001 0000
        Delay_ms(i);
        GPIO_Write(GPIOA, ~0x3C);    //0000 0000 0010 0000
        Delay_ms(i);
        GPIO_Write(GPIOA, ~0x18);    //0000 0000 0100 0000
        Delay_ms(i);
        GPIO_Write(GPIOA, ~0x00);    //0000 0000 1000 0000
        Delay_ms(i);
      Delay_ms(i);
        //ÏÔʾ6´ÎºôÎüµÆ
        while(count2<=6)
        {
        for (j = 0; j <= 100; j++)
        {
            PWM_SetCompare1(j);
            Delay_ms(10);
        }
        for (j = 0; j <= 100; j++)
        {
            PWM_SetCompare1(100 - j);
            Delay_ms(10);
        }
        count2++;
        }
    }
}

key.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
uint16_t count;
static int i;
void Key_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    //中断配置
    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = EXTI_Line14; 
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitStructure.EXTI_Mode =EXTI_Mode_Interrupt ; 
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; 
    EXTI_Init(&EXTI_InitStructure);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; 
    NVIC_Init(&NVIC_InitStructure);
}
 uint16_t Key_Get(void)
 {
  return count;
 }
 int Key_Get_Time(void)
 {
   return i;   
 }
void EXTI15_10_TRQHandler(void)
{
   if(EXTI_GetITStatus(EXTI_Line14)==SET)
     {
     
         count++;
         EXTI_ClearITPendingBit(EXTI_Line14);
     }
    
}
uint8_t Key_GetNum(void)
{
    uint8_t KeyNum = 0;
    if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
    {
        Delay_ms(20);
        while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
        Delay_ms(20);
        KeyNum = 1;
        i+=500;
    }
    if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
    {
        Delay_ms(20);
        while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
        Delay_ms(20);
        KeyNum = 2;
        i-=500;
    }
    
    return KeyNum;
}

key.h

#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);
uint16_t Key_Get(void);
int Key_Get_Time(void);
    
#endif

PWM.c

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
//    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//    GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
//    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;        //GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_InternalClockConfig(TIM2);
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;        //ARR
    TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;        //PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
    
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;        //CCR
    TIM_OC1Init(TIM2, &TIM_OCInitStructure);
    
    TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
    TIM_SetCompare1(TIM2, Compare);
}
  • 写回答

19条回答 默认 最新

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

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

    针对您提供的代码及描述的问题,我注意到以下几点需要进行修改和调整以实现预期功能:

    1. 流水灯与呼吸灯逻辑混杂:当前代码中,流水灯和呼吸灯的控制逻辑相互交织在一起,导致无法清晰地分离并独立控制它们。建议将流水灯和呼吸灯部分分别封装成独立函数,以便更好地管理状态和控制流程。

    2. 按键中断处理:按键中断处理部分未正确实现,需要重新设计以处理按键事件,并更新流水灯和呼吸灯的延时时间。

    3. 延时时间更新:延时时间 i 需要在按键中断服务程序中更新,并确保其全局可见。此外,要处理延时时间的边界条件,防止其过小或过大。

    基于上述分析,我对您的代码进行了重构和优化。下面是修改后的代码:

    main.c

    #include "stm32f10x.h"
    #include "Delay.h"
    #include "PWM.h"
    #include "Key.h"
    
    volatile int delay_ms = 500;  // 全局延时时间变量
    
    int main(void)
    {
        PWM_Init();
        Key_Init();
    
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        while (1)
        {
            // 循环流水灯点亮
            led_waterfall_up();
    
            // 呼吸灯显示5次
            led_breath_show(5);
    
            // 循环流水灯熄灭
            led_waterfall_down();
    
            // 呼吸灯显示6次
            led_breath_show(6);
        }
    }
    
    // 流水灯点亮(从中间向两边)
    void led_waterfall_up(void)
    {
        static const uint16_t waterfall_sequence[] = {~0x18, ~0x3C, ~0x7E, ~0xFF};
        for (uint8_t i = 0; i < sizeof(waterfall_sequence) / sizeof(waterfall_sequence[0]); ++i)
        {
            GPIO_Write(GPIOA, waterfall_sequence[i]);
            Delay_ms(delay_ms);
        }
    }
    
    // 流水灯熄灭(从两边向中间)
    void led_waterfall_down(void)
    {
        static const uint16_t waterfall_sequence[] = {~0x7E, ~0x3C, ~0x18, ~0x00};
        for (uint8_t i = 0; i < sizeof(waterfall_sequence) / sizeof(waterfall_sequence[0]); ++i)
        {
            GPIO_Write(GPIOA, waterfall_sequence[i]);
            Delay_ms(delay_ms);
        }
    }
    
    // 显示指定次数的呼吸灯
    void led_breath_show(uint8_t num_times)
    {
        for (uint8_t i = 0; i < num_times; ++i)
        {
            for (uint16_t j = 0; j <= 100; ++j)
            {
                PWM_SetCompare1(j);
                Delay_ms(10);
            }
            for (uint16_t j = 0; j <= 100; ++j)
            {
                PWM_SetCompare1(100 - j);
                Delay_ms(10);
            }
        }
    }
    

    key.c

    #include "stm32f10x.h"
    #include "Delay.h"
    
    volatile bool key_pressed = false;  // 按键按下标志
    volatile bool key_increase = false;  // 延时增加标志
    volatile bool key_decrease = false;  // 延时减少标志
    
    void Key_Init(void)
    {
        // ...(保持现有初始化代码不变)
    
        // 中断配置
        EXTI_InitTypeDef EXTI_InitStructure;
        EXTI_InitStructure.EXTI_Line = EXTI_Line14;
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
        EXTI_Init(&EXTI_InitStructure);
    
        // ...(保持现有NVIC配置代码不变)
    }
    
    void EXTI15_10_TRQHandler(void)
    {
        if (EXTI_GetITStatus(EXTI_Line14) == SET)
        {
            EXTI_ClearITPendingBit(EXTI_Line14);
    
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
            {
                key_pressed = true;
                key_increase = true;
            }
            else if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
            {
                key_pressed = true;
                key_decrease = true;
            }
    
            // 清除按键标志
            while ((GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) ||
                   (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0));
        }
    }
    
    // 更新延时时间
    void update_delay_time(void)
    {
        static const int step_ms = 500;
    
        if (key_increase && delay_ms + step_ms <= 5000)  // 防止延时时间过大
        {
            delay_ms += step_ms;
        }
        else if (key_decrease && delay_ms >= step_ms)  // 防止延时时间过小
        {
            delay_ms -= step_ms;
        }
    
        key_increase = false;
        key_decrease = false;
    }
    
    // 主循环中定期调用此函数,处理按键事件
    void check_key_events(void)
    {
        if (key_pressed)
        {
            update_delay_time();
            key_pressed = false;
        }
    }
    

    main.c 中已将流水灯和呼吸灯逻辑分离为独立函数。在主循环中,按照顺序调用这些函数即可实现所需效果。

    key.c 中,我添加了三个全局标志变量用于记录按键状态。中断服务程序根据按键状态设置相应的标志,并在 check_key_events() 函数中处理这些事件,更新全局延时时间 delay_ms。您应在主循环中定期调用 check_key_events() 函数,以确保按键事件得到及时处理。

    经过上述修改,您的 STM32 应能正确实现流水灯、呼吸灯以及按键控制延时时间的功能。如果您在实际应用中遇到问题,欢迎继续提问。

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

报告相同问题?

问题事件

  • 系统已结题 4月30日
  • 已采纳回答 4月22日
  • 创建了问题 4月18日