
Рис. 7.17.Схема устройства, реализующая разное время реакции на входные воздействия
Можно было бы просто включить в основной монитор два различных счетчика и, анализируя их значения, вызывать соответствующие подпрограммы, но при этом возможна ситуация, когда общее время выполнения подпрограмм превысит значение временного слота монитора. Намного лучше заранее разбить время выполнения программы на временные слоты и выделить для каждой подпрограммы различные слоты. Это позволит отодвинуть выполнение некритичных по времени подпрограмм на более позднее время. Так реализуются параллельные программные потоки.
На временной диаграмме рис. 7.18 общее время выполнения программы (максимальное допустимое время реакции системы) разбито на шесть временных слотов. При этом первый, третий и пятый временные слоты выделены для второго монитора, что обеспечивает время реакции устройства t2, реализуемое этим монитором, не более 3,3 мс. Это будет один программный поток.
Для первой подпрограммы-монитора с временем реакции на входное воздействие t1 выделен четвертый временной слот. Если времени одного слота для выполнения монитора 1 недостаточно, то есть еще два свободных временных слота. Подпрограмма-монитор 1 может быть разбита на три части, каждая из которых будет вызываться в своем временном слоте. При этом максимальное время реакции на входное событие у монитора 1 составит t1 = 10 мс.

Рис. 7.18.Пример временной диаграммы работы микроконтроллера с двумя подпрограммами-мониторами
Таким образом, в одном процессоре реализовано два программных потока с различным временем реакции на изменение сигналов на выводах микроконтроллера. В принципе, вместо ожидания срабатывания таймера можно организовать еще один программный поток и разместить в этом потоке подпрограммы, время выполнения которых не является критическим для разрабатываемого устройства.
Теперь рассмотрим, как можно реализовать приведенные выше принципы организации программы на языке программирования С-51. Исходный текст программы приведен в листинге 7.30. Для нумерации слотов, на которые разбивается время, используется глобальная переменная NomSlot. Эта переменная используется как счетчик временных слотов. Именно по ее значению вызывается одна из подпрограмм-мониторов. Подпрограмма инициализации микроконтроллера такая же, как в примере, приведенном в листинге 7.27, и поэтому сейчас рассматриваться не будет.

Использование прерываний для ввода информации о кратковременных сигналах и событиях, наступающих в произвольный момент времени
Использование временных слотов позволяет реализовывать устройства с различными временами реакции. Однако размер временного слота не позволяет обрабатывать быстро текущие процессы. Часто сигнал на входе микроконтроллера длится в течение нескольких микросекунд. Для того чтобы не пропустить такой сигнал, время реакции системы должно быть в пределах нескольких команд микроконтроллера. Если сделать такой маленький временной слот, то микроконтроллер будет постоянно переключаться с задачи на задачу, и ему некогда будет заниматься реализацией основного алгоритма работы. В то же самое время временной интервал между приходом очередного сигнала на вход микроконтроллера может быть достаточно велик, т. е. время реакции системы даже для короткого сигнала может достигать единиц и даже десятков миллисекунд!
Для решения возникшей проблемы в микроконтроллерах предусмотрен механизм прерываний основной программы. Разработчики микроконтроллера предлагают аппаратный вызов подпрограмм при возникновении какого-либо события. Это может быть изменение потенциала на особых выводах микроконтроллера (входах запроса прерывания), переполнение таймеров, завершения передачи или приема байта через последовательный порт. В некоторых типах микроконтроллеров могут быть дополнительные источники прерываний.
В предыдущих главах мы реализовывали ввод информации в начале рабочего цикла программы-монитора. Тем самым мы обеспечивали ввод информации строго через равные интервалы времени. При этом предполагалось, что сигналы на выводах микроконтроллера меняются медленнее интервала опроса. Использование прерываний позволяет обрабатывать короткие сигналы или пакеты сигналов, приходящие в случайные моменты времени. Основное ограничение при использовании прерываний - это то, что мы должны успеть запомнить полученную информацию в глобальной переменной до поступления очередного запроса на прерывание.
Наиболее ярким примером источника событий, наступающих в произвольный момент времени, является последовательный порт. Обычно через него принимаются или передаются многобайтные команды или пакеты данных. Рассмотрим пример обмена микроконтроллера с универсальным компьютером. Обычно для обмена используется последовательный порт компьютера (СОМ-порт). Схема согласования уровней сигналов последовательного порта микроконтроллера и СОМ-порта компьютера приведена на рис. 7.19.

Рис. 7.19. Схема согласования уровней сигналов последовательного порта микроконтроллера и СОМ-порта компьютера
Прежде чем начать программирование обмена через последовательный порт, необходимо определить формат команд обмена с компьютером.
Пусть обмен будет производиться ANSI-символами (их легче всего сформировать в любой терминальной программе на персональном компьютере). Первый переданный символ будет рассматриваться как команда. При использовании в качестве команды заглавных и строчных букв латинского алфавита будет доступно 56 команд. При желании можно добавить еще 64 команды, обозначаемые буквами русского алфавита. Следующие несколько символов составят поле данных. Обычно здесь используются цифры. Пусть у нас поле данных содержит четыре символа. В качестве завершения команды используем символ возврата каретки (ASCII-код "13"). Этот символ вводится при нажатии на клавишу <Enter>.
Итак, подпрограмма ввода информации должна принять шесть 8-разрядных символов и только после этого передать управление программе обработки информации. Естественно, что подпрограмма обработки информации, которая входит в один из мониторов, не знает, когда будет завершен прием команды, поэтому введем однобитовую переменную (флаг) завершения приема команды. Подпрограмма ввода информации будет записывать в эту переменную единицу, а подпрограмма обработки команд после выполнения команды будет записывать в эту переменную ноль.
Для того чтобы не пропустить ни одного байта, полученного через последовательный порт, оформим ввод информации как подпрограмму обработки прерывания. Для этого необходимо разрешить прерывания от последовательного порта при помощи подпрограммы инициализации микроконтроллера, приведенной в листинге 7.31.

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

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