Встраиваемые системы. Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С - Стивен Барретт
Шрифт:
Интервал:
Закладка:
else next_state = 'R';
break;
case 'A': /*из состояния активности(A)задача переходит в состояние */
/*определяемое значением переменной action. */
if (action == 'p') /*время ожидания или приостановка задачи*/
next_state = 'R'; /*возврат в состояние готовности*/
else if (action == 'w')
/*переход в состояние ожидания*/
next_state = 'W'; /*состояние ожидания */
else if (action == 'n') /*ресурс недоступен */
next_state = 'S';
/*задача переходит в состояние приостановки*/
else if (action == 'd')
/*завершается выполнение задачи*/
next_state = "X';
/*если требуется время для */
/* восстановления */
else if (action == 'x') /*задача исключается */
next_state = 'D'; /*возврат в состояние бездействия */
else next_state = 'A'; /*остается в состоянии активности */
break;
case 'X': /*из состояния восстановления (X) переход в состояние */
/*готовности (R)по сигналу таймера восстановления (t). */
if (action=='t') /*ожидается сигнал таймера восстановления*/
next_state='R'; /*задача переходит в состояние готовности*/
else next_state='X';
break;
case 'W': /*из состояния ожидания (W) переход в состояние готовности (R)*/
/*по сигналу таймера ожидания (e). */
if (action == 'e') /*ожидание сигнала таймера*/
next_state = 'R'; /*возврат в состояние готовности*/
else next_state = 'W';
break;
case 'S': /*из состояния приостановки (S) переход в состояние готовности (R)*/
/*при появлении ожидаемого ресурса (a) */
if (action == 'a') /*необходимый ресурс доступен*/
next_state = 'R'; /*переход в состояние готовности*/
else next_state = 'S';
break;
return next_state;
}
}
/********************************************************************/
Блок управления задачами. Как мы уже упоминали, задачи представляют собой независимые, асинхронные и взаимодействующие процессы, для взаимосвязанного выполнения которых необходим один и тот же процессор. Давайте вспомним о нашем бесстрашном официанте из предшествующего раздела. Официант (процессор) должен удовлетворять запросы нескольких заказчиков (задач), используя при этом ограниченные ресурсы. Так как официант (процессор) переключается с обслуживания одного столика заказчиков (от одной задачи) к другому, ему, или ей необходимо помнить состояние (контекст) каждого из столиков (задач), чтобы обеспечить качественное обслуживание.
В этом разделе мы рассмотрим, как ОСРВ «запоминает» и отслеживает состояние каждой задачи, чтобы позволить каждой задаче выполнить свой процесс. Вы, наверное, думаете: «А в чем сложности? Позвольте процессу, который стал активным завершиться». Но как мы иллюстрировали в примере с роботом, это невозможно. Так, в системе с большим количеством конкурирующих задач, некоторые задачи низким приоритетом никогда не выполнялись бы процессором. Вообразите, что случилось бы, если наш официант (процессор) посвятил все свое время одному столику (процесс) до полного его обслуживания, не обращая внимания на все остальные столики (задачи).
Мы не знаем точно, как хороший официант следит за многими столиками одновременно. А вот ОСРВ для отслеживания состояния каждой задачи обычно использует блок управления задачами (TCB). Каждая задача в ОСРВ имеет собственную связь с TCB, которая обеспечивает текущую информацию о задаче. Эта информация используется и модифицируется ядром ОСРВ, чтобы эффективно отслеживать, планировать и выполнять весь набор задач данной системы. Мы должны подчеркнуть, что TCB изменяется только операционной системой. Задача не имеет прямого контакта с TCB, хотя этот блок содержит наиболее обновленную информацию о задаче.
Структура TCB показана на рис. 8.15. Когда ОСРВ переключается с одной задачи на другую, вся ключевая информация о текущей задаче должна быть надежно сохранена перед переключением к следующей задаче. Таким образом, когда задача позже получает процессорное время, она может продолжить процесс с того места, где он был остановлен, при выгрузке. Как мы говорили ранее, эта ключевая информация задачи называется контекстом.
Рис. 8.15. Блок управления задачами
Прервемся на минуту, и подумаем, какая информация была бы важна для задачи. Рассмотрим также, как мы могли бы выполнить программное обеспечение TCB. Как минимум TCB должен содержать имя задачи, текущее состояние, приоритет, текущий контекст (ключевые значения регистров), и адрес, по которому можно найти этот контекст для обработки задачи.
Сначала, попробуем справится с разработкой программы для TCB. Данные, отражающие отдельные свойства каждой задачи имеют различные типы. Ранее в этой главе мы обсуждали запись или структуру — абстрактный тип данных, хорошо подходящий для программной реализации TCB. Как было упомянуто, структура представляет собой определяемую пользователем совокупность различных, но связанных между собой типов данных. Мы можем объединить эти различные типы данных в структуру и использовать ее для создания программы TCB. В главе мы уже разработали структуру для автомобиля и следили за самой разнообразной информацией о конкретных автомобилях, заключенной в полях структуры. Мы сделаем теперь то же самое для TCB. (На самом деле, мы попросим, чтобы это сделали вы в качестве задания 4 для самостоятельной работы). Используйте автомобильную структуру в качестве примера, и разработайте подобную структуру для TCB.
Рассмотрим подробнее отдельные поля для TCB и определим типы данных для каждого поля.
• Имя задачи состоит из символьного массива. Для примера робота мы ограничим имя задачи 20 символами. Это позволит нам сохранить полное имя для каждой задачи, не пользуясь маловразумительными сокращениями. Мы позволяем себе такую расточительность в использовании памяти ради удобочитаемости.
• Текущее состояние задачи: как следует из предыдущего раздела, задача в каждый момент времени может находиться в одном из шести состояний бездействия (D), готовности (R), активности (A), ожидания (W), приостановки (S) и восстановления (X). Мы обозначили каждое состояние задачи одним символом. Мы можем, следовательно, сохранять текущее состояние задачи в символьной переменной внутри нашей структуры TCB.
• Приоритет задачи: Для относительного ранжирования задач внутри системы, разработчиком системы назначается приоритет задачи. В нашем примере с роботом, мы использует фиксированные приоритетные значения. Но при необходимости можно выполнить и ОСРВ системы, в которых приоритет задачи может изменяться в процессе выполнения программы. Приоритет задачи представляется натуральными числами. В следующем примере мы покажем, как назначать приоритет задачи.
• Контекст задачи: Содержимое всех ключевых регистров связанных с задачей, составляет контекст задачи. Система прерывания, встроенная в микропроцессор 68HC12 использует стек, чтобы сохранить весь контекст, когда прерывание происходит. Мы также используем стек, чтобы сохранить контекст задачи. Каждая задача имеет собственный стек, следовательно, ОСРВ имеет целый ряд одновременно существующих стеков. Как программист системы, вы должны гарантировать, что эти стеки не будут смешиваться друг с другом в пространстве памяти. Для простоты, мы используем фиксированную структуру стека, разработанную ранее в этой главе для контекстной памяти TCB. Так как все ключевые регистры и ячейки памяти в микроконтроллере 68HC12 имеют объем в 8 или 16 бит, мы используем фиксированный массив целых чисел для стеков TCB.
• Состояние активности задачи: состояние активности задачи представляет собой следующий шаг программы, который должен выполняться, как только задача станет активной. После инициализации, задача начинается с начала соответствующего ей программного кода. Однако до своего полного завершения задача может неоднократно выгружаться задачами с более высоким приоритетом. Следовательно, TCB должен помнить следующий шаг, с которого должно продолжиться выполнение задачи.
• Указатель задачи: Так как мы будем связывать эти структуры TCB с помощью указателей, нам необходим указатель на следующий в списке TCB.
Вы уже, наверное, усвоили понятиям задачи и блока управления задачей. Однако мы еще не касались ряда сложных проблем. Вам, вероятно, не очень ясна идея выхода из программы до ее завершения, даже если она обладает наивысшим приоритетом. Мы исследуем эту тему в следующем разделе. Вы можете воображать осложнения, которые получатся, если мы начнем ATD-преобразование, а оно выгрузится событием с более высоким приоритетным прежде, чем будет закончено. И представьте себе, какая путаница возникнет, если это событие с более высоким приоритетом также должно будет использовать ATD-преобразование. Мы видим, что разработчик операционной системы должен определить, когда можно безопасно прервать управление задачи. Перед исследованием этих проблем, возвратимся к нашему примеру робота и посмотрим, как назначаются приоритеты задач.