Arm 在KEIL RTX RTO上执行任务的固定时间

Arm 在KEIL RTX RTO上执行任务的固定时间,arm,rtos,cortex-m3,cmsis,rtx,Arm,Rtos,Cortex M3,Cmsis,Rtx,我正在使用KEIL RTX RTOS,它使用先发制人的循环调度程序。我有一个用于显示数据的LCD,一些任务可以访问此LCD(还有一些其他任务),这些任务需要固定的时间来处理LCD(例如,第一个任务手柄LCD用于显示50秒和50秒后的数据,第二个任务手柄LCD用于显示10秒的数据)。我知道我必须使用互斥来管理对LCD的访问。但我不知道我必须如何管理固定时间的互斥?LCD任务的优先级最低,如果没有任何其他任务要执行,则将执行这些任务以显示消息。我将尝试先回答您的问题,然后我将为y提出另一种设计方案你

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

我将尝试先回答您的问题,然后我将为y提出另一种设计方案你要考虑。

您应该使用计时器来根据真实世界的时间,尤其是相对较长的周期,如以秒为单位测量的周期。创建两个计时器对象,一个为50秒周期,另一个为10秒周期。两个计时器都应为单次触发类型。还应创建两个信号对象,一个表示50秒ond period已过期,另一个用于指示10秒时间段已过期。两个计时器对象在过期时分别调用不同的回调函数。50秒回调函数应设置50秒过期信号,然后启动10秒计时器。10秒回调函数应设置10秒过期信号nal,然后重新启动50秒计时器。计时器将来回乒乓,交替设置两个信号

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

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

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


考虑制作一个负责LCD显示界面的单个任务。此LDC任务是唯一与显示器接口的任务。您的数据任务在生成要显示的数据时将向LCD任务发送消息。LCD任务只需等待这些消息,并在它们到达时适当显示数据。根据数据的复杂程度和多样性,您可以使用此消息服务的消息队列或邮件队列。现在,您不需要LCD显示屏的互斥,因为只有一个任务使用它。您还需要使用此设计的50/10秒时间分割吗?我不确定,因为我不知道是什么原因与其让多个线程访问由互斥体仲裁的单个资源,不如让单个线程处理该资源更简单

在本例中,我建议使用一个显示管理器线程,其他线程可以向显示管理器注册,提供一个指向显示缓冲区的指针和所需的显示周期。然后,显示管理器只需在每个注册线程中循环,在切换到下一个线程之前显示其缓冲区

例如(伪代码):


正如前面的回答中提到的,首先为LCD显示创建一个任务,然后使用计时器事件跟踪时间片

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


如果您不知道收益率,收益率是任务放弃执行的一种方式,以使调度程序能够移动到下一个任务。

在先发制人的RTO中,收益率应该是不必要的。
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 ;
    }
}
displayLock( my_display_handle ) ;
update_display_buffer() ;
displayUnlock( my_display_handle ) ;