RT-Thread论坛
直播中

王兰

14年用户 1738经验值
擅长:基础元器件
私信 关注
[问答]

中断发送信号量不能释放等待信号量的线程是怎么回事?

MCU为STM32f407vgt6,rt-thread的版本为4.0.3。

  • 代码如下:

    • /* 接收数据回调函数,该函数会在uart中断例程中调用*/
    • static rt_err_t modbus_uart_input(rt_device_t dev, rt_size_t size)
    • {
    • /* 串口接收到数据后产生中断, 调用此回调函数, 然后发送接收信号量 */
    • rt_sem_release(&modbus_uart_sem);
    • return RT_EOK;
    • }
    • /* 线程comm uart receive入口 */
    • void thread_comm_uart_receive_entry(void* parameter)
    • {
    • char ch;
    • static uint32_t comm_uart_cmd_buff_pos = 0;
    • static uint8_t comm_uart_cmd_buff[MSG_BUFF_LEN];
    • while (1)
    • {
    •      /* 从串口读取一个字节的数据,没有读到则等待接收信号量 */
    •      if(rt_device_read(comm_uart_dev, -1, &ch, 1) == 1) {
    •          if (ch == END_CHAR) {
    •               comm_uart_cmd_buff[comm_uart_cmd_buff_pos] = '�';
    •               if (comm_uart_cmd_buff_pos > 0) {
    •                   if (comm_uart_cmd_buff[comm_uart_cmd_buff_pos - 1] == BEFOR_END_CHAR) {
    •                       comm_uart_cmd_buff[--comm_uart_cmd_buff_pos] = '�';
    •                   }
    •               }
    •               /* 接收到一行完整的指令*/
    •               CmdHandleMsg(comm_uart_cmd_buff);
    •               comm_uart_cmd_buff_pos = 0;
    •           } else if (ch == BACK_CHAR) {

    •               if (comm_uart_cmd_buff_pos > 0) {
    •                   comm_uart_cmd_buff[--comm_uart_cmd_buff_pos] = '�';
    •               }
    •           } else {
    •               if (comm_uart_cmd_buff_pos < MSG_BUFF_LEN - 1) {
    •                   comm_uart_cmd_buff[comm_uart_cmd_buff_pos++] = ch;
    •               }
    •           }
    •       } else {
    •           rt_sem_take(&comm_uart_sem, RT_WAITING_FOREVER);
    •       }
    • }
    • }


  • 现象如下,偶尔会出现rt_sem_release发送信号量时,查询挂起线程链表为空,然而thread_comm_uart_receive_entry该线程没有执行,这种现象比较难复现,需要发送很多次数据才会偶尔复现一次。


回帖(2)

陈茗卓

2025-9-10 17:44:10
    可能进中断的时候没有调用 rt_interrupt_enter()函数                        
举报

杨海清

2025-9-12 18:19:10

根据您提供的代码和描述,问题可能由以下几个原因引起。以下是详细分析和解决方案:


1. 信号量初始化问题


在RT-Thread中,信号量需要正确初始化才能工作。请确认信号量 modbus_uart_sem 是否在创建接收线程之前正确初始化:


   rt_sem_init(&modbus_uart_sem, "uart_sem", 0, RT_IPC_FLAG_FIFO);
   // 或动态创建:rt_sem_create("uart_sem", 0, RT_IPC_FLAG_FIFO);


  • 关键点:初始值应为 0,确保接收线程在启动后立刻等待信号量。

  • 错误现象:如果初始值设为 1,线程可能在无数据时提前运行,导致后续信号量无法正确同步。




2. 串口设备配置问题


回调函数 modbus_uart_input 需在串口设备中正确注册才能触发:


   // 在初始化代码中设置回调函数
   rt_device_set_rx_indicate(comm_uart_dev, modbus_uart_input);


  • 检查项

    1. 是否调用 rt_device_open() 时启用了中断接收模式?
      rt_device_open(comm_uart_dev, RT_DEVICE_FLAG_INT_RX);

    2. 确认串口设备名称(如 "uart3")是否正确绑定到 comm_uart_dev





3. 中断与线程优先级冲突


STM32中断优先级需高于线程优先级,否则中断无法抢占线程:



  • 配置步骤

    1. 为串口中断设置较高的硬件优先级(数值较小)。
      // 在HAL库中设置中断优先级
      HAL_NVIC_SetPriority(USARTx_IRQn, 0, 0);
      HAL_NVIC_EnableIRQ(USARTx_IRQn);

    2. 确保接收线程优先级低于中断优先级(数值较大):
      rt_thread_init(..., RT_THREAD_PRIORITY_MAX / 2, ...);





4. 线程堆栈溢出


接收线程 thread_comm_uart_receive_entry 的堆栈过小可能导致运行异常:


   #define THREAD_STACK_SIZE 1024
   rt_thread_t thread = rt_thread_create("uart_rcv", thread_comm_uart_receive_entry, RT_NULL, THREAD_STACK_SIZE, ...);


  • 建议:使用 rt_thread_mdelay(10) 替代原地循环等待数据,避免堆栈溢出。




5. 中断未清除标志位


在STM32中,需手动清除串口中断标志(如 USART_SR_RXNE)。RT-Thread设备驱动通常已处理,但需确认:



  • 检查驱动代码(如 drv_usart.c)是否清除了中断标志。

  • 在回调函数中增加调试输出(慎重使用),观察是否被触发:
     static rt_err_t modbus_uart_input(rt_device_t dev, rt_size_t size) {
         rt_kprintf("IRQ!\n");  // 中断中打印需简短
         rt_sem_release(&modbus_uart_sem);
         return RT_EOK;
    }




6. 数据读取逻辑错误


接收线程需正确处理 rt_device_read() 返回值:


   void thread_comm_uart_receive_entry(void* parameter) {
       char ch;
       while (1) {
           rt_sem_take(&modbus_uart_sem, RT_WAITING_FOREVER); // 阻塞等待
           if (rt_device_read(comm_uart_dev, -1, &ch, 1) != 1) {
               continue; // 读取失败处理
           }
           // 处理数据 ch
       }
   }


  • 潜在问题size 参数应为 1(读一个字节),而非 sizeof(ch)




7. RT-Thread版本兼容性


确认以下API在V4.0.3中未被弃用:



  • rt_sem_release():中断中释放信号量是安全的。

  • rt_device_set_rx_indicate():串口驱动的标准注册方式。




解决方案总结



  1. 检查信号量初始化:确认初始值为 0

  2. 验证串口配置
    // 示例初始化代码
    comm_uart_dev = rt_device_find("uart3");
    rt_device_set_rx_indicate(comm_uart_dev, modbus_uart_input);
    rt_device_open(comm_uart_dev, RT_DEVICE_FLAG_INT_RX);

  3. 调整优先级

    • 串口中断硬件优先级:0~5

    • 接收线程优先级:>20


  4. 增加调试输出

    • 在回调函数和线程中打印日志(避开中断关键路径)。


  5. 测试最小代码:注释数据处理逻辑,仅验证信号量同步。


通过逐步排除以上问题,可定位根源。重点优先级:信号量初始化 > 中断配置 > 串口驱动

举报

更多回帖

发帖
×
20
完善资料,
赚取积分