Berezka7km.ru

Березка 7км
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Операционные системы (архив ИПМ специалисты, бакалавры 2001г — 2021г, Богомолов)

Операционные системы (архив ИПМ специалисты, бакалавры 2001г — 2021г, Богомолов)

Планирование — обеспечение поочередного доступа процессов к одному процессору.

Планировщик — отвечающая за это часть операционной системы.

Алгоритм планирования — используемый алгоритм для планирования.

Ситуации, когда необходимо планирование:

Когда создается процесс

Когда процесс завершает работу

Когда процесс блокируется на операции ввода/вывода, семафоре, и т.д.

При прерывании ввода/вывода.

Алгоритм планирования без переключений (неприоритетный) — не требует прерывание по аппаратному таймеру, процесс останавливается только когда блокируется или завершает работу.

Алгоритм планирования с переключениями (приоритетный) — требует прерывание по аппаратному таймеру, процесс работает только отведенный период времени, после этого он приостанавливается по таймеру, чтобы передать управление планировщику.

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

Основные три системы:

Системы пакетной обработки — могут использовать неприоритетный и приоритетный алгоритм (например: для расчетных программ).

Интерактивные системы — могут использовать только приоритетный алгоритм, нельзя допустить чтобы один процесс занял надолго процессор (например: сервер общего доступа или персональный компьютер).

Системы реального времени — могут использовать неприоритетный и приоритетный алгоритм (например: система управления автомобилем).

Задачи алгоритмов планирования:

Для всех систем
Справедливость — каждому процессу справедливую долю процессорного времени
Контроль над выполнением принятой политики
Баланс — поддержка занятости всех частей системы (например: чтобы были заняты процессор и устройства ввода/вывода)

Системы пакетной обработки
Пропускная способность — количество задач в час
Оборотное время — минимизация времени на ожидание обслуживания и обработку задач.
Использование процесса — чтобы процессор всегда был занят.

Интерактивные системы
Время отклика — быстрая реакция на запросы
Соразмерность — выполнение ожиданий пользователя (например: пользователь не готов к долгой загрузке системы)

Системы реального времени
Окончание работы к сроку — предотвращение потери данных
Предсказуемость — предотвращение деградации качества в мультимедийных системах (например: потерь качества звука должно быть меньше чем видео)

4.2 Планирование в системах пакетной обработки

4.2.1 «Первый пришел — первым обслужен» (FIFO — First In Fist Out)

Процессы ставятся в очередь по мере поступления.

Справедливость (как в очереди покупателей, кто последний пришел, тот оказался в конце очереди)

Процесс, ограниченный возможностями процессора может затормозить более быстрые процессы, ограниченные устройствами ввода/вывода.

4.2.2 «Кратчайшая задача — первая»

Нижняя очередь выстроена с учетом этого алгоритма

Уменьшение оборотного времени

Справедливость (как в очереди покупателей, кто без сдачи проходит в перед)

Длинный процесс занявший процессор, не пустит более новые краткие процессы, которые пришли позже.

4.2.3 Наименьшее оставшееся время выполнение

Аналог предыдущего, но если приходит новый процесс, его полное время выполнения сравнивается с оставшимся временем выполнения текущего процесса.

4.3 Планирование в интерактивных системах

4.3.1 Циклическое планирование

Самый простой алгоритм планирования и часто используемый.

Каждому процессу предоставляется квант времени процессора. Когда квант заканчивается процесс переводится планировщиком в конец очереди. При блокировке процессор выпадает из очереди.

Пример циклического планирования

Справедливость (как в очереди покупателей, каждому только по килограмму)

Если частые переключения (квант — 4мс, а время переключения равно 1мс), то происходит уменьшение производительности.

Если редкие переключения (квант — 100мс, а время переключения равно 1мс), то происходит увеличение времени ответа на запрос.

4.3.2 Приоритетное планирование

Каждому процессу присваивается приоритет, и управление передается процессу с самым высоким приоритетом.

Приоритет может быть динамический и статический.

Динамический приоритет может устанавливаться так:

П=1/Т, где Т- часть использованного в последний раз кванта

Если использовано 1/50 кванта, то приоритет 50.

Если использован весь квант, то приоритет 1.

Т.е. процессы, ограниченные вводом/вывода, будут иметь приоритет над процессами ограниченными процессором.

Часто процессы объединяют по приоритетам в группы, и используют приоритетное планирование среди групп, но внутри группы используют циклическое планирование.

Приоритетное планирование 4-х групп

4.3.3 Методы разделения процессов на группы

Группы с разным квантом времени

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

Процесс либо заканчивает работу, либо переходит в другую группу

Этот метод напоминает алгоритм — «Кратчайшая задача — первая».

Группы с разным назначением процессов

Процесс, отвечающий на запрос, переходит в группу с наивысшим приоритетом.

Такой механизм позволяет повысить приоритет работы с клиентом.

Гарантированное планирование

В системе с n-процессами, каждому процессу будет предоставлено 1/n времени процессора.

Лотерейное планирование

Процессам раздаются «лотерейные билеты» на доступ к ресурсам. Планировщик может выбрать любой билет, случайным образом. Чем больше билетов у процесса, тем больше у него шансов захватить ресурс.

Справедливое планирование

Процессорное время распределяется среди пользователей, а не процессов. Это справедливо если у одного пользователя несколько процессов, а у другого один.

4.4 Планирование в системах реального времени

Системы реального времени делятся на:

жесткие (жесткие сроки для каждой задачи) — управление движением

гибкие (нарушение временного графика не желательны, но допустимы) — управление видео и аудио

Внешние события, на которые система должна реагировать, делятся:

периодические — потоковое видео и аудио

непериодические (непредсказуемые) — сигнал о пожаре

Что бы систему реального времени можно было планировать, нужно чтобы выполнялось условие:

m — число периодических событий

i — номер события

P(i) — период поступления события

T(i) — время, которое уходит на обработку события

Т.е. перегруженная система реального времени является не планируемой.

4.4.1 Планирование однородных процессов

В качестве однородных процессов можно рассмотреть видео сервер с несколькими видео потоками (несколько пользователей смотрят фильм).

Т.к. все процессы важны, можно использовать циклическое планирование.

Но так как количество пользователей и размеры кадров могут меняться, для реальных систем он не подходит.

4.4.2 Общее планирование реального времени

Используется модель, когда каждый процесс борется за процессор со своим заданием и графиком его выполнения.

Планировщик должен знать:

частоту, с которой должен работать каждый процесс

объем работ, который ему предстоит выполнить

ближайший срок выполнения очередной порции задания

Рассмотрим пример из трех процессов.

Процесс А запускается каждые 30мс, обработка кадра 10мс

Процесс В частота 25 кадров, т.е. каждые 40мс, обработка кадра 15мс

Процесс С частота 20 кадров, т.е. каждые 50мс, обработка кадра 5мс

Три периодических процесса

Проверяем, можно ли планировать эти процессы.

Условие выполняется, планировать можно.

Будем планировать эти процессы статическим (приоритет заранее назначается каждому процессу) и динамическим методами.

4.4.3 Статический алгоритм планирования RMS (Rate Monotonic Scheduling)

Процессы должны удовлетворять условиям:

Процесс должен быть завершен за время его периода

Один процесс не должен зависеть от другого

Каждому процессу требуется одинаковое процессорное время на каждом интервале

У непериодических процессов нет жестких сроков

Прерывание процесса происходит мгновенно

Приоритет в этом алгоритме пропорционален частоте.

Процессу А он равен 33 (частота кадров)

Процессу В он равен 25

Процессу С он равен 20

Процессы выполняются по приоритету.

Читайте так же:
Kyocera m2030dn сброс счетчика тонера

Статический алгоритм планирования RMS (Rate Monotonic Scheduling)

4.4.4 Динамический алгоритм планирования EDF (Earliest Deadline First)

Наибольший приоритет выставляется процессу, у которого осталось наименьшее время выполнения.

При больших загрузках системы EDF имеет преимущества.

Рассмотрим пример, когда процессу А требуется для обработки кадра — 15мс.

Таймеры-счетчики. Прерывания

Сегодня мы узнаем, что такое таймеры-счётчики в микроконтроллерах и для чего они нужны, а также что такое прерывания и для чего они тоже нужны.

Таймеры-счётчики — это такие устройства или модули в микроконтроллере, которые, как видно из названия, постоянно что-то считают. Считают они либо до определённой величины, либо до такой величины, сколько они битности. Считают они постоянно с одной скоростью, со скоростью тактовой частоты микроконтроллера, поправленной на делители частоты, которые мы будем конфигурировать в определённых регистрах.

И вот эти таймеры-счётчики постоянно считают, если мы их инициализируем.

Таймеров в МК Atmega8 три.

image00

Два из них — это восьмибитные таймеры, то есть такие, которые могут максимально досчитать только до 255. Данной величины нам будет маловато. Даже если мы применим максимальный делитель частоты, то мы не то что секунду не отсчитаем, мы даже полсекунды не сможем посчитать. А у нас задача именно такая, чтобы досчитывать до 1 секунды, чтобы управлять наращиванием счёта светодиодного индикатора. Можно конечно применить ещё наращивание переменной до определенной величины, но хотелось бы полностью аппаратного счёта.

Но есть ещё один таймер — это полноправный 16-битный таймер. Он не только 16-битный, но есть в нём ещё определённые прелести, которых нет у других таймеров. С данными опциями мы познакомимся позже.

Вот этот 16-битный таймер мы и будем сегодня изучать и использовать. Также, познакомившись с данным таймером, вам ничего не будет стоить самостоятельно изучить работу двух других, так как они значительно проще. Но тем не менее 8-битные таймеры в дальнейшем мы также будем рассматривать, так как для достижения более сложных задач нам одного таймера будет недостаточно.

Теперь коротко о прерываниях.

Прерывания (Interrupts) — это такие механизмы, которые прерывают код в зависимости от определённых условий или определённой обстановки, которые будут диктовать некоторые устройства, модули и шины, находящиеся в микроконтроллере.

В нашем контроллере Atmega8 существует 19 видов прерываний. Вот они все находятся в таблице в технической документации на контроллер

image01

Какого типа могут быть условия? В нашем случае, например, досчитал таймер до определённой величины, либо например в какую-нибудь шину пришёл байт и другие условия.

На данный момент мы будем обрабатывать прерывание, которое находится в таблице, размещённой выше на 7 позиции — TIMER1 COMPA, вызываемое по адресу 0x006.

Теперь давайте рассмотрим наш 16-битный таймер или TIMER1.

Вот его структурная схема

image02

Мы видим там регистр TCNTn, в котором постоянно меняется число, то есть оно постоянно наращивается. Практически это и есть счётчик. То есть данный регистр и хранит число, до которого и досчитал таймер.

А в регистры OCRnA и OCRnB (буквы n — это номер таймера, в нашем случае будет 1) — это регистры, в которые мы заносим число, с которым будет сравниваться чило в регистре TCNTn.

Например, занесли мы какое-нибудь число в регистр OCRnA и как только данное число совпало со значением в регистре счёта, то возникнет прерывание и мы его сможем обработать. Таймеры с прерываниями очень похожи на обычную задержку в коде, только когда мы находимся в задержке, то мы в это время не можем выполнять никакой код (ну опять же образно "мы", на самом деле АЛУ). А когда считает таймер, то весь код нашей программы в это время спокойно выполняется. Так что мы выигрываем колоссально, не давая простаивать огромным ресурсам контроллера по секунде или даже по полсекунды. В это время мы можем обрабатывать нажатия кнопок, которые мы также можем обрабатывать в таймере и многое другое.

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

Также у таймера существует несколько режимов, с которыми мы также познакомимся немного позденее.

Он состоит из двух половинок, так как у нас конотроллер 8-битный и в нем не может быть 16-битных регистров. Поэтому в одной половинке регистра (а физически в одном регистре) хранится старшая часть регистра, а в другом — младшая. Можно также назвать это регистровой парой, состоящей из двух отдельных регистров TCCR1A и TCCR1B. Цифра 1 означает то, что регистр принадлежит именно таймеру 1.

Даный регист TCCR отвечает за установку делителя, чтобы таймер не так быстро считал, также он отвечает (вернее его определённые биты) за установку определённого режима.

За установку режима отвечают биты WGM

image03

Мы видим здесь очень много разновидностей режимов.

Normal — это обычный режим, таймер считает до конца.

PWM — это ШИМ только разные разновидности, то есть таймер может играть роль широтно-импульсного модулятора. С данной технологией мы будем знакомиться в более поздних занятиях.

CTC — это сброс по совпадению, как раз то что нам будет нужно. Здесь то и сравнивются регистры TCNT и OCR. Таких режима два, нам нужен первый, второй работает с другим регистром.

Все разновидности режимов мы в данном занятии изучать не будем. Когда нам эти режимы потребуются, тогда и разберёмся.

Ну давайте не будем томить себя документацией и наконец-то попробуем что-то в какие-нибудь регистры занести.

Код, как всегда, был создан из прошлого проекта. Для протеуса также код был скопирован и переименован с прошлого занятия, также в свойствах контроллера был указан путь к новой прошивке. Проекты мы назовем Test07.

Попробуем как всегда скомпилировать код и запустить его в протеусе. Если всё нормально работает, то начинаем добавлять новый код.

Добавим ещё одну функцию, благо добавлять функции мы на прошлом занятии научились. Код функции разместим после функции segchar и до функции main. После из-за того, что мы будем внутри нашей новой функции вызывать функцию segchar.

Мало того, мы создадим не одну функцию, а целых две. В одну функцию мы разместим весь код инициализации нашего таймеру, а другая функция будет являться обработчиком прерывания от таймера, а такие функции они специфичны и вызывать их не требуется. Когда возникнет необходимость, они вызовутся сами в зависимости от определённых условий, которые были оговорены выше.

Поэтому первую функцию мы назвовём timer_ini

void timer_ini ( void )

Также давайте наши функции, а также какие-то законченные блоки с объявлением глобальных переменных, с прототипами функций будем отделять друг от друга вот такими чёрточками, которые за счет наличия двух слешей впереди компилятор обрабатывать не будет и примет их за комментарии. За счёт этих отчерчиваний мы будем видеть, где заканчивается одна функция и начинается другая.

Данная функция, как мы видим не имеет ни каких аргументов — ни входных, не возвращаемых. Давайте сразу данную функцию вызовем в функции main()

Читайте так же:
Шкафы для выносных счетчиков

unsigned char butcount=0, butstate=0;

timer_ini ();

Теперь мы данную функцию начнём потихонечку наполнять кодом.

Начнем с регистра управления таймером, например с TCCR1B. Используя нашу любимую операцию "ИЛИ", мы в определённый бит регистра занесём единичку

void timer_ini ( void )

TCCR1B |= (1<< WGM12 ); // устанавливаем режим СТС (сброс по совпадению)

Из комментария мы видим, что мы работает с битами режима, и установим мы из них только бит WGM12, остальные оставим нули. Исходя из этого мы сконфигурировали вот такой режим:

image04

Также у таймера существует ещё вот такой регистр — TIMSK. Данный регистр отвечает за маски прерываний — Interrupt Mask. Доступен данный регистр для всех таймеров, не только для первого, он общий. В данном регистре мы установим бит OCIE1A, который включит нужный нам тип прерывания TIMER1 COMPA

image05

TCCR1B |= (1<< WGM12 ); // устанавливаем режим СТС (сброс по совпадению)

TIMSK |= (1<< OCIE1A ); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)

Теперь давайте поиграемся с самими регистрами сравнения OCR1A(H и L). Для этого придётся немного посчитать. Регистр OCR1AH хранит старшую часть числа для сравнения, а регистр OCR1AL — младшую.

Но прежде чем посчитать, давайте пока напишем код с любыми значениями данного регистра и потом поправим, так как дальше мы будем инициализировать делитель и он тоже будет учавствовать в расчёте требуемого времени счёта. Без делителя таймер будет слишком быстро считать.

TIMSK |= (1<< OCIE1A ); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)

OCR1AH = 0b10000000; //записываем в регистр число для сравнения

OCR1AL = 0b00000000;

TCCR1B |= ( ); //установим делитель.

Пока никакой делитель не устанавливаем, так как мы его ещё не посчитали. Давайте мы этим и займёмся.

Пока у нас в регистре OCR1A находится число 0b1000000000000000, что соответствует десятичному числу 32768.

Микроконтроллер у нас работает, как мы договорились, на частоте 8000000 Гц.

Разделим 8000000 на 32768, получим приблизительно 244,14. Вот с такой частотой в герцах и будет работать наш таймер, если мы не применим делитель. То есть цифры наши будут меняться 244 раза в секунду, поэтому мы их даже не увидим. Поэтому нужно будет применить делитель частоты таймера. Выберем делитель на 256. Он нам как раз подойдёт, а ровно до 1 Гц мы скорректируем затем числом сравнения.

Вот какие существуют делители для 1 таймера

image07

Я выделил в таблице требуемый нам делитель. Мы видим, что нам требуется установить только бит CS12.

Так как делитель частоты у нас 256, то на этот делитель мы поделим 8000000, получится 31250, вот такое вот мы и должны занести число в TCNT. До такого числа и будет считать наш таймер, чтобы досчитать до 1 секунды. Число 31250 — это в двоичном представлении 0b0111101000010010. Занесём данное число в регистровую пару, и также применим делитель

OCR1AH = 0b01111010; //записываем в регистр число для сравнения

OCR1AL = 0b00010010;

TCCR1B |= (1<< CS12 ); //установим делитель.

С данной функцией всё.

Теперь следующая функция — обработчик прерывания от таймера по совпадению. Пишется она вот так

ISR ( TIMER1_COMPA_vect )

И тело этой функции будет выполняться само по факту наступления совпадения чисел.

Нам нужна будет переменная. Объявим её глобально, в начале файла

unsigned char i ;

Соответственно, из кода в функции main() мы такую же переменную уберём

unsigned char i ;

Также закомментируем весь код в бесконечном цикле. Его роль теперь у нас будет выполнять таймер, и, я думаю, он с этим справится не хуже, а даже лучше, "никому" при этом не мешая.

while (1)

// for(i=0;i<10;i++)

// while (butstate==0)

// if (!(PINB&0b00000001))

// if(butcount < 5)

// butcount++;

// else

// i=0;

// butstate=1;

// else

// if(butcount > 0)

// butcount—;

// else

// butstate=1;

// segchar(i);

// _delay_ms(500);

// butstate=0;

Теперь, собственно, тело функции-обработчика. Здесь мы будем вызывать функцию segchar. Затем будем наращивать на 1 переменную i. И чтобы она не ушла за пределы однозначного числа, будем её обнулять при данном условии

if ( i >9) i =0;

segchar ( i );

i ++;

Теперь немного исправим код вначале функции main(). Порт D, отвечающий за состояние сегментов, забьём единичками, чтобы при включении у нас не светился индикатор, так как он с общим анодом. Затем мы здесь занесём число 0 в глобавльную переменную i, просто для порядка. Вообще, как правило, при старте в неициализированных переменных и так всегда нули. Но мы всё же проинициализируем её. И, самое главное, чтобы прерывание от таймера работало, её недостаточно включить в инициализации таймера. Также вообще для работы всех прерываний необходимо разрешить глобальные прерывания. Для этого существует специальная функция sei() — Set Interrupt.

Теперь код будет вот таким

PORTD = 0b11111111;

i =0;

sei ();

Также ещё мы обязаны подключить файл библиотеки прерываний вначале файла

#include <avr/interrupt.h>

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

//unsigned char butcount=0, butstate=0;

Соберём наш код и проверим его работоспособность сначала в протеусе. Если всё нормально работает, то проверим также в живой схеме

image08

Всё у нас работает. Отлично!

Вот такой вот получился секундомер. Но так как у нас даже нет кварцевого резонатора, то данный секундомер нельзя назвать точным.

Тем не менее сегодня мы с вами много чему научились. Мы узнали о прерываниях, также научились их обрабатывать, Научились работать с таймерами, конфигурировать несколько новых регистров микроконтроллера, до этого мы работали только с регистрами портов. Также за счёт всего этого мы значительно разгрузили арифметическо-логическое устройство нашего микроконтроллера.

Купить программатор можно здесь (продавец надёжный) USBASP USBISP 2.0

13 — Программируемые таймеры и счетчики событий

Довольно часто требуется устройство формирования временных интервалов для процессора и внешних устройств, подсчета внешних событий и ввода показаний в процессор, а также генерирования внешней синхронизации, которую может программировать процессор. Такое устройство называется программируемым интервальным таймером/счетчиком событий. Некоторыми областями применение такого устройства являются:

прерывание операционной системы с разделением времени через равномерные интервалы, чтобы она осуществляла переключение программ;

вывод точных временных сигналов с программируемыми периодами в устройство ввода-вывода (например, в аналого-цифровой преобразователь);

программируемая генерация скорости передачи в бодах;

измерение временной задержки между внешними событиями;

подсчет числа появлений событий во внешнем эксперименте и ввод показания в компьютер;

Рис. 9.25. Типичный интервальный таймер/счетчик событий

Рекомендуемые файлы

прерывание процессора после появления запрограммированного числа внешних событий.

Типичная организация интервального таймера/счетчика событий показана на рис. 9.25. Слева находятся четыре доступных компьютеру регистра: два верхних являются выходними портами, а два нижних — входными. Сам счетчик прямо процессору не доступен, но может инициализироваться из регистра начального счета и считывается посредством передачи его содержимого в выходной регистр счетчика. Счетчик запускается с начального значения и отсчитывает до 0. Вход CLK определяет скорость счета, сигнал GATE разрешает и запрещает вход CLK и, возможно, выполняет другие функции, а выход OUT -становится активным при достижении счетчиком 0 или, возможно, при подаче сиг-нала АТЕ. Выход OUT подключается к линии запроса прерывания в системной шине, поэтому прерывание возникает при достижении счетчиком 0; его же можно подключить к устройству ввода-вывода для инициирования необходимых действий.

Читайте так же:
Питерфлоу рс класс счетчика

Устройство вводит значение в регистр начального счета, передает его в счетчик и выполняет счет "назад" (т. е. вычитание) импульсами со входа CLK. Текущее содержимое счетчика в любой момент можно ввести в процессор, не нарушая работы счетчика, посредством передачи его в выходной регистр счетчика с последующим считыванием из этого регистра. При буферировании содержимого счетчика не требуется вводить его в процессор немедленно. Индикация нуля в счетчике обычно фиксируется на выходе OUT и в одном бите регистра состояния. Поэтому для обнаружения нуля допускается применять Программный ввод-вывод и ввод-вывод по прерываниям.

Регистр управления определяет режим работы и выполняет другие функции. Режим точно определяет, что происходит при достижении счетчиком 0 и (или) при подаче сигнала на вход GATE . Возможными действиями являются:

вход GATE применяется для разрешения и запрещения входа CLK;

вход GATE вызывает реинициализацию счетчика;

[ i . вход GATE прекращает счет и формирует высокий уровень на выходе OUT ;

— при достижении 0 счетчик выдает сигнал OUT и останавливается;

при достижении 0 счетчик выдает сигнал OUT и автоматически реинициализируется из регистра начального счета.

Режимы могут также определяться комбинациями перечисленных возможностей. Рассмотрим, например, применение интервального таймера в операционной системе разделением времени. В этом случае на вход CLK подаются сигналы синхронизации, ) выход OUT подключается к линии запроса прерывания, возможно, немаскируемой прерывания. Вход GATE здесь не требуется. При включении системы в регистр начального счета загружается значение

начальный счет == частота синхронизации Х Т,

где Т — продолжительность каждого временного кванта в секундах. Задается такой режим, что при достижении счетчиком 0 содержимое регистра начального счета вновь загружается в счетчик, а выход OUT становится активным. Поскольку сигнал OUT используется как запрос прерывания, процедура прерывания для переключения программ будет выполняться с интервалом Т секунд.

9.3.1 Программируемый интервальный таймер

На рис. 9.26 представлена схема интервального таймера/счетчика событий 8254 фирмы Intel . В нем имеются три одинаковые счетные схемы со своими входами CLK и GATE и выходом OUT . Каждая схема имеет регистр управления и состояния, регистр счетчика ( CR ) для приема начального счета, счетного элемента (СЕ) , который выполняет счет, но непосредственно процессору недоступен, и выходного регистра-защелки ( OL ) для фиксации содержимого СЕ, так что его может считать процессор. Полагается, что CR, СЕ и OL представляют собой пары 8-битных регистров. (Реальные схемы несколько отличаются от приведенных, но для программиста рисунок абсолютно точен.)

Обращения к регистрам производятся в соответствии с табл. 9.3.

Обращения к регистрам таймера/счетчика 8254

Все остальные комбинации приводят к тому, что линии данных переводятся в высокоимпедансное состояние. Когда А1 = АО = 1, выполнение записи в регистр управления или выдачи приказа зависит от старшего бита выводимого байта. В последних трех комбинациях считывание OL или регистра состояния определяет предыдущий приказ.

Имеются два вида приказов. Приказ фиксации счетчика заставляет соответствующий OL зафиксировать содержимое СЕ счетчика, определяемого двумя старшими битами приказа. Приказ обратного считывания фиксирует комбинацию СЕ или "готовит" комбинацию регистров состояния для считывания. Подготовка регистра состояния означает

Рис. 9.26. Схема таймера/счетчика 8254

его считывание, когда в следующей операции считывания осуществляется ввод из счетчика. Состояния 00, 01 и 10 двух старших бит показывают приказ фиксации счетчика, а состояние 11 — приказ обратного считывания. В приказе фиксации биты 5 и 4 должны быть нулевыми, а остальные биты не используются. Приказ обратного считывания имеет следующий формат:

Если бит COUNT = 0, фиксируются СЕ всех счетчиков, биты CNT которых содержат 1. если, например, CNTO = CNT 2 = 1 и CNT 1 = 0, то СЕ в счетчиках 0 и 2 фиксируются, "»в счетчике 1 не фиксируется. Аналогично STAT = 0 вызывает подготовку регистров

Рис 9 27 Регистры управления и состояния счетчиков

состояний счетчиков для ввода. Действия по фиксации и подготовке допускается указывать в одном приказе.

Форматы регистров управления и состояния показаны на рис. 9.27. Если два старших бита равны 1, они задают приказ обратного считывания; в противном случае они опреде­ляют счетчик. Если указан счетчик и биты 5-4 содержат нули, то имеет место приказ фиксации, который направляется в регистр управления выбираемого старшими битами счетчика. Когда же комбинация в битах 5-4 отличается от 00, она указывает тип ввода из OL или вывода в CR . Комбинация 01 идентифицирует операции считывания/записи из (в) OL ^/ CR , комбинация 10 — из (в) OLix / CRv » и комбинация 11 — выполнение операций парами (первый байт из (в) OLi / CRi и второй из (в) OLn / CR ^ i ) Запись одного байта в CR вызывает сброс другого байта Биты 1, 2 и 3 определяют режим, а бит 0 определяет формат счета.

Таймер/счетчик имеет следующие режимы работы (через N обозначен начальный счет)

Режим 0 (прерывания по концу счета) . Сигнал GATE = 1 разрешает счет, a GATE = О запрещает счет, причем GATE не влияет на выход OUT . Содержимое CR передается в СЕ по первому импульсу CLK после того, как процессор осуществил запись в CR, независимо от сигнала на входе GATE Импульс, который загружает СЕ, не учитывается при сче­те На выходе OUT формируется низкий уровень при записи в регистр управления, который сохраняется до достижения счетчиком 0. Режим 0 предназначен в основном для счета событий.

Режим 1 (аппаратно перезапускаемый одновибратор). После загрузки значения N в CR переход 0 -* 1 на входе GATE вызывает загрузку СЕ, переход 1 -»0 на выходе OUT и запускает счет. Когда счетчик достигает 0, на выходе OUT формируется высокий уровень; таким образом, результатом является отрицательный импульс на выходе OUT с продолжительностью N периодов синхронизации

Режим 2 (гчрч’ v-и^й nil ерьиышй таймер) После загрузки значения N в CR следующий импульс синхронизации осуществляет передачу из CR в СЕ. На выходе OUT возникает переход 1 -^ 0. когда счетчик достигает 0 низкий уровень сохраняется в течение одною импульса CJ — K Згпсм на выходе OUT . появляется высокий уровень, производится повторная загрузка СЕ из CR, в результате на выходе 01Л появляется отрицательный импульс через N тактов синхронизации Сигнал GAU 1 разрешает счет, а GATi U запрещаег Переход 0 " 1 на входе GAJ 1 вызывает реинициализацию счета следующим импульсом синхронизации. Данный pt-л.л vi применяется для реализации периодического интервального таймера

Режим 3 (генератор прямоугольного сигнала). Аналогичен режиму 2, но на выходе От формируется низкий уровень при достижении половины начального счета; этот уровень сохраняется до достижения счетчиком 0. Как и прежде, сигнал GATE разрешает и запрещает счет, а его переход 0 -* 1 реинициализирует счет Этот режим применяется в генераторах, определяющих скорость передачи в бодах.

Режим 4 (программно-запускаемый строб) . Аналогичен режиму 0, но на выходе OUT в процессе счета действую высокий уровень, а при достижении счетчиком 0 появляется отрицательный импульс с продолжительностью в один такт синхронизации

Читайте так же:
Счетчик купюр магнер 150 инструкция

Режим 5 (аппаратно-запускаемый строб с перезапуском) После загрузки CR переход 0 ^ 1 на входе GATF вызывает передачу из CR в СЕ следующим импульсом CLK . В процессе счета на выходе OUT действует высокий уровень, а при достижении счетчиком 0 формируется отрицательный импульс с продолжительностью в один период CLK Сигнал GATE может в любой момент времени реинициализировать счет.

Начальное значение счета 0 во всех режимах интерпретируется как 2 16 или Ю 4 в зависимости от формата счета. Мы привели общие принципы работы микросхемы 8254, а подробное описание содержится в фирменных материалах.

Цикл со счетчиком

Цикл — разновидность управляющей конструкции в высокоуровневых языках программирования, предназначенная для организации многократного исполнения набора инструкций. Также циклом может называться любая многократно исполняемая последовательность инструкций, организованная любым способом (например, с помощью условного перехода).

Содержание

Определения

Последовательность инструкций, предназначенная для многократного исполнения, называется телом цикла. Однократное выполнение тела цикла называется итерацией. Выражение определяющее, будет в очередной раз выполняться итерация, или цикл завершится, называется условием выхода или условием окончания цикла (либо условием продолжения в зависимости от того, как интерпретируется его истинность — как признак необходимости завершения или продолжения цикла). Переменная, хранящая текущий номер итерации, называется счётчиком итераций цикла или просто счётчиком цикла. Цикл не обязательно содержит счётчик, счётчик не обязан быть один — условие выхода из цикла может зависеть от нескольких изменяемых в цикле переменных, а может определяться внешними условиями (например, наступлением определённого времени), в последнем случае счётчик может вообще не понадобиться.

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

Виды циклов

Безусловные циклы

Иногда в программах используются циклы, выход из которых не предусмотрен логикой программы. Такие циклы называются безусловными, или бесконечными. Специальных синтаксических средств для создания бесконечных циклов, ввиду их нетипичности, языки программирования не предусматривают, поэтому такие циклы создаются с помощью конструкций, предназначенных для создания обычных (или условных) циклов. Для обеспечения бесконечного повторения проверка условия в таком цикле либо отсутствует (если позволяет синтаксис, как, например, в цикле LOOP…END LOOP языка Ада), либо заменяется константным значением (while true do … в Паскале).

Цикл с предусловием

Цикл с предусловием — цикл, который выполняется пока истинно некоторое условие, указанное перед его началом. Это условие проверяется до выполнения тела цикла, поэтому тело может быть не выполнено ни разу (если условие с самого начала ложно). В большинстве процедурных языков программирования реализуется оператором while, отсюда его второе название — while-цикл.

Цикл с постусловием

Цикл с постусловием — цикл, в котором условие проверяется после выполнения тела цикла. Отсюда следует, что тело всегда выполняется хотя бы один раз. В языке Паскаль этот цикл реализует оператор repeat..until; в Си — do…while.

В трактовке условия цикла с постусловием в разных языках есть различия. В Паскале и языках, произошедших от него, условие такого цикла трактуется как условие выхода (цикл завершается, когда условие истинно, в русской терминологии такие циклы называют ещё «цикл до»), а в Си и его потомках — как условие продолжения (цикл завершается, когда условие ложно, такие циклы иногда называют «цикл пока»)…..

Цикл с выходом из середины

Цикл с выходом из середины — наиболее общая форма условного цикла. Синтаксически такой цикл оформляется с помощью трёх конструкций: начала цикла, конца цикла и команды выхода из цикла. Конструкция начала маркирует точку программы, в которой начинается тело цикла, конструкция конца — точку, где тело заканчивается. Внутри тела должна присутствовать команда выхода из цикла, при выполнении которой цикл заканчивается и управление передаётся на оператор, следующий за конструкцией конца цикла. Естественно, чтобы цикл выполнился более одного раза, команда выхода должна вызываться не безусловно, а только при выполнении условия выхода из цикла.

Принципиальным отличием такого вида цикла от рассмотренных выше является то, что часть тела цикла, расположенная после начала цикла и до команды выхода, выполняется всегда (даже если условие выхода из цикла истинно при первой итерации), а часть тела цикла, находящаяся после команды выхода, не выполняется при последней итерации.

Легко видеть, что с помощью цикла с выходом из середины можно легко смоделировать и цикл с предусловием (разместив команду выхода в начале тела цикла), и цикл с постусловием (разместив команду выхода в конце тела цикла).

Часть языков программирования содержат специальные конструкции для организации цикла с выходом из середины. Так, в языке Ада для этого используется конструкция LOOP…END LOOP и команда выхода EXIT или EXIT WHEN:

Здесь внутри цикла может быть любое количество команд выхода обоих типов. Сами команды выхода принципиально не различаются, обычно EXIT WHEN применяют, когда проверяется только условие выхода, а просто EXIT — когда выход из цикла производится в одном из вариантов сложного условного оператора.

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

Цикл cо счётчиком

Цикл со счётчиком — цикл, в котором некоторая переменная изменяет своё значение от заданного начального значения до конечного значения с некоторым шагом, и для каждого значения этой переменной тело цикла выполняется один раз. В большинстве процедурных языков программирования реализуется оператором for, в котором указывается счётчик (так называемая «переменная цикла»), требуемое количество проходов (или граничное значение счётчика) и, возможно, шаг, с которым изменяется счётчик. Например, в языке Оберон-2 такой цикл имеет вид:

(здесь v — счётчик, b — начальное значение счётчика, e — граничное значение счётчика, s — шаг).

Неоднозначен вопрос о значении переменной по завершении цикла, в котором эта переменная использовалась как счётчик. Например, если в программе на языке Паскаль встретится конструкция вида:

возникает вопрос: какое значение будет в итоге присвоено переменной k: 9, 10, 100, может быть, какое-то другое? А если цикл завершится досрочно? Ответы зависят от того, увеличивается ли значение счётчика после последней итерации и не изменяет ли транслятор это значение дополнительно. Ещё один вопрос: что будет, если внутри цикла счётчику будет явно присвоено новое значение? Различные языки программирования решают данные вопросы по-разному. В некоторых поведение счётчика чётко регламентировано. В других, например, в том же Паскале, стандарт языка не определяет ни конечного значения счётчика, ни последствий его явного изменения в цикле, но не рекомендует изменять счётчик явно и использовать его по завершении цикла без повторной инициализации. Программа на Паскале, игнорирующая эту рекомендацию, может давать разные результаты при выполнении на разных системах и использовании разных трансляторов.

Радикально решён вопрос в языке Ада: счётчик считается описанным в заголовке цикла, и вне его просто не существует. Даже если имя счётчика в программе уже используется, внутри цикла в качестве счётчика используется отдельная переменная. Счётчику запрещено явно присваивать какие бы то ни было значения, он может меняться только внутренним механизмом оператора цикла. В результате конструкция

Читайте так же:
Счетчик се 303 s31 503 jayvz

внешне аналогичная вышеприведённому циклу на Паскале, трактуется однозначно: переменной k будет присвоено значение 100, поскольку переменная i, используемая вне данного цикла, не имеет никакого отношения к счётчику i, который создаётся и изменяется внутри цикла. Считается, что подобное обособление счётчика наиболее удобно и безопасно: не требуется отдельное описание для него и минимальна вероятность случайных ошибок, связанных со случайным разрушением внешних по отношению к циклу переменных. Если программисту требуется включить в готовый код цикл со счётчиком, то он может не проверять, существует ли переменная с именем, которое он выбрал в качестве счётчика, не добавлять описание нового счётчика в заголовок соответствующей процедуры, не пытаться использовать один из имеющихся, но в данный момент «свободных» счётчиков. Он просто пишет цикл с переменной-счётчиком, имя которой ему удобно, и может быть уверен, что никакой коллизии имён не произойдёт.

Цикл со счётчиком всегда можно записать как условный цикл, перед началом которого счётчику присваивается начальное значение, а условием выхода является достижение счётчиком конечного значения; к телу цикла при этом добавляется оператор изменения счётчика на заданный шаг. Однако специальные операторы цикла со счётчиком могут эффективнее транслироваться, так как формализованный вид такого цикла позволяет использовать специальные процессорные команды организации циклов.

В некоторых языках, например, Си и других, произошедших от него, цикл for, несмотря на синтаксическую форму цикла со счётчиком, в действительности является циклом с предусловием. То есть в Си конструкция цикла:

фактически представляет собой другую форму записи конструкции:

То есть в конструкции for сначала пишется произвольное предложение инициализации цикла, затем — условие продолжения и, наконец, выполняемая после каждого тела цикла некоторая операция (это не обязательно должно быть изменение счётчика; это может быть правка указателя или какая-нибудь совершенно посторонняя операция). Для языков такого вида вышеописанная проблема решается очень просто: переменная-счётчик ведёт себя совершенно предсказуемо и по завершении цикла сохраняет своё последнее значение.

Вложенные циклы

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

Полное число исполнений тела внутреннего цикла не превышает произведения числа итераций внутреннего и всех внешних циклов. Например взяв три вложенных друг в друга цикла, каждый по 10 итераций, получим 10 исполнений тела для внешнего цикла, 100 для цикла второго уровня и 1000 в самом внутреннем цикле.

Одна из проблем, связанных с вложенными циклами — организация досрочного выхода из них. Во многих языках программирования есть оператор досрочного завершения цикла (break в Си, exit в Турбо Паскале, last в Perl и т. п.), но он, как правило, обеспечивает выход только из цикла того уровня, откуда вызван. Вызов его из вложенного цикла приведёт к завершению только этого внутреннего цикла, объемлющий же цикл продолжит выполняться. Проблема может показаться надуманной, но она действительно иногда возникает при программировании сложной обработки данных, когда алгоритм требует немедленного прерывания в определённых условиях, наличие которых можно проверить только в глубоко вложенном цикле.

Решений проблемы выхода из вложенных циклов несколько.

  • Простейший — использовать оператор безусловного перехода goto для выхода в точку программы, непосредственно следующую за вложенным циклом. Этот вариант критикуется сторонниками структурного программирования, как и все конструкции, требующие использования goto. Некоторые языки программирования, например Modula-2, просто не имеют оператора безусловного перехода, и в них подобная конструкция невозможна.
  • Альтернатива — использовать штатные средства завершения циклов, в случае необходимости устанавливая специальные флаги, требующие немедленного завершения обработки. Недостаток — усложнение кода, снижение производительности без каких-либо преимуществ, кроме теоретической «правильности» из-за отказа от goto.
  • Размещение вложенного цикла в процедуре. Идея состоит в том, чтобы всё действие, которое может потребоваться прервать досрочно, оформить в виде отдельной процедуры, и для досрочного завершения использовать оператор выхода из процедуры (если такой есть в языке программирования). В Си, например, можно построить функцию с вложенным циклом, а выход из неё организовать с помощью оператора return. Недостаток — выделение фрагмента кода в процедуру не всегда логически обосновано, и не все языки имеют штатные средства досрочного завершения процедур.
  • Воспользоваться механизмом генерации и обработки исключений (исключительных ситуаций), который имеется сейчас в большинстве ЯВУ. В этом случае в нештатной ситуации код во вложенном цикле возбуждает исключение, а блок обработки исключений, в который помещён весь вложенный цикл, перехватывает и обрабатывает его. Недостаток — реализация механизма обработки исключений в большинстве случаев такова, что скорость работы программы уменьшается. Правда, в современных условиях это не особенно важно: практически потеря производительности столь мала, что имеет значение лишь для очень немногих приложений.
  • Наконец, существуют специальные языковые средства для выхода из вложенных циклов. Так, в языке Ада программист может пометить цикл (верхний уровень вложенного цикла) меткой, и в команде досрочного завершения цикла указать эту метку. Выход произойдёт не из текущего цикла, а из всех вложенных циклов до помеченного, включительно.

Совместный цикл

Ещё одним вариантом цикла является цикл, задающий выполнение некоторой операции для объектов из заданного множества, без явного указания порядка перечисления этих объектов. Такие циклы называются совместными (а также циклами по коллекции, циклами просмотра) и представляют собой формальную запись инструкции вида: «Выполнить операцию X для всех элементов, входящих в множество M». Совместный цикл, теоретически, никак не определяет, в каком порядке операция будет применяться к элементам множества, хотя конкретные языки программирования, разумеется, могут задавать конкретный порядок перебора элементов. Произвольность даёт возможность оптимизации исполнения цикла за счёт организации доступа не в заданном программистом, а в наиболее выгодном порядке. При наличии возможности параллельного выполнения нескольких операций возможно даже распараллеливание выполнения совместного цикла, когда одна и та же операция одновременно выполняется на разных вычислительных модулях для разных объектов, при том что логически программа остаётся последовательной.

Совместные циклы имеются в некоторых языках программирования (C#, JavaScript, Python, LISP, коллекции объектов. В определении такого цикла требуется указать только коллекцию объектов и переменную, которой в теле цикла будет присвоено значение обрабатываемого в данный момент объекта (или ссылка на него). Синтаксис в различных языках программирования синтаксис оператора различен:

голоса
Рейтинг статьи
Ссылка на основную публикацию
Adblock
detector