RT-Thread论坛
直播中

王桂英

8年用户 1410经验值
私信 关注
[问答]

在串口中断中发送事件,线程中不接收是怎么回事?


  • rt_event_t  GPS_event_set = NULL;
  • void main()
  • {


  •      // 部分代码
  •    GPS_event_set =  rt_event_create("GPS_events", RT_IPC_FLAG_PRIO);

  •         tid = rt_thread_create("GPS_task",
  •                                                      GPS_task_entry,
  •                                                      RT_NULL,
  •                                                      GPS_STACK_SIZE,
  •                                                      GPS_THREAD_PRIORITY,
  •                                                      20);                //运行多少tick

  •         rt_thread_startup(tid);




  • }
  • void GPS_task_entry(void *parameter)
  • {

  •         static rt_err_t result;
  •         rt_uint32_t events;

  •        // 初始化事件集
  •   //  rt_event_init(&event_set, "GPS_events", RT_IPC_FLAG_PRIO);
  •     while (1)
  •     {
  • //
  •             // 等待任意一个事件发生
  •         result = rt_event_recv(GPS_event_set,
  •                                EVENT_NEW_NMEA | EVENT_PPS,
  •                                RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  •                                RT_WAITING_FOREVER,
  •                                &events);


  •             if (result == RT_EOK)
  •         {
  •             // 检查哪个事件被触发
  •             if (events & EVENT_NEW_NMEA)
  •             {
  •               update_rtc_with_rmc_data(nmea_buffer,&rmc_data);

  •             }

  •             if (events & EVENT_PPS)
  •             {
  •                 // 处理PPS信号
  •                 handle_pps_signal();
  •             }
  •         }

  •     }


  • }

  • void USART5_IRQHandler(void)
  • {


  •     if (RESET != usart_interrupt_flag_get(USART5, USART_INT_FLAG_RBNE)) {
  •         // 从USART5的接收数据寄存器读取一个字节
  •         uint8_t byte = (uint8_t)usart_data_receive(USART5);

  •         // 将字节添加到缓冲区
  •         nmea_buffer[buffer_index++] = byte;



  •         // 检查是否到达行尾
  •         if (byte == 0x0A && nmea_buffer[buffer_index-2] ==0x0D )
  •                     {

  •             // 重置缓冲区索引
  •               buffer_index = 0;

  •                          // 处理NMEA数据
  •                 memset(&rmc_data, 0, sizeof(RMCData));
  •                 if (RT_EOK == parse_RMC(nmea_buffer, &rmc_data))
  •                                 {

  •                                    new_nmea_data = 1;
  •                        rt_event_send(GPS_event_set, EVENT_NEW_NMEA);
  •                                 }

  •         }

  •         // 清除RBNE中断标志
  •         usart_interrupt_flag_clear(USART5, USART_INT_FLAG_RBNE);
  •     }
  • }


程序在串口中可以正常发送 。。。。 但是接收线程仿真的时候没反应。

回帖(1)

陈博

2025-10-21 17:53:38

在串口中断中发送事件但线程无法接收,通常由以下几个原因导致。请对照您的代码检查:


1. 事件集未正确创建


   rt_event_t GPS_event_set = NULL; // 全局变量初始化为NULL
   void main() {
       GPS_event_set = rt_event_create("GPS_events", RT_IPC_FLAG_PRIO);
       // 未检查返回值!
   }

问题:如果创建失败(如内存不足),GPS_event_set 仍为 NULL,中断中调用 rt_event_send(NULL, ...) 会导致崩溃或静默失败。

解决:添加错误检查:


   GPS_event_set = rt_event_create("GPS_events", RT_IPC_FLAG_PRIO);
   if (GPS_event_set == RT_NULL) {
       rt_kprintf("Event create failed!n");
       return -1;
   }

2. 线程优先级问题


问题:线程优先级过低,导致无法及时抢占当前运行的线程。串口中断发送事件后,系统不会强制切换到低优先级线程。

解决



  • 提高线程优先级(确保高于其他非实时线程):
     tid = rt_thread_create("GPS_task", ..., 10 /* 优先级数值越小越高 */, ...);

  • 确认中断退出后调度器是否触发:在中断中发送事件后,可尝试手动触发线程切换:
     void USART_IRQHandler() {
         rt_event_send(GPS_event_set, FLAG);
         rt_schedule(); // 强制线程切换(需在中断上下文中谨慎使用)
    }


3. 线程未正确等待事件


线程代码可能存在的错误



  • 事件标志不匹配:发送和接收的标志位需一致(如 0x01)。  

  • 等待参数错误:未使用阻塞模式(RT_WAITING_FOREVER)。
    void gps_thread_entry(void *param) {
       rt_uint32_t recv_flag;
       while (1) {
           // 错误:未指定超时时间或标志位错误
           if (rt_event_recv(GPS_event_set, 0x01, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
                             RT_WAITING_FOREVER, &recv_flag) == RT_EOK) {
               rt_kprintf("Event received!n");
           }
       }
    }


4. 串口中断未正确触发


问题:串口中断配置错误,导致中断未触发或未调用发送事件的代码。

排查



  • 在中断处理函数中添加调试信息(谨慎使用):
     void USART_IRQHandler() {
         rt_kprintf("ISR entered!n"); // 确认中断触发
         rt_event_send(GPS_event_set, FLAG);
    }

  • 检查串口初始化配置(波特率、中断使能等)。


5. 中断上下文限制


问题:在中断中执行了非法操作(如使用阻塞函数),导致系统异常。

注意



  • rt_event_send() 可在中断中使用,但 rt_kprintf() 等非异步函数需避免。

  • 确保中断处理函数尽可能短促。


6. 事件被覆盖或遗漏


问题:线程处理速度慢,而中断发送事件过于频繁,导致事件标志被覆盖。

解决



  • 在接收时使用 RT_EVENT_FLAG_CLEAR 清除标志。

  • 增加事件标志位数,区分不同事件。




推荐解决方案步骤:



  1. 检查事件集创建:确保返回值非 NULL

  2. 提高线程优先级:设置为较高值(如 8-15),确保能抢占其他线程。

  3. 确认线程等待逻辑
    // 线程中正确等待事件
    rt_event_recv(GPS_event_set,
                 0x01, // 与发送的标志一致
                 RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
                 RT_WAITING_FOREVER, // 永久阻塞等待
                 RT_NULL);

  4. 中断中调试:临时添加日志确认中断触发和事件发送。

  5. 检查调度器状态:确保系统调度器已启动且未被锁住。


通过以上步骤排查,通常可解决中断发送事件线程无响应的问题。

举报

更多回帖

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