【问题标题】: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 是任务放弃执行以使调度程序移至下一个任务的一种方式。