为什么中断在 STM32 上没有按预期工作?

Fad*_*EID 0 c embedded microcontroller arm stm32

我正在尝试编写一个简单的程序,该程序利用外部中断来控制 2 个 LED 中的哪一个闪烁。在没有中断例程的情况下,两个 LED 都会闪烁,因此 LED 引脚(PB 和 PC13)的配置是正确的。每当我尝试使用 ISR 时就会出现该程序。我正在为 STM32F103C8 MCU 使用仅带有 CMSIS 内核的 Keil uVision 5。

在下面的代码中,两个 LED 都没有闪烁。我试图将引脚 PB5 设置为输入上拉,并在将 PB5 与 GND 连接时检测下降沿作为中断。

#include "stm32f10x.h"                  // Device header

void delay(int rep);
void EXTI9_5_IRQHandler();

// global variable
int signal = 0; // this will change upon each interrupt

int main(void)
{
    // set RCC for PortC to enable the clock BUS
    RCC->APB2ENR |= (1<<4);
    // set RCC for portB to enable the clock bus
    RCC->APB2ENR |= (1<<3);
    
    // set the mode and function of PC13 to output
    GPIOC->CRH &= 0xFF0FFFFF;   // reset to all zeros
    GPIOC->CRH |= 0x00200000;   // make output push-pull
    
    // set the mode and function of PB3 as output
    GPIOB->CRH &= 0xFFFFFFF0;   // reset to all zeros
    GPIOB->CRH |= 0x00000002; // make output push-pull
    
    // set PB5 as input to later make it an external interrupt
    GPIOB->CRL &= 0xFF0FFFFF;   // reset to all zeros
    GPIOB->CRL |= 0x00800000;   // make input pullup/pulldown
    GPIOB->ODR |= (1<<5); // pullup
    
    // configure PB5 as external interrupt
    __disable_irq();    // disable interrupt requests (for safety)
    AFIO->EXTICR[1] = 0x00000010;
    EXTI->IMR |= (1<<5);
    EXTI->FTSR |= (1<<5);   // set to falling edge
    NVIC_EnableIRQ(EXTI9_5_IRQn);
    __enable_irq(); // enable the interrupt requests again 
    
    
    
    // toggle PC13 indefinitely (waiting for interrupts)
    while(1)
    {
        if(signal==0)
        {
            GPIOC->ODR |= (1<<13);
            delay(10);
            GPIOC->ODR &= ~(1<<13);
            delay(5);
        }
        else if(signal==1)
        {
            GPIOB->ODR |= (1<<8);
            delay(10);
            GPIOB->ODR &= ~(1<<8);
            delay(5);
        }
    }
        
}



// ISR Function to service PB5 external interrupts
void EXTI9_5_IRQHandler()
{
    EXTI->PR |=(1<<5);
    if(signal ==1) signal = 0;
    else signal = 1;
}



/// Random time delay Function
void delay(int rep)
{
    for(;rep>0;rep--)
    {
    int i;
    for(i=0; i< 100000;i++)
    {}
    }
}

Run Code Online (Sandbox Code Playgroud)

Cli*_*ord 5

EXTI 功能需要在 RCC 中启用 SYSCFG/AFIO。否则您的 EXTI 配置将被忽略。对于STM32F1xx来说是AFIO,其他系列使用SYSCFG。

RCC->APB2ENR |= (1<<0);  // Enable AFIO CLOCK
Run Code Online (Sandbox Code Playgroud)

初始化:

GPIOB->ODR |= (1<<5); // pullup
Run Code Online (Sandbox Code Playgroud)

写入错误的寄存器。你的意图是:

GPIOB->PUPDR |= (1<<5); // pullup
Run Code Online (Sandbox Code Playgroud)

如果评论有意义的话。

延迟循环有严重缺陷 - 至少你应该有:

volatile int i ;
Run Code Online (Sandbox Code Playgroud)

除此之外,请考虑使用 Cortex-M SYSCLK 并SystemCoreClock实现更合理、更确定的延迟。例如:

volatile uint32_t tick = 0 ;
  
void SysTick_Handler(void)  
{
    tick++ ;
}

void delayms( uint32_t millisec )
{
    static bool init = false ;
    if( !init )
    {
        SysTick_Config( SystemCoreClock / 1000 ) ;
        init = true ;
    }

    uint32_t start = tick ;
    while( tick - start < millisec ) ;
}
Run Code Online (Sandbox Code Playgroud)

线程上下文之间共享的任何变量也必须声明volatile

volatile int signal = 0; // this will change upon each interrupt
Run Code Online (Sandbox Code Playgroud)

并且signal无需测试两次,else if(signal==1)即可简单else。这会更好,因为signal两个测试之间可能会发生变化,并且最终不会执行任何一个块。切勿在同一迭代中重新测试共享变量。如果您需要这样做,请一次性获取一份副本并测试该副本。