首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >即使没有数据发送到UART,Isr也会一直被调用

即使没有数据发送到UART,Isr也会一直被调用
EN

Stack Overflow用户
提问于 2020-09-17 05:29:02
回答 2查看 345关注 0票数 0

我想在我的USART1上启用isr进行空闲检测,但在控制寄存器中设置了适当的标志后,我在调试器中看到isr过程总是被调用。我的意思是,我在这个过程上设置了一个断点,所以我可以看到它总是被调用,而不是只调用一次,甚至是零次。老实说,我预计isr过程不会被调用,直到我向UART发送了一些数据...

下面是我的代码。我使用STM32F103和libopencm3。

代码语言:javascript
复制
extern "C" {
  #include <libopencm3/stm32/rcc.h>
  #include <libopencm3/stm32/gpio.h>
  #include <libopencm3/cm3/systick.h>
  #include <libopencm3/stm32/timer.h>
  #include <libopencm3/cm3/nvic.h>
  #include <libopencm3/stm32/usart.h>
  #include <libopencm3/stm32/dma.h>
}

static void rcc_setup()
{
  //Peripherals clock
  rcc_periph_clock_enable(RCC_GPIOA);
  rcc_periph_clock_enable(RCC_GPIOB); 
}

int main()
{
  rcc_setup();
  
  rcc_clock_setup_in_hse_8mhz_out_72mhz();

  systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
  systick_set_reload(8999);

  systick_interrupt_enable();
  systick_counter_enable();

  rcc_periph_clock_enable(RCC_USART1);
  rcc_periph_clock_enable(RCC_DMA1);

  // -> GPIO
  gpio_set_mode(GPIO_BANK_USART1_TX, GPIO_MODE_OUTPUT_50_MHZ, 
    GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);

  gpio_set_mode(GPIO_BANK_USART1_RX, GPIO_MODE_INPUT, 
    GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_USART1_RX);

  // -> Configuration
  usart_set_mode(USART1, USART_MODE_TX_RX);
  usart_set_baudrate(USART1, 9600);
  usart_set_parity(USART1, USART_PARITY_NONE);
  usart_set_databits(USART1, 8);
  usart_set_stopbits(USART1, 1);
  usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);

  USART_CR1(USART1) |= USART_CR1_IDLEIE; //without this, the isr is not called

  nvic_enable_irq(NVIC_USART1_IRQ);

  // -> Enable 
  usart_enable(USART1);


  while(true)
  {
    [[maybe_unused]] int x = 10;
  }
}

void usart1_isr()
{
  [[maybe_unused]]auto x = (USART_CR1(USART1) & USART_CR1_IDLEIE);
  [[maybe_unused]]auto y = (USART_SR(USART1) & USART_FLAG_IDLE);

    if (((USART_CR1(USART1) & USART_CR1_IDLEIE) != 0) &&
        ((USART_SR(USART1) & USART_FLAG_IDLE) != 0))
  {
    [[maybe_unused]] auto x = USART1_SR;
    [[maybe_unused]] auto y = USART1_DR; 

    // process_rx();

  }
}
EN

回答 2

Stack Overflow用户

发布于 2020-09-18 15:37:41

如果要通过读取清除标志,就像某些UART或SPI外设有时所做的那样,您应该这样做:

代码语言:javascript
复制
void usart1_isr (void)
{
   // read registers in well-defined, clear order to ensure flags are cleared
   volatile uint32_t usart_sr = USART1_SR; // MUST be volatile 
   volatile uint32_t usart_dr = USART1_DR;

   ...
   if(usart_sr == USART_FLAG_IDLE) // check the local variable, not the register
   ....   
}

特别是,在嵌入式系统中不应该使用大脑受损的C++11 关键字!。因为(USART_CR1(USART1) & USART_CR1_IDLEIE)是一个int类型的左值,所以从局部变量中丢弃了volatile限定符。这又会导致编译器不能生成对应于实际寄存器读取的指令。

演示C++11 auto众多危险之一的简单示例

代码语言:javascript
复制
volatile int a=1;
auto b = a & 1; // b is now int, not volatile int

int* pa = &a; // not OK since a is volatile
int* pb = &b; // OK since b is not volatile

我强烈建议尽快将此程序移植到C。或者至少是对C++03来说。

编辑

好的,现在我对这一部分进行了RTFM,显然,在大多数情况下,你也可以通过向SR写入0来清除SR。引起中断的标志取决于您如何设置CR寄存器。将USART_CR1(USART1) |= USART_CR1_IDLEIE;设置为在线路空闲时生成中断,然后通过从内部读取SR来清除空闲位。

您已经告诉程序在线路空闲时生成无休止的中断,这就是它所做的。丢弃IDLEIE位,您应该只获得TX或RX的中断,理想情况下还应覆盖or和FE。

票数 1
EN

Stack Overflow用户

发布于 2020-09-17 06:02:17

《STM32参考手册》解释说,只要在USART_ISR寄存器中执行IDLE=1,就会产生IDLE中断。当检测到空闲线路时,USART_ISR中的空闲位由硬件设置。它由软件清0,将1写入USART_ICR寄存器中的IDLECF值。我猜您需要在ISR中清除它,以防止中断立即被重新断言。尝试向usart1_isr()添加类似下面这一行的内容。

代码语言:javascript
复制
USART1_ICR = USART_ICR_IDLECF;  // Clear Idle flag in the USART_ISR register.
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63928188

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档