8.4.2. Управление задачами
В этом разделе мы рассмотрим, как ОСРВ взаимодействует с отдельной задачей. Сначала мы рассмотрим различные состояния, в которых может находиться задача. Затем исследуем, как задачи переходят из одного состояния в другое, и рассмотрим программную функцию, позволяющую моделировать состояния задач и их связь друг с другом. Это обсуждение будет частью полного обсуждения блока управления задачами.
Состояния задачи. В любой момент времени задача может быть только в одном определенном состоянии. Различные состояния задачи показаны на рис. 8.14. ОСРВ должна отслеживать и изменять состояние каждой задачи. Не забудем при этом, что все задачи независимы, асинхронны и претендуют на процессорное время. ОСРВ должна обеспечить эффективное планирование этого дефицитного ресурса.
Рис. 8.14. Состояния задач
Задача находится в одном из следующих состояний:
• Бездействия (Dormant — D): задача не нуждается в обработке и не требует процессорного времени. Она рассматривается как удаленная или неактивная задача, и по сигналу операционной системы переходит в состояние готовности.
• Готовности (Ready — R): задача полностью готова к переходу в активное состояние; однако, в настоящее время процессор занят другой задачей. Задача может переходить в состояние готовности из состояний бездействия или активности. Она переходит от активного состояния в состояние готовности, когда процессор обрабатывает другую более приоритетную задачу. Зарезервированная задача с более низким приоритетом (находящаяся в состоянии готовности) повторно переходит в активное состояние, как только становится доступным процессорное время и операционной системой дается разрешение на выполнение.
• Активности (Executing/active/running — A): задача управляется процессором, выполняя часть своей программы. Так как наша система содержит только один процессор, только одна задача может быть в активном состоянии в любое данное время. Задача остается в активном состоянии, пока не происходит одно из трех событий:
1) завершаются необходимые для выполнения задачи действия;
2) она выгружается задачей с более высоким приоритетом;
3) она возвращает управление операционной системе.
Во всех этих случаях задача переходит от активного состояния в состояние готовности. Эти варианты станут более ясными, когда мы обсудим различные типы систем ОСРВ в разделе 8.5. Из активного состояния задача может также переходить в состояния ожидания.
• Ожидание (Wait — W): выполнение задачи было отсрочено. Она остается в ждущем состоянии на заданном отрезке времени и затем переходит в состояние готовности, ожидая обработки. Задача переводится в состояние ожидания временно, чтобы выделить время для обработки задач с более низким приоритетом.
• Приостановка (suspended — S): задача ждет некоторого ресурса. Как только ресурс становится доступным, задача переходит в состояние готовности и ждет процессорного времени.
• Восстановление (rescheduling — X): Это состояние вводится каждый раз, когда задача выполнена, но не может сразу же перейти в состояние готовности. В этом случае, задача остается в состоянии восстановления, пока не закончится необходимый интервал восстановления (RSI). Как только это происходит, задача снова переходит в состояние готовности.
Приведенная диаграмма состояний задач может быть выполнена с помощью программного кода, использующего команду switch, которая позволяет нам точно управлять переходами в зависимости от состояния.
/********************************************************************/
char task_state_diagram(char present_state, char action) {
char next_state;
switch (present_state) {
case 'D': /*если состояние бездействия (D) и выбрана опция create(c), то */
/* задача переходит в состояние готовности, в противном */
/* случае она остается в состоянии бездействия (D) */
if (action == 'с') next_state = 'R';
else next_state = 'D';
break;
case 'R': /*если задача в состоянии готовности (R), процессор доступен */
/* и задача имеет наивысший приоритет,то она переходит в */
/* активное состояние (A). Это состояние обозначается */
/*присвоением переменной action значения (g). */
if (action == 'g') next_state = 'A';
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-преобразование. Мы видим, что разработчик операционной системы должен определить, когда можно безопасно прервать управление задачи. Перед исследованием этих проблем, возвратимся к нашему примеру робота и посмотрим, как назначаются приоритеты задач.
Сценарий: В нашем примере с роботом у нас было много задач по обеспечению его работы. Теперь мы должны назначить численное значение приоритета для каждой задачи. Мы будем использовать более низкое численное значение для задач с более высоким приоритетом. Например, задаче с самым высоким приоритетом сопоставим значение 1. Мы используем наше понимание сценария работы робота, чтобы назначить приоритеты задач. Так как наш робот дезактивируется, когда приближается к мине, мы присваиваем задаче обнаружения мин приоритет 1. Следующий самый высокий приоритет, равный 2 присвоим операции объезда мины. Задаче ATD-преобразования присвоим приоритет 3, так как она обеспечивает информацию о близости стенок лабиринта. Задаче выбора поворота присвоим следующий приоритет 4, так как она обрабатывает информацию, необходимую, чтобы избежать столкновения со стенками. Наконец, задаче модификации ЖКД назначаем приоритет 5. Это самый низкий приоритет для задач, рассмотренных к настоящему времени; однако, приоритет всех прочих задач еще ниже. Остающиеся задачи имеют еще более низкий приоритет. Они активны на начальных этапах работы нашей операционной системы, а затем входят в состояние бездействия. Мы, следовательно, назначаем им самый низкий приоритет, давая им приоритеты 6 (инициализация ЖКД), 7 (инициализация ATD), и 8 (инициализация ШИМ).
Фрагментация задач. Как мы уже выяснили в этом разделе, желательно разделить программный код задачи на непрерываемые части или фазы, определив удобные точки выхода. Это важно, поскольку в ОСРВ с несколькими задачами с одинаковым приоритетом, задача редко будет способна завершить связанные с ней действия от начала до конца. Чаще всего задача завершит некоторую часть действий и затем будет приостановлена задачей или задачами с более высоким приоритетом. Факт перехода задачи с более высоким приоритетом в состояние готовности еще не означает, что процессорное время немедленно передается ей. Мы должны организовать переход от одной задачи к другой, прервав выполнение кода в заранее определенном удобном для этого месте. Поскольку мы записываем контекст прерываемой задачи, мы должны сохранить его в памяти. Например, мы можем подразделять связанную с задачей функцию на три части. Первый раз, когда задача становится активной, процессор выполняет первую треть кода до удобной отметки прерывания (определенной вами, как программистом). Когда код достигает этой отметки прерывания, контекст сохраняется в TCB, и процессор прерывает управление задачей. Затем выполняется задача с более высоким приоритетом. Когда прерванная задача снова получает для своего выполнения драгоценное процессорное время, она начинается с того места, где была прервана и продолжает обработку второй части своего кода. Этот процесс продолжается, пока задача не завершает все предусмотренные действия.
Проиллюстрируем такую работу примером.
Пример: Предположим, что робот, имеющий пять ИК локаторов (рис. 8.16) выполняет функцию названную process_turn, которая инициализирует систему ATD контроллера 68HC12, начиная последовательность преобразований, необходимую, чтобы записать аналоговые сигналы от пяти датчиков (с номерами от 0 до 4), которые связаны с каналами ATD от 7 до 3, соответственно. Выход датчика Холла, установленного в нижней части робота, чтобы обнаруживать магнитные мины, связан с каналом 2 ATD. Обратите внимание: этот пример придуман, чтобы показать, как следует подразделять код, чтобы обеспечить удобные точки прерывания.
Рис. 8.16. Робот c пятью ИК локаторами и датчиком Холла. ИК-датчик обнаруживает присутствие стенок лабиринта, в то время как датчик Холла обнаруживает присутствие магнитных мин.
Код process_turn, обеспечивающий процесс поворота, приведен ниже.
void process_turn() {
/*Инициализация системы ATD */
ATDCTL2 = 0x80; /*установка флага ADPU, чтобы подать питание на систему ATD*/
ATDCTL3 = 0x00; /*игнорировать «замораживание» системы */
ATDCTL4 = 0x7F; /*Снижение частоты таймера P до 125 кГц */
/*выборка, время преобразования = 32 ATD цикла */
/* 1 выборка за каждые 256 мкс */
for (i=0; i<67; i++) { /* ожидание 100 мкс при 8 МГц ECLK*/
;
}
/*Инициализация ATD-преобразования */
ATDCTL5 = 0x50; /*Начать многоканальное ATD-преобразование */
/* для 8 каналов */
while((ATDSTAT & 0x8000) == 0) { /* проверить окончание преобразования по*/
/*состоянию флага SCF */
;
}
/* сохранить результаты ATD-преобразования*/
/* в глобальном массиве char*/
sens[0] = ADR7H; /*крайний левый датчик */
sens[1] = ADR6H; /*средний левый датчик */
sens[2] = ADR5H; /*центральный датчик */
sens[3] = ADR4H; /*средний правый датчик */
sens[4] = ADR3H; /*крайний правый датчик */
sens[5] = ADR2H; /*Датчик Холла*/
/*анализ информации датчиков для решения о повороте. Примечание: пороги для*/
/*датчика Холла(hes_threshold) и для ИК-датчиков (opto_threshold)являются*/
/* глобальными переменными и определены экспериментально*/
if (sens[5] < hes_threshold) { /*сигнал с датчика Холла, объезд*/
pwm_motors(back_up); /* робот дает задний ход*/
/*действия, следующие после того */
/* как робот отъехал назад */
if(sens[0] > opto_threshold) pwm_motors(right_turn);
else pwm_motors(left_turn);
for(i=0; i<0xFFFF; i++) { /*задержка перед вращением двигателя */
for(j=0; j<15; j++){
;
}
}
}
/*если обнаружен тупик - задний ход*/
else if((sens[2]>opto_threshold) && (sens[0]>opto_threshold) && (sens[4]>opto_threshold)) {
pwm_motors(back_up);
}
/*если стенки спереди и слева, */
/*поворот робота направо */
else if((sens[0]>opto_threshold) && (sens[2]>opto_threshold)) {
pwm_motors(right_turn);
}
/*если стенки спереди и справа, */
/*поворот робота налево */
else if((sens[2]>opto_threshold) && (sens[4]>opto_threshold)) {
pwm_motors(left_turn);
}
/*если стенка перед средним правым */
/* датчиком, то полуповорот направо */
else if (sens[1] > opto_threshold) {
pwm_motors(half_right);
}
/*если стенка перед средним левым */
/* датчиком, то полуповорот налево */
else if (sens[3]>opto_threshold) {
pwm_motors(half_left);
}
/*если сигналов от датчиков нет, продолжить движение вперед*/
else {
pwm_motors(forward);
}
}
Если мы хотим подразделить этот код на три части обрабатываемые ОСРВ без прерывания, мы можем вставить точки прерывания после последовательности инициализации ATD и после последовательности записи данных с ATD. Это позволит функции без проблем прерывать и восстанавливать управление процессором. Чтобы выполнять эти изменения, мы должны ввести переменную, которую мы назовем code_section. Эта переменная позволит нам проследить, какая из трех частей кода должна быть выполнена при очередной активности задачи.
int process_turn(int code_section) {
switch(code_section) {
case 0:
/*Инициализация системы ATD */
ATDCTL2 = 0x80; /*включение ATD */
ATDCTL3 = 0x00; /*игнорировать доступ при отладке системы */
ATDCTL4 = 0x7F; /*Снижение частоты таймера P до 125 кГц */
/*выборка, время преобразования = 32 ATD цикла */
/* 1 выборка за каждые 256 мкс */
for (i=0; i<67; i++) {
/* ожидание 100 мкс при 8 МГц ECLK*/
;
}
code_section = 1; /*update code_section variable */
break;
case 1:
/*Инициализация ATD-преобразования */
ATDCTL5 = 0x50; /*Начать многоканальное ATD-преобразование*/
/* для 8 каналов */
while ((ATDSTAT & 0x8000) == 0) {
/* проверить окончание преобразования по*/
/*состоянию флага SCF */
;
}
/* сохранить результаты ATD-преобразования*/
/* в глобальном массиве char */
sens[0] = ADR7H; /*крайний левый датчик */
sens[1] = ADR6H; /*средний левый датчик */
sens[2] = ADR5H; /*центральный датчик */
sens[3] = ADR4H; /*средний правый датчик */
sens[4] = ADR3H; /*крайний правый датчик */
sens[5] = ADR2H; /*Датчик Холла */
code_section = 2; /*update code_section variable */
break;
case 2:
/*анализ информации датчиков для решения о повороте. Примечание: пороги для*/
/*датчика Холла(hes_threshold) и для ИК-датчиков (opto_threshold)являются*/
/* глобальными переменными и определены экспериментально*/
if (sens[5] < hes_threshold) { /*сигнал с датчика Холла, объезд*/
pwm_motors(back_up); /* робот дает задний ход*/
/*действия, следующие после того */
/* как робот отъехал назад */
if (sens[0] > opto_threshold) pwm_motors(right_turn);
else pwm_motors(left_turn);
for (i=0; i<0xFFFF; i++) { /*задержка перед вращением двигателя */
for(j=0; j<15; j++) {
;
}
}
}
/*если обнаружен тупик - задний ход*/
else if ((sens[2]>opto_threshold) && (sens[0]>opto_threshold) && (sens[4]>opto_threshold)) {
pwm_motors(back_up);
}
/*если стенки спереди и слева, */
/*поворот робота направо */
else if((sens[0]>opto_threshold) && (sens[2]>opto_threshold)) {
pwm_motors(right_turn);
}
/*если стенки спереди и справа, */
/*поворот робота налево */
else if((sens[2]>opto_threshold) && (sens[4]>opto_threshold)) {
pwm_motors(left_turn);
}
/*если стенка перед средним правым */
/* датчиком, то полуповорот направо */
else if (sens[1] > opto_threshold) {
pwm_motors(half_right);
}
/*если стенка перед средним левым */
/* датчиком, то полуповорот налево */
else if (sens[3]>opto_threshold) {
pwm_motors(half_left);
}
/*если сигналов от датчиков нет */
/*продолжить движение вперед */
else {
pwm_motors(forward);
}
code_section = 0; /* изменить переменную code_section */
break;
}/*конец switch*/
return code_section;
}
Когда задача, связанная с функцией process_turn, переходит из состояния готовности в активное состояние, ОСРВ вызывает функцию с параметром 0. Функция process_turn затем выполняется до первой отметки прерывания в коде. Достигнув этой отметки, функция возвращает управление ОСРВ, которая модифицирует TCB, связанный с процессом и продолжает выполнение второй части кода, когда задача в очередной раз переходит в активное состояние. Затем задача снова возвращается в состояние готовности и ждет, когда ОСРВ выделит ей процессорное время. Повторим снова, что причина, по которой мы делим код на логические части, состоит в том, чтобы позволить задаче работать до завершения определенной части и затем позволить другой задаче выполнить часть связанного с ней кода, и т.д. Это дает возможность выполнять несколько появившихся задач практически одновременно, хотя в любой момент времени процессор выполняет только одну задачу.
В этом примере мы использовали глобальные переменные, чтобы сохранять информацию между последовательными обращениями к функции process_turn. Использование глобальных переменных может быть не самое лучшее использование дефицитных ресурсов памяти RAM. Далее в этой главе мы рассмотрим альтернативные методы движения информации между задачами.
Как можно предположить из этого примера, ядро ОСРВ должно быть довольно сложным, чтобы позволить следить за множеством задач, эффективно планировать использование процессорного времени и полностью выполнять функции, необходимые для конкретного применения. В следующем разделе мы исследуем составляющие части ядра ОСРВ и их взаимодействие друг с другом, позволяющие удовлетворить требования применения.
- Встраиваемые системы Проектирование приложений на микроконтроллерах семейства 68hc12/hcs12 с применением языка с с. Ф. Баррет
- Предисловие
- Структура книги
- Учебные системы
- Целевая аудитория
- Благодарности
- Глава 1 первое знакомство со встраиваемыми системами
- 1.1. Что такое встраиваемая система?
- 1.2. Особенности встраиваемых систем
- 1.2.1. Работа в реальном времени
- 1.2.2. Миниатюризация размеров и процесс тестирования
- 1.2.3. Минимизация энергии потребления
- 1.2.4. Интерфейс пользователя и интерфейс сопряжения с объектом
- 1.2.5. Многозадачность
- 1.2.6. Минимизация стоимости
- 1.2.7. Ограничение объема памяти
- 1.2.8. Программно–аппаратный дуализм
- 1.3. Введение в микроконтроллеры семейства 68hc12 и hcs12
- 1.4 Микроконтроллеры hcs12
- 1.4.1. Семейство hcs12
- 1.4.2. Обозначения мк
- 1.4.3. Модельный ряд hcs12
- 1.5. Заключение по главе 1
- 1.6. Вопросы и задания Основные
- Более сложные
- Исследовательские
- Глава 2 программирование встраиваемых систем и структурное проектирование
- 2.1. Почему мы программируем микроконтроллеры на Си?
- 2.2. Преимущества программирования на языке ассемблер
- 2.3. Преимущества языков высокого уровня
- 2.3.1. Выбираем язык высокого уровня для программирования встраиваемых систем
- 2.3.2. Краткая история языка Си
- 2.4. Оптимальная стратегия — программирование на Си и на ассемблере
- 2.5. Структурное проектирование
- 2.5.1. Основные положения метода структурного проектирования
- 2.5.2. Документирование программ
- 2.5.3. Как язык Си соотносится со структурным проектированием
- 2.6. Рабочие тетради
- 2.6.1. Порядок ведения записей
- 2.6.2. Содержание записей
- 2.7. Блок схемы алгоритмов
- 2.8. Пример применения
- 2.9. Заключение по главе 2
- 2.10 Что еще почитать?
- 2.11 Вопросы и задания Основные
- Более сложные
- Исследовательские
- Глава 3 основы программирования микроконтроллеров на си
- 3.1. Введение в программирование на Си
- 3.1.1. Глобальные и локальные переменные
- 3.2. Типы данных в Си
- 3.3. Операторы языка Си
- 3.4. Функции
- 3.4.1. Что такое функция?
- 3.4.2. Основная программа
- 3.4.3. Прототипы функций
- 3.4.4. Описание функций
- 3.4.5. Вызов функций, передача параметров, возврат полученных значений
- 3.5. Файлы заголовков
- 3.6. Директивы компилятора
- 3.6.1. Директивы условной компиляции
- 3.7. Конструкции программирования
- 3.8. Операторы для организации программных циклов
- 3.8.1. Оператор for
- 3.8.2. Оператор while
- 3.8.3. Оператор do-while
- 3.9. Операторы принятия решения
- 3.9.1. Оператор if
- 3.9.2. Оператор if-else
- 3.9.3. Оператор if-else if-else
- 3.9.4. Оператор switch
- 3.10. Массивы
- 3.11. Указатели
- 3.12. Структуры
- 3.13. Процесс программирования и отладки микропроцессорной системы
- 3.13.1. Технология создания программного кода
- 3.13.2. Режим отладки bdm
- 3.13.3. Аппаратные и программные средства отладчика p&e от компании pemicro
- 3.13.4. Эмуляторы
- 3.13.5. Логические анализаторы
- 3.14. Особенности компилятора и ассемблера
- 3.15. Заключение по главе 3
- 3.16. Что еще почитать?
- 3.17. Вопросы и задания Основные
- Более сложные
- Исследовательские
- Глава 4 микроконтроллеры 68hc12 и hcs12: архитектура и программирование
- 4.1. Аппаратные средства микроконтроллеров семейства 68hc12
- 4.2. Аппаратные средства мк семейства hcs12
- 4.3. Режимы работы мк семейства 68hc12/hcs12
- 4.3.1. Рабочие режимы
- 4.3.2. Режимы работы отладочной платы m68evb912b32
- 4.4. Назначение выводов мк
- 4.5. Регистры специальных функций мк
- 4.5.1. Виртуальный адрес блока регистров
- 4.6. Порты ввода/вывода
- 4.6.1. Спецификация портов ввода/вывода
- Регистры управления портами
- Вопросы для самопроверки
- Пример применения
- 4.7. Подсистема памяти мк b32
- Пример применения
- 4.7.1. Карта памяти мк b32
- 4.7.2. Изменение адресов в карте памяти мк
- 4.8. Подсистема памяти мк dp256
- Вопросы для самопроверки
- 4.9. Состояния сброса и прерывания мк
- 4.9.1. Реакция мк на внешние события
- 4.10. Состояния сброса и прерывания в мк 68hc12
- 4.10.1. Состояние сброса мк
- Регистры сторожевого таймера и монитора тактирования
- 4.10.2. Прерывания
- Немаскируемые прерывания
- Маскируемые прерывания
- Вопросы для самопроверки
- 3. Каково различие между прерываниями по входам
- 4. Как организовать подсистему прерывания с несколькими внешними запросами для мк семейства 68hc12/hcs12, используя лишь один вход внешнего прерывания
- 4.10.3. Вектора исключений
- 4.10.4. Система приоритетов для исключений
- 1. Внешний сброс по входу
- 5. Немаскируемое прерывание по входу
- Вопросы для самопроверки
- 4. Какие действия должен предпринять программист, чтобы после начального запуска мк присвоить входу
- 4.10.5. Регистры подсистемы прерывания
- 4.11. Процесс перехода к подпрограмме прерывания
- Вопросы для самопроверки
- 4.12. Оформление подпрограммы прерывания на Си
- 4.13. Система тактирования
- 4.13.1.Система тактирования отладочной платы mc68hc912b32evb
- 4.14. Подсистема реального времени — модуль таймера
- 4.14.1. Структура модуля таймера
- 4.14.2. Счетчик временной базы
- Особенности счетчика временной базы
- Флаг переполнения счетчика
- Определение длительности временных интервалов
- Сброс счетчика временной базы
- Вопросы для самопроверки
- 4.14.3. Регистры для управления счетчиком временной базы
- Регистр управления модулем таймера
- Регистр счетчика временной базы
- Регистр масок таймера 2
- 4.14.4. Каналы захвата/сравнения
- Режим входного захвата
- Вопросы для самопроверки
- Режим выходного сравнения
- Канал 7 в режиме выходного сравнения
- Регистры для управления каналами захвата/сравнения
- Регистры управления таймером 3 и 4
- Регистр масок таймера 1
- Регистр масок таймера 2
- Регистр флагов таймера 1
- Регистр флагов таймера 2
- Регистры данных каналов захвата/сравнения
- Вопросы для самопроверки
- Примеры работы с таймером
- Измерение частоты и периода логического сигнала
- Генерация импульсной последовательности
- Генерация импульсной последовательности с использованием прерывания
- 4.14.5. Счетчик событий
- Режимы работы счетчика
- Регистры управления счетчиком событий
- Регистр управления счетчиком событий
- Регистр флагов счетчика событий
- Регистр текущего состояния счетчика событий
- Пример использования счетчика событий
- 4.15. Модуль меток реального времени
- Пример использования модуля меток реального времени
- 4.16. Модуль таймера ect в составе мк мc68hc12be32 и hcs12
- 4.16.1. Небуферированные каналы входного захвата
- 4.16.2. Буферированные каналы входного захвата
- 4.16.3. Особенности счетчиков событий
- 4.16.4. Регистры управления модуля est
- Регистр управления порядком перезаписи
- Регистр управления режимом входного захвата
- Регистр управления счетчиком задержки
- Регистр управления 16-разрядным вычитающим счетчиком
- Регистр коэффициента счета вычитающего счетчика
- Регистр флагов вычитающего счетчика
- 4.17. Обмен информацией в последовательном коде: многофункциональный последовательный интерфейс
- 4.17.1. Термины последовательного обмена
- Вопросы для самопроверки
- 4.18. Контроллер асинхронного обмена sci
- Вопросы для самопроверки
- 4.18.1. Передатчик контроллера sci
- 4.18.2. Приемник контроллера sci
- 4.18.3. Регистры контроллера sci
- Регистры скорости обмена sCxBdh и sCxBdl
- Регистры управления sCxCr1 и sCxCr2
- Регистры состояния sCxSr1 и sCxSr2
- Регистры данных sCxDrh и sCxDrl
- Вопросы для самопроверки
- 4.18.4. Алгоритмы программного обслуживания контроллера sci
- 4.18.5. Пример программирования контроллера sci
- 4.19. Синхронный последовательный интерфейс spi
- 4.19.1 Концепция интерфейса spiФункциональная схема обмена между двумя контроллерами spi
- 4.19.2. Алгоритмы работы контроллера spi
- Вопросы для самопроверки
- 4.19.3. Регистры контроллера spi
- Регистр скорости обмена sPxBr
- Регистры управления sPxCr1 и sPxCr2
- Регистр данных spCxDr
- Регистр данных порта s
- Регистр направления передачи порта s
- Вопросы для самопроверки
- 4.19.4. Алгоритмы программного обслуживания контроллера spi
- 4.19.5 Периферийные ис с интерфейсом spi
- 4.20. Введение в теорию аналого-цифрового преобразования
- 4.20.1. Частота дискретизации сигнала
- 4.20.2. Представление аналоговой величины в цифровом коде
- 4.20.3.Квантование по уровню и разрешающая способность
- 4.20.4 Скорость потока данных оцифровки
- Вопросы для самопроверки
- 4.21. Принцип действия ацп
- 4.21.1. Ацп последовательного приближения
- Вопросы для самопроверки
- 4.22. Подсистема аналого-цифрового преобразования мк 68hc12
- 4.22.1 Структура и порядок функционирования
- 4.22.2. Регистры управления модуля atd
- Группа регистров управления
- Регистры управления atdctl0 и atdctl1
- Регистр управления atdctl2
- Регистр управления atdctl3
- Регистр управления atdctl4Формат регистра atdctl4
- Регистр управления atdctl5
- Вопросы для самопроверки
- Регистр состояния atdstat
- Регистр данных порта portad
- Регистры результата adr0h…adr7h
- Вопросы для самопроверки
- Тестовый регистр atdtest
- 4.22.3. Пример программирования модуля atd
- Цифровой вольтметр
- 4.22.4. Обслуживание прерываний от модуля atd
- 4.23. Особенности модуля atd в составе мк семейства hcs12
- 4.23.1. Выбор разрядности ацп
- 4.23.2. Представление результата измерения
- 4.23.3. Запуск измерительной последовательности от внешнего сигнала
- 4.23.4. Программируемое число преобразований в измерительной последовательности
- 4.23.5. Увеличение числа аналоговых входов
- 4.23.6. Регистры модуля atd hcs12
- Регистр состояния atdstat0
- Регистр состояния atdstat1
- Регистр разрешения цифрового входа порта atddien
- 4.24. Подсистема широтно-импульсной модуляции
- 4.24.1. Структура модуля pwm
- 4.24.2. Режимы центрированной и фронтовой шим
- 4.24.3. Система тактирования
- 4.24.4. Регистры модуля pwm
- Регистр конфигурации pwclk
- Регистр конфигурации pwpol
- Регистр разрешения работы каналов pwen
- Регистр дополнительного делителя pwpres
- Регистры делителей pwscnt0/pwscnt1 и pwscal0/pwscal0
- Регистры счетчика каналов pwcnTx
- Регистры периода каналов pwpeRx
- Регистры коэффициента заполнения каналов pwdtYxФормат регистров коэффициента заполнения pwdtYx
- Регистры коэффициента заполнения каналов pwdtYx
- Регистр управления pwctl
- Регистр специальных режимов pwtst
- Регистры работы с портом p
- 4.24.5. Примеры программирования модуля pwm
- Инициализация модуля pwm, пример 1
- Инициализация модуля pwm, пример 2
- 4.25. Ограничение энергии потребления
- 4.25.1. Как остановить мк 68hc12
- 4.25.2. Как вывести мк 68hc12 из состояния пониженного энергопотребления
- 4.26. Советы по использованию платы отладки mc68evb912b32
- 4.27. Заключение по главе 4
- 4.28. Что еще почитать?
- 4.29. Вопросы и задания Основные
- Исследовательские
- Глава 5 основы сопряжения мк с устройствами ввода/вывода
- 5.1. Электрические характеристики мк 68hc12
- 5.1.1. Нагрузочные характеристики
- 5.1.2. Что произойдет, если Вы должным образом не учтете электрические характеристики периферийных ис?
- 5.1.3. Входные и выходные характеристики логических элементов
- 5.2. Устройства дискретного ввода: кнопки, переключатели, клавиатуры
- 5.2.1. Кнопки и переключатели
- 5.2.2. Dip переключатели
- 5.2.3. Клавиатуры
- 5.3. Устройства индикации: светодиоды, семисегментные индикаторы, индикаторы логического выхода с тремя состояниями
- 5.3.1. Светодиоды
- 5.3.2. Семисегментные индикаторы
- 5.3.3. Индикаторы для логического выхода с тремя состояниями
- 5.4. Программное обслуживание дискретных входов и выходов
- 5.5. Подавление механического дребезга контактов переключателей
- 5.5.1. Аппаратная защита от механического дребезга контактов
- 5.5.2. Программная защита от механического дребезга контактов
- 5.5.3. Пример программной защиты
- 5.6. Жидкокристаллические индикаторы
- 5.6.1. Краткие сведения о жидкокристаллических индикаторах
- 5.6.2. Сопряжение мк с символьным жк индикатором
- 5.6.3 Сопряжение мк с графическим жк дисплеем
- 5.7. Управление электрическим двигателем
- 5.7.1. Силовые полупроводниковые ключи
- 5.7.2. Оптоэлектронная потенциальная развязка
- 5.7.3. Инвертор напряжения
- 5.8. Кодовый замок
- 5.8.1. Схема подключения периферийных устройств
- 5.8.2. Программа управления
- 5.9. Интерфейс мк с аналоговыми датчиками
- 5.10. Интерфейс rs-232
- 5.11. Заключение по главе 5
- 5.12. Что еще почитать?
- 5.13. Вопросы и задания Основные
- Более сложные
- Исследовательские
- Глава 6 добро пожаловать в реальный мир!
- 6.1. Ужасные истории об ошибках проектирования
- 6.1.1. Случай квадратичного генератора
- 6.1.2. Случай таймера для лазерного излучения
- 6.2. Правила обращения с микросхемой 68нс12 и рекомендации по проектированию
- 6.2.1. Рекомендации по обращению со cmos
- 6.2.2. Рекомендации по проектированию на cmos
- 6.3. Исследование помех
- 6.3.1. Что такое помехи
- 6.3.2. Электромагнитная совместимость
- 6.3.3. Спецификации системы помех — не будем крепки задним умом!
- 6.3.4. Методы снижения помех
- 6.4. Защитное программирование
- 6.5. Методики испытаний на наличие помех
- 6.5.1. Обнаружение помех
- 6.5.2. Испытание на чувствительность к помехам
- 6.5.3. Испытания на электромагнитную совместимость
- 6.6. Управление энергопотреблением
- 6.6.1. Параметры потребляемой мощности для микроконтроллера 68hc12
- 6.6.2. Типы батарей
- 6.6.3. Емкость батарей
- 6.6.4. Стабилизация напряжения
- 6.6.5. Схемы супервизора для микропроцессора
- 6.6.6. Меры энергосбережения
- 6.7. Заключение по главе 6
- 6.8. Что еще прочитать?
- 6.9. Вопросы и задания Основные
- Более сложные
- Исследовательские
- Глава 7 примеры встроенных систем управления
- 7.1. Система привода робота, движущегося вдоль стенок лабиринта
- 7.1.1. Описание проекта
- 7.1.2. Подсистемы 68hc12, используемые в проекте
- 7.1.3. Компоненты системы
- 7.1.4. Структура программы и блок-схема алгоритма
- 7.1.5. Программный код
- 7.2. Лазерный проектор
- 7.2.1. Описание проекта
- 7.2.2. Подсистемы 68hc12 используемые в проекте
- 7.2.3. Описание некоторых компонентов системы
- 7.2.4. Аппаратные средства
- 7.2.5. Структура программы и блок-схема алгоритма
- 7.2.6. Программный код
- 7.2.7. Испытания устройства
- 7.2.8. Заключительные испытания системы управления
- 7.3. Цифровой вольтметр
- 7.3.1. Описание проекта
- 7.3.2. Системы 68hc12 используемые в проекте
- 7.3.3. Расчет интерфейса модуля atd
- 7.3.4. Структура программы и блок-схема алгоритма
- 7.3.5. Программа управления
- 7.3.6. Измерение неэлектрических величин
- 7.4. Стабилизация скорости вращения двигателя с использованием оптического тахометра
- 7.4.1. Описание проекта
- 7.4.2. Немного теории
- 7.4.3. Анализ
- 7.4.4. Структура программы и блок-схема алгоритма
- 7.4.5. Программный код
- 7.4.6. Испытания
- 7.5. Парящий робот
- 7.5.1. Описание проекта
- 7.5.2. Системы hcs12 используемые в проекте
- 7.5.3. Теоретическое обсуждение
- 7.5.4. Структура программы и блок-схема алгоритма
- 7.5.5. Программный код
- 7.5.6. Некоторые комментарии
- 7.6. Система защиты компьютера, основанная на нечеткой логике
- 7.6.1. Описание проекта
- 7.6.2. Использование системы hcs12
- 7.6.3. Основы теории
- 7.6.4. Структура программы и блок-схема алгоритма
- 7.6.5. Описание системы
- 7.6.6. Обсуждение проекта
- 7.6.7. Программный код
- 7.6.8. Некоторые комментарии
- 7.7. Электронная версия игры в «15»
- 7.7.1. Описание проекта
- 7.7.2. Системы hcs12 используемые в проекте
- 7.7.3. Основы теории
- 7.7.4. Схемное решение, структура программы и блок-схема алгоритма
- 7.7.5. О компонентах системы
- 7.7.6. Программный код
- 7.7.7. Некоторые комментарии
- 7.8. Программирование резидентного Flash пзу микроконтроллера b32 в составе платы отладки mc68hc912b32evb
- 7.9. Заключение по главе 7
- 7.10. Что еще прочитать?
- 7.11. Вопросы и задания Основные
- Более сложные
- Исследовательские
- Глава 8 операционные системы реального времени
- 8.1. Рассказ: официант — «живая» операционная система реального времени
- 8.2. Что является целью осрв?
- Вопросы для самопроверки
- 8.3. Обзор концепций
- 8.3.1. Требования к динамическому распределению ram
- Вопросы для самопроверки
- 8.3.2. Динамическое распределение памяти
- 8.3.3. Структуры данных
- 8.4. Основные понятия
- 8.4.1. Что такое задача?
- 8.4.2. Управление задачами
- 8.4.3. Компоненты многозадачных систем
- 8.5. Типы операционных систем реального времени
- 8.5.1. Системы с циклическим опросом
- 8.5.2. Циклический опрос с прерываниями
- 8.5.3. Карусельные системы
- 8.5.4. Смешанные системы
- 8.5.5. Системы с управлением по прерыванию
- 8.5.6. Кооперативная многозадачность
- 8.5.7. Многозадачные системы с преимущественным приоритетом
- 8.6. Проблемы осрв
- 8.6.1. Конкуренция Другой рассказ
- 8.6.2. Повторная входимость
- 8.6.3. Межзадачные связи
- 8.6.4. Безопасность, проверка и безотказная работа
- 8.6.5. Главный вопрос
- 8.7. Выполнение операционной системы реального времени
- 8.8. Пример применения: осрв циклического опроса
- 8.8.1. Краткий обзор проекта
- 8.8.2. Пример кода
- 8.8.3. Испытание контроллера усилителя
- 8.9. Другая прикладная программа: цикл опроса с прерываниями
- 8.10. Сложное прикладное устройство: имитатор осрв
- 8.10.1. Краткий обзор проекта
- 8.10.2. Типовой код
- 8.11.Заключение по главе 8
- 8.12. Что еще почитать?
- 8.13. Вопросы и задания Основные
- Более сложные
- Исследовательские
- Глава 9 распределенные сети с интерфейсом msCan
- 9.1. Компьютерные сети
- 9.2. Промышленные сети
- 9.3. Сети с протоколом can
- 9.3.1. Протокол can
- 9.3.2. Модуль контроллера последовательного обмена msCan12
- Подсистема прерывания контроллера msCan12.
- 9.3.3. Проблемы синхронизации
- 9.3.4. Конфигурирование модуля msCan12 для работы в сети
- 9.4. Различия между контроллерами msCan в составе 68hc12 и hcs12
- 9.5. Пример программирования контроллера msCan Схема включения аппаратных средств для двух отладочных плат Axiom
- 9.6. Контроллер последовательного обмена bdlc
- 9.7. Заключение по главе 9
- 9.8. Что еще почитать?
- 9.9. Вопросы и задания Основные
- Более сложные
- Исследовательские