【问题标题】:Fixed time for executing a task on the KEIL RTX RTOS修复了在 KEIL RTX RTOS 上执行任务的时间
【发布时间】:2016-02-18 11:04:38
【问题描述】:

我正在使用 KEIL RTX RTOS,它使用了抢先式循环调度程序。我有一个用于显示数据的 LCD,一些任务可以访问这个 LCD(还有一些其他任务),这些任务需要固定时间来处理LCD(例如,第一个任务句柄 LCD 用于显示其数据 50 秒,50 秒后,第二个任务句柄并显示其数据 10 秒)。我知道我必须使用互斥锁来管理对 LCD 的访问。但我不知道我必须如何管理它的固定时间?LCD 任务处于最低优先级,如果没有任何其他任务要执行,这些任务将被执行以显示消息.

【问题讨论】:

    标签: arm rtos cortex-m3 cmsis rtx


    【解决方案1】:

    我会先尝试回答你的问题,然后我会提出一个替代设计供你考虑。

    您应该使用 Timer 来以真实世界时间为基础,尤其是相对较长的时间段,例如以秒为单位的时间段。创建两个 Timer 对象,一个具有 50 秒的周期,一个具有 10 秒的周期。两个计时器都应该是一次性的。还要创建两个 Signal 对象,一个指示 50 秒周期已过期,另一个指示 10 秒周期已过期。两个 Timer 对象在到期时各自调用不同的回调函数。 50 秒回调函数应该设置 50 秒过期信号,然后启动 10 秒 Timer。 10 秒回调函数应该设置 10 秒过期信号,然后重新启动 50 秒 Timer。计时器将来回乒乓,交替设置两个信号。

    现在您的资源使用任务应该定期检查适当的到期信号。当任务观察到信号已设置时,它可以放弃资源并清除信号。另一个任务对另一个信号做同样的事情。这样两个任务就知道何时放弃资源并允许另一个任务获得它。

    您的设计让我感到困扰的一点是,您有两种同步机制来保护您的资源。互斥锁是一种同步机制。当任务要异步使用资源时(即随机时间),可以使用互斥锁来同步这些使用情况,并确保在任何给定时间只有一个任务在使用资源。如果您已经有另一种同步机制,那么您可能不需要互斥锁。换句话说,如果您的任务有不同的时间段来使用资源,那么它们已经是同步的。如果他们不打算在随机时间尝试使用资源,那么您可能不需要互斥锁。

    您的设计似乎也很复杂,我想知道这种替代设计是否会更简单。

    考虑制作一个负责 LCD 显示界面的任务。此 LDC 任务是唯一与显示器交互的任务。当您的数据任务产生要显示的数据时,它们将向 LCD 任务发送消息。 LCD 任务将简单地等待这些消息并在它们到达时适当地显示数据。根据数据的复杂程度和变化程度,您可以为此消息服务使用消息队列或邮件队列。现在您不需要 LCD 显示器的互斥体,因为只有一个任务使用它。你还需要这种设计的 50/10 秒时间分割吗?我不确定,因为我不知道该要求的来源。

    【讨论】:

      【解决方案2】:

      如果让多个线程访问由互斥体仲裁的单个资源,那么让单个线程处理资源会更简单。

      在这种情况下,我建议使用显示管理器线程,其他线程可以向显示管理器注册,可能提供指向显示缓冲区的指针,以及所需的显示周期。然后,显示管理器只需在每个已注册线程中循环显示其缓冲区所需的时间,然后再切换到下一个。

      例如(伪代码):

      static struct 
      {
          const char* frame_buffer ;
          int display_seconds ;
          OS_MUTEX mutex ;
      
      } display_registry[MAX_DISPLAY_THREADS] = {0,0} ;
      
      void displayLock( int handle )
      {
          if( handle >= 0 && handle < MAX_DISPLAY_THREADS )
          {
              os_mutex_lock( display_registry[handle].mutex ) ;
          }
      }
      
      void displayUnock( int handle )
      {
          if( handle >= 0 && handle < MAX_DISPLAY_THREADS )
          {
              os_mutex_unlock( display_registry[handle].mutex ) ;
          }
      }
      
      void lcd_thread
      {
          int display = 0 ;
      
          for(;;)
          {
              int t = 0 ;
              while( t < display_registry[display].display_seconds &&
                     display_registry[display].frame_buffer != 0 )
              {
                  displayLock( display ) ;
                  render_display( display_registry[display].frame_buffer ) ;
                  displayUnlock( display ) ;
      
                  delay( ONE_SECOND ) ;
              }
      
              display = (display + 1) % MAX_DISPLAY_THREADS ;
          }
      }
      
      int displayRegister( const char* frame_buffer, int display_seconds )
      {
          for( int i = MAX_DISPLAY_THREADS - 1; 
               frame_buffer[i] != 0 && 
               i >= 0; i-- )
          {
              // do nothing
          }
      
          if( i >= 0 )
          {
              display_registry[i].display_seconds = display_seconds ;
              display_registry[i].frame_buffer = frame_buffer ;
          }
      
          return i ; // handle for de-registering/locking
      }
      
      void displayDeregister( int handle )
      {
          if( handle >= 0 && handle < MAX_DISPLAY_THREADS )
          {
              display_registry[handle].frame_buffer = 0 ;
          }
      }
      

      注意,互斥锁不是锁定LCD资源,而是锁定共享内存帧缓冲资源。

      然后,其他线程只需将要显示的数据放在它们自己的帧缓冲区中,与显示该数据完全异步,例如:

      displayLock( my_display_handle ) ;
      update_display_buffer() ;
      displayUnlock( my_display_handle ) ;
      

      【讨论】:

        【解决方案3】:

        如前面的答案中提到的,首先为 LCD 显示制作单个任务,然后使用计时器事件来跟踪时间片。

        最后,在计时器事件处理程序(在时间片之后调用)中生成任务。

        如果您不了解 yield,yield 是任务放弃执行以使调度程序移至下一个任务的一种方式。

        【讨论】:

        • 在抢占式 RTOS 中应该不需要让步。
        猜你喜欢
        • 2016-12-26
        • 1970-01-01
        • 2016-12-03
        • 2011-02-27
        • 2019-12-09
        • 2016-03-12
        • 2018-03-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多