Фиксированное время выполнения задачи на KEIL RTX RTOS

Я использую KEIL RTX RTOS, который использовал упреждающий циклический планировщик. У меня есть ЖК-дисплей для отображения данных, и несколько задач имеют доступ к этому ЖК-дисплею (есть и другие задачи). Эти задачи требуют фиксированного времени для обработки ЖК-дисплея ( например, первый ЖК-дисплей дескриптора задачи для отображения данных в течение 50 секунд, а через 50 секунд второй дескриптор задачи и отображает данные в течение 10 секунд). Я знаю, что должен использовать мьютекс для управления доступом к ЖК-дисплею. Но я не знаю, как мне управлять им в фиксированное время? Задачи ЖК-дисплея имеют самый низкий приоритет, и если нет других задач для выполнения, эти задачи будут выполняться для отображения сообщений .


person Mahmoud Hosseinipour    schedule 17.11.2015    source источник


Ответы (3)


Сначала я попытаюсь ответить на ваш вопрос, но затем я собираюсь предложить вам альтернативный дизайн.

Вы должны использовать таймер, чтобы основывать что-либо в реальном времени, особенно относительно длительных периодов, таких как те, которые измеряются в секундах. Создайте два объекта Timer, один с периодом 50 секунд и один с периодом 10 секунд. Оба таймера должны быть одноразовыми. Также создайте два объекта Signal, один для указания, что истек 50-секундный период, а другой, чтобы указать, что истек 10-секундный период. Каждый из двух объектов Timer вызывает отдельные функции обратного вызова по истечении срока их действия. 50-секундная функция обратного вызова должна установить 50-секундный сигнал истечения, а затем запустить 10-секундный таймер. 10-секундная функция обратного вызова должна установить 10-секундный сигнал истечения срока действия, а затем перезапустить 50-секундный таймер. Таймеры будут пинг-понг взад и вперед, поочередно устанавливая два сигнала.

Теперь ваш ресурс, использующий задачи, должен периодически проверять наличие соответствующего Сигнала истечения срока действия. Когда задача замечает, что Сигнал установлен, она может отказаться от ресурса и очистить Сигнал. Другая задача делает то же самое с другим Сигналом. Таким образом, две задачи знают, когда отказаться от ресурса и позволить другой задаче получить его.

В вашем дизайне меня беспокоит то, что у вас есть два механизма синхронизации, защищающих ваш ресурс. Мьютекс - это механизм синхронизации. Когда задачи привязаны к использованию ресурса асинхронно (то есть в случайное время), мьютекс может использоваться для синхронизации этих использований и обеспечения того, чтобы только одна задача использовала ресурс в любой момент времени. Если у вас уже есть другой механизм синхронизации, то мьютекс вам, вероятно, не понадобится. Другими словами, если у ваших задач есть отдельные временные интервалы, в которых они используют ресурс, то они уже синхронны. Если они не собираются пытаться использовать ресурс в случайное время, мьютекс может не понадобиться.

Ваш дизайн также кажется сложным, и мне интересно, может ли этот альтернативный дизайн быть проще.

Подумайте о том, чтобы сделать одну задачу, которая отвечает за интерфейс ЖК-дисплея. Эта задача LDC - единственная задача, которая будет взаимодействовать с дисплеем. Ваши задачи с данными будут отправлять сообщения на ЖК-задачу, когда они производят данные для отображения. Задача ЖК-дисплея будет просто ждать этих сообщений и соответствующим образом отображать данные, когда они поступят. Вы можете использовать очередь сообщений или почтовую очередь для этой службы сообщений в зависимости от сложности и разнообразия данных. Теперь вам не нужен мьютекс для ЖК-дисплея, потому что его использует только одна задача. И вам все еще нужно разделение времени 50/10 секунд с этим дизайном? Я не уверен, потому что не знаю, что было источником этого требования.

person kkrambo    schedule 17.11.2015

Вместо того, чтобы иметь несколько потоков, обращающихся к одному ресурсу с арбитражем мьютексов, было бы проще иметь один поток, обрабатывающий ресурс.

В этом случае я предлагаю поток диспетчера отображения, другие потоки могут регистрироваться в диспетчере отображения, предоставляя, возможно, указатель на буфер отображения и требуемый период отображения. Затем диспетчер отображения просто циклически просматривает каждый зарегистрированный поток, отображая его буфер в течение требуемого периода, прежде чем переключиться на следующий.

Например (псевдокод):

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 ) ;
person Clifford    schedule 17.11.2015

Как упоминалось в предыдущих ответах, сначала создайте одну задачу для ЖК-дисплея, а затем используйте события таймера для отслеживания временного интервала.

Наконец, передайте задачу в обработчик событий таймера (вызываемый после временного интервала).

Если вы не знаете о yield, yield - это способ отказаться от выполнения задачи, чтобы позволить планировщику перейти к следующей задаче.

person sniper    schedule 23.11.2015
comment
В упреждающей ОСРВ не требуется уступка. - person Clifford; 26.11.2015