<?xml version="1.0" encoding="utf-8"?>
<!-- generator="FeedCreator 1.7.2-ppt DokuWiki" -->
<?xml-stylesheet href="http://wiki.pic24.ru/lib/exe/css.php?s=feed" type="text/css"?>
<rdf:RDF
    xmlns="http://purl.org/rss/1.0/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
    xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel rdf:about="http://wiki.pic24.ru/feed.php">
        <title>PIC24 osa:tutorial</title>
        <description></description>
        <link>http://wiki.pic24.ru/</link>
        <image rdf:resource="http://wiki.pic24.ru/lib/images/favicon.ico" />
       <dc:date>2023-02-10T11:22:20+03:00</dc:date>
        <items>
            <rdf:Seq>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/osa/tutorial/intro?rev=1285333092"/>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/osa/tutorial/introduction?rev=1295425524"/>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor1?rev=1295425595"/>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor2?rev=1332239027"/>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor3?rev=1260368187"/>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor4?rev=1274808786"/>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor5?rev=1295443110"/>
            </rdf:Seq>
        </items>
    </channel>
    <image rdf:about="http://wiki.pic24.ru/lib/images/favicon.ico">
        <title>PIC24</title>
        <link>http://wiki.pic24.ru/</link>
        <url>http://wiki.pic24.ru/lib/images/favicon.ico</url>
    </image>
    <item rdf:about="http://wiki.pic24.ru/doku.php/osa/tutorial/intro?rev=1285333092">
        <dc:format>text/html</dc:format>
        <dc:date>2010-09-24T16:58:12+03:00</dc:date>
        <title>OSA : Учебник. Содержание</title>
        <link>http://wiki.pic24.ru/doku.php/osa/tutorial/intro?rev=1285333092</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;osa_учебник._содержание&quot; id=&quot;osa_учебник._содержание&quot;&gt;OSA : Учебник. Содержание&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/introduction&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:introduction&quot;&gt;Введение&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/tutor1&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:tutor1&quot;&gt;Урок 1. OS_Yield()&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/tutor2&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:tutor2&quot;&gt;Урок 2. Локальные переменные&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/tutor3&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:tutor3&quot;&gt;Урок 3. Задержки&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/tutor4&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:tutor4&quot;&gt;Урок 4. Бинарные семафоры&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/tutor5&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:tutor5&quot;&gt;Урок 5. Расширенный приоритетный режим&lt;/a&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

&lt;em&gt;(Продолжение следует…)&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
Виктор Тимофеев, &lt;a href=&quot;mailto:&amp;#x6f;&amp;#x73;&amp;#x61;&amp;#x40;&amp;#x70;&amp;#x69;&amp;#x63;&amp;#x32;&amp;#x34;&amp;#x2e;&amp;#x72;&amp;#x75;&quot; class=&quot;mail JSnocheck&quot; title=&quot;&amp;#x6f;&amp;#x73;&amp;#x61;&amp;#x40;&amp;#x70;&amp;#x69;&amp;#x63;&amp;#x32;&amp;#x34;&amp;#x2e;&amp;#x72;&amp;#x75;&quot;&gt;osa@pic24.ru&lt;/a&gt;
&lt;/p&gt;

&lt;/div&gt;
</description>
    </item>
    <item rdf:about="http://wiki.pic24.ru/doku.php/osa/tutorial/introduction?rev=1295425524">
        <dc:format>text/html</dc:format>
        <dc:date>2011-01-19T11:25:24+03:00</dc:date>
        <title>OSA : Учебник. Введение</title>
        <link>http://wiki.pic24.ru/doku.php/osa/tutorial/introduction?rev=1295425524</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;osa_учебник._введение&quot; id=&quot;osa_учебник._введение&quot;&gt;OSA : Учебник. Введение&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/intro&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:intro&quot;&gt;К оглавлению&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;OSA : Учебник. Введение&quot; [1-110] --&gt;
&lt;h2&gt;&lt;a name=&quot;вступление&quot; id=&quot;вступление&quot;&gt;Вступление&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

ОСРВ для многих - новый инструмент и, как при знакомстве с любым новым инструментом, у программиста возникает вопрос: с чего начать? В данном пособии приведены несколько примеров, позволяющих упростить понимание организации ОСРВ и принципов ее работы и самое главное - научиться ее использовать для проектирования своих программ. 
&lt;/p&gt;

&lt;p&gt;
Во &amp;quot;Введении&amp;quot; будут рассмотрены общие вопросы применения OSA. Здесь будет рассказано о том, как реализуется многозадачность на одном контроллере, показана структура взаимодействия программы и ядра ОС, а также будут приведены особенности программ, использующих OSA.
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Предполагается, что читатель уже знаком с PIC-контроллерами и языком программирования Си.

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Вступление&quot; [111-1413] --&gt;
&lt;h2&gt;&lt;a name=&quot;определения&quot; id=&quot;определения&quot;&gt;Определения&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Для начала дадим несколько определений.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;ядро&quot; id=&quot;ядро&quot;&gt;Ядро&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;
- совокупность подпрограмм и системных переменных, обеспечивающих взаимодействие задач и разделение ресурсов контроллера между ними. Ядро скрыто от программиста, взаимодействие с ним обеспечивается специальными сервисами ОС.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;задачи&quot; id=&quot;задачи&quot;&gt;Задачи&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;
- самостоятельные подпрограммы, имеющие возможность работать параллельно друг с другом.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;приоритет&quot; id=&quot;приоритет&quot;&gt;Приоритет&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;
- количественная характеристика задачи, отражающая ее важность по отношению к другим задачам. Приоритет рассматривается планировщиком при наличии нескольких готовых к выполнению задач как основной критерий для выбора, какой из них передавать управление.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;планировщик&quot; id=&quot;планировщик&quot;&gt;Планировщик&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;
- подпрограмма в составе ядра, занимающаяся поиском готовых к выполнению задач, выделением самой приоритетной из них и передачей ей управления.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;сервисы_ос&quot; id=&quot;сервисы_ос&quot;&gt;Сервисы ОС&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;
- набор подпрограмм и макросов, предназначенных для доступа к функциям ядра. В основном применяются для управления состояниями задач и обмена информацией между задачами.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;ресурсы&quot; id=&quot;ресурсы&quot;&gt;Ресурсы&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;
- аппаратные возможности микроконтроллера, а также внешние модули, подключенные к нему, которыми может пользоваться задача во время своего выполнения. 
&lt;/p&gt;

&lt;p&gt;
Ресурсами являются:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в первую очередь - модуль выборки и выполнения команд, программный счетчик, АЛУ, аккумулятор (WREG) и регистр состояния (STATUS) (в один момент времени выполняться может только одна задача);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; оперативная память (каждая задача может по-своему использовать память);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; внутренняя EEPROM (пока одна задача выполняет запись, другие не могут производить ни запись ни чтение);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; встроенные периферийные модули: последовательный порт, параллельный порт, АЦП, таймеры, порты ввода/вывода и т.д. (несколько задач могут выводить данные через USART; один и тот же вывод контроллера используется для разных целей);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; какие-то внешние устройства, подключенные к контроллеру: LCD, EEPROM, DAC и т.д.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Определения&quot; [1414-4839] --&gt;
&lt;h2&gt;&lt;a name=&quot;многозадачность&quot; id=&quot;многозадачность&quot;&gt;Многозадачность&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Термин многозадачность означает, что система способна обеспечить параллельное выполнение нескольких процессов (задач), разделяя между ними ресурсы контроллера.
&lt;/p&gt;

&lt;p&gt;
Не вдаваясь в подробности, рассмотрим, как выглядит многозадачность на практике. Рассмотрим для простоты параллельное выполнение двух процессов (задач): Task1 (голубой график) и Task2 (зеленый график). 
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Рис.1&lt;/strong&gt;&lt;br/&gt;
 
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_task_switch.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_task_switch.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_task_switch.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
На рисунке рис.1а изображено то, как многозадачность воспринимается пользователем: обе задачи выполняются одновременно, каждая выполняет какие-то свои действия (например, одна задача управляет двигателем стиральной машины, а другая выводит на индикатор текущее состояние: режим работы, время до завершения стирки, температуру стирки и т.д.). Пользователю кажется, что обе задачи выполняются одновременно. Но на самом деле это не совсем так. 
&lt;/p&gt;

&lt;p&gt;
Т.к. контроллер в один момент времени может выполнять только одну команду (или одну последовательность команд), то для выполнения двух задач он должен переключаться с выполнения одной последовательности команд на другую и обратно. Поэтому на уровне программы многозадачность будет выглядеть несколько иначе, чем на уровне пользователя (рис.1б): задачи по очереди сменяют друг друга, захватывая на какое-то время ресурсы контроллера. Одна задача, отработав какое-то время, приостанавливается и начинает выполняться другая. Пользователю же это будет незаметно, т.к. смена задач происходит достаточно быстро. 
&lt;/p&gt;

&lt;p&gt;
Контроллер должен знать, когда и какую последовательность команд выполнять, когда и как переключаться между ними. Для этого и служит операционная система. И на уровне операционной системы многозадачность будет выглядеть так, как показано на рис.1в. Обратим внимание, что здесь добавлен еще один график - желтый - ядро операционной системы. Прерываясь, задача Task1 передает управление не задаче Task2, а планировщику операционной системы (в кооперативных ОСРВ именно задача передает управление планировщику, в отличие от вытесняющих, где сам планировщик либо более приоритетная задача отнимают управление у менее приоритетной), который в свою очередь принимает решение о том, какой задаче отдать управление. В нашем случае он отдает управление задаче Task2. Когда Task2 отдает управление планировщику, у Task1 появляется шанс получить управление вновь.
&lt;/p&gt;

&lt;p&gt;
Наконец, для полноты картины добавим еще один график (рис.1г) - прерывания. Как видно из рисунка прерывание может прервать как задачу, так и планировщик. 
&lt;/p&gt;

&lt;p&gt;
Здесь, наверное, может возникнуть вопрос: для чего нужны сложности с планировщиком, если можно в вечном цикле (часто называют суперциклом или суперлупом) по очереди вызывать функции, содержащие код для Task1 и Task2? Штука в том, что при вызове функции мы каждый раз попадаем в ее начало, в то время как ОС позволяет нам прервать функцию в любом месте, позволив выполниться другим функциям, а затем продолжить ее выполнение с того места, где она была приостановлена. (Это основное отличие от суперцикла. На остальных отличиях пока не будем заострять внимание.) Благодаря этой особенности, каждая задача может быть написана как отдельная независимая программа (она должна быть написана с учетом некоторых требований, но об этом чуть ниже).
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Многозадачность&quot; [4840-10682] --&gt;
&lt;h2&gt;&lt;a name=&quot;структура_программы_под_osa&quot; id=&quot;структура_программы_под_osa&quot;&gt;Структура программы под OSA&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

На рис.2 схематически изображено взаимодействие программы пользователя с ядром операционной системы. Все, что находится внутри желтого прямоугольника, - это ядро ОС, скрытое от программиста. Взаимодействие с ним производится только через сервисы ОС.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Рис.2&lt;/strong&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_system.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_system.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_system.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Логически программа получается разбита на 5 частей:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;ядро&lt;/strong&gt; системы (желтое);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;main()&lt;/strong&gt; - основная функция Си-программы;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;прерывание&lt;/strong&gt; (красное) - код прерывания; обратим внимание, что рядом с прерыванием стоит &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;(), присоединенный к нему пунктирной линией; такая условная привязка показывает, что сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; чаще всего (но не всегда) вызывается именно из прерывания;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;задачи&lt;/strong&gt; (светло-голубые) - Си-функции, которые предполагается использовать как параллельно выполняющиеся задачи ОС;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;функции&lt;/strong&gt; - все вспомогательные функции.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Сердцем ядра является планировщик, который оперирует с массивом задач, выбирая из него самую приоритетную из готовых и передавая ей управление. Массив задач - это массив дескрипторов, содержащих для каждой активной задачи данные, необходимые для работы с ней: текущий адрес или точка возврата в задачу, состояние задачи (готова, ждет событие, пауза, задержка), таймер задачи (у каждой - свой) и некоторые дополнительные данные в зависимости от используемой платформы (например, для MCC18 - значение регистра FSR1, т.е. указателя стека; для MCC30 - регистры общего назначения W8..W15).
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Структура программы под OSA&quot; [10683-13337] --&gt;
&lt;h3&gt;&lt;a name=&quot;передача_управления_внутри_системы&quot; id=&quot;передача_управления_внутри_системы&quot;&gt;Передача управления внутри системы&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Красными линиями показаны пути передачи управления внутри программы. Причем светло-красные обозначают вызов подпрограммы (т.е. подразумевает возврат из нее), а темно-красные - передачу управления безусловным переходом (без возврата). Обратим внимание на три момента:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; передача управления от &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;() планировщику ОС производится только в одном направлении. Это означает, что после вызова сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; управление берет на себя ядро ОС, т.е. на этом вызове выполнение функции main() заканчивается;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; вызов функций-задач осуществляется только самим планировщиком и скрыт от программиста;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; вызов функций из тела прерывания - не всеми поддерживаемая практика, тем не менее, такое допустимо.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

После ресета мы попадаем в функцию main(), где производим инициализацию системы &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt;(), создаем задачи &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_task_create&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_task_create&quot;&gt;OS_Task_Create&lt;/a&gt;&lt;/span&gt;() и передаем управление планировщику &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;(). Планировщик живет сам по себе, циклически проверяя все задачи в своем внутреннем списке на предмет готовности. Когда появляются готовые к выполнению задачи, планировщик выбирает из них ту, приоритет которой самый высокий, и передает ей управление. Обратите внимание, что передача управления задаче отмечена на рисунке темно-красной линией: это значит, что задача должна будет сама вернуть управление ядру, иначе остальные задачи никогда не получат управление. Для возврата в планировщик есть специальные сервисы: безусловный возврат, перевод в режим ожидания события или задержки, приостановка задачи и удаление задачи.
&lt;/p&gt;

&lt;p&gt;
Во время своего выполнения задача может вызывать другие функции (не являющиеся задачами).
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Передача управления внутри системы&quot; [13338-16426] --&gt;
&lt;h3&gt;&lt;a name=&quot;обмен_данными&quot; id=&quot;обмен_данными&quot;&gt;Обмен данными&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Голубыми линии показано направление обмена данными. Рассмотрим особенности:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt;() очищает массив задач;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_task_create&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_task_create&quot;&gt;OS_Task_Create&lt;/a&gt;&lt;/span&gt;() - добавляет задачу в список, если там есть свободное место;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; массив задач снабжает данными планировщик;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;() увеличивает значения таймеров задач, отслеживая их переполнение, и пользовательских таймеров, также следя за переполнениями;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; из функций задач, помимо обычных сервисов, разрешенных для использования в любом месте программы, можно также использовать сервисы, переключающие контекст (т.е. передающие управление планировщику), поэтому рядом с линией между задачами и сервисами стоит литера &amp;quot;Т&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; из прерывания, помимо общих сервисов, можно вызывать специальные сервисы, предназначенные для работы в прерывании, поэтому рядом с линией стоит литера &amp;quot;I&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; из функций разрешен вызов сервисов, не переключающих контекст и не предназначенных для работы в прерывании.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Обмен данными&quot; [16427-18223] --&gt;
&lt;h2&gt;&lt;a name=&quot;особенности_программы_написанной_с_использованием_osa&quot; id=&quot;особенности_программы_написанной_с_использованием_osa&quot;&gt;Особенности программы, написанной с использованием OSA&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Программа, написанная с использованием ОСРВ OSA, должна быть написана с учетом некоторых требований:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в папке проекта должен быть размещен файл &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; - файл конфигурации системы (в простейшем случае этот файл может быть пустым);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в проект, помимо файлов самой программы, должен быть включен файл osa.c (это требование не относится к программам, написанным на CCS);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; во все Си-файлы проекта, в которых предполагается использование системных сервисов, должен быть включен файл osa.h (директивой #include);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в опциях компилятора должны быть указаны пути для включаемых файлов (include-пути): путь к папке проекта и путь к папке, где находятся файлы osa.c и osa.h;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в функции main() должны вызываться два системных сервиса: &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt; и &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в программе должна быть одна или несколько функций, описанных как задачи.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

Ниже в двух словах все эти пункты расшифровываются. Здесь их расшифровка приводится только для информации; более подробно они будут рассмотрены по ходу уроков.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Особенности программы, написанной с использованием OSA&quot; [18224-20172] --&gt;
&lt;h3&gt;&lt;a name=&quot;osacfg.h&quot; id=&quot;osacfg.h&quot;&gt;osacfg.h&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Система OSA является довольно гибкой в настройке, что позволяет сконфигурировать ее под конкретный проект так, чтобы минимизировать ресурсозатраты. Все указания по конфигурации OSA для конкретного проекта задаются в файле &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; (поэтому и важно, чтобы файл находился именно в папке проекта). В самом простом случае этот файл может быть пустым, тогда система будет сконфигурирована по умолчанию. Однако в большинстве случаев может понадобиться внести коррекцию в настройки системы с тем, чтобы повысить эффективность использования ОСРВ. 
&lt;/p&gt;

&lt;p&gt;
Этот файл можно создавать вручную, задавая нужные значения констант конфигурации, описанные &lt;strong&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;здесь&lt;/a&gt;&lt;/strong&gt;. Но гораздо проще, удобнее, быстрее и нагляднее пользоваться специальной утилитой OSAcfg_Tool, которую можно скачать &lt;strong&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/download/intro&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:download:intro&quot;&gt;здесь&lt;/a&gt;&lt;/strong&gt;. Эта программа представляет собой диалоговое окно, в котором программист выбирает параметры системы для своего проекта: количество задач, банки памяти для размещения системных переменных, размерности переменных и т.д. Далее в уроках мы будем создавать этот файл с использованием этой утилиты. Те, кто не захотят ей пользоваться, а захотят создавать файл конфигурации вручную, смогут один раз заглянуть в сгенерированный утилитой файл, чтобы понять, как правильно его создавать.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;osacfg.h&quot; [20173-22559] --&gt;
&lt;h3&gt;&lt;a name=&quot;osa.c&quot; id=&quot;osa.c&quot;&gt;osa.c&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Этот файл содержит определения всех системных переменных и функций. Было решено его оставить именно в виде Си-файла, не компилируя в библиотеку, с тем, чтобы он был максимально гибким в настройке. Т.к. PIC-контроллеры младшего семейства имеют дефицит ресурсов, то бывает так, что каждый байт на счету. Максимальной оптимизации получится добиться только использованием условных директив в Си-файле. В противном случае пришлось бы создавать целую кучу вариантов библиотечных файлов под разные контроллеры и под различные конфигурации, что усложнило бы процесс создания проекта и процесс изменения конфигурации в ходе работы над проектом.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;osa.c&quot; [22560-23742] --&gt;
&lt;h3&gt;&lt;a name=&quot;osa.h&quot; id=&quot;osa.h&quot;&gt;osa.h&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Этот файл содержит прототипы системных функций, предопределения системных переменных, а также включает в себя файлы с определением макросов всех системных сервисов. Именно этому файлу требуется наличие файла конфигурации &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt;, т.к., опираясь на настроечные константы из него, будет принято решение о том, какие функции и переменные включать в программу.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;osa.h&quot; [23743-24449] --&gt;
&lt;h3&gt;&lt;a name=&quot;include-пути&quot; id=&quot;include-пути&quot;&gt;include-пути&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Здесь все просто: компилятор должен знать, где искать подключаемые файлы, а именно - osa.h (и, следовательно, все файлы включаемые в него из папок osa\port и osa\service) и файл &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt;, чтобы он был включен в osa.h.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;include-пути&quot; [24450-24871] --&gt;
&lt;h3&gt;&lt;a name=&quot;os_init_и_os_run&quot; id=&quot;os_init_и_os_run&quot;&gt;OS_Init() и OS_Run()&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Наличие вызова этих двух сервисов обязательно. Причем &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt; должен быть вызван в самом начале программы до вызова какого-либо другого сервиса ОС, а &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; - в самом конце (после &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; ничего не будет выполняться, т.к. этот сервис переводит программу в вечный цикл).
&lt;/p&gt;

&lt;p&gt;
&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt; - процедура инициализации системы. В ней подготавливаются все системные переменные, обнуляются списки задач, таймеров, семафоров. Этот сервис должен вызываться один раз за все выполнение программы (если, конечно, самой программой не предусмотрен программный ресет). 
&lt;/p&gt;

&lt;p&gt;
&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; - этот сервис представляет собой вечный цикл, в котором крутится планировщик - подпрограмма, отвечающая за проверку готовности задач, сравнение приоритетов у готовых задач и передачу управления наиболее приоритетной из готовых задаче. Т.к. сервис содержит внутри себя вечный цикл, то все, что в программе идет за вызовом этого сервиса, будет либо проигнорировано на стадии компиляции, либо просто никогда не получит управление.
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    ...           &lt;span class=&quot;co1&quot;&gt;// Инициализация периферии, переменных программы и пр.&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    ...           &lt;span class=&quot;co1&quot;&gt;// Создание задач, подготовка сервисов&lt;/span&gt;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- SECTION &quot;OS_Init() и OS_Run()&quot; [24872-27114] --&gt;
&lt;h3&gt;&lt;a name=&quot;функции-задачи&quot; id=&quot;функции-задачи&quot;&gt;Функции-задачи&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Те функции, которые предполагается выполнять параллельно, т.е. сами задачи, описываются как обычные Си-функции с параметром void, но должны быть оформлены по определенным правилам:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; тело функции должно содержать вечный цикл (есть случаи, когда можно обойтись и без него, но на первых порах этого делать не стоит);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; внутри вечного цикла должен вызываться хотя бы один сервис, передающий управление планировщику;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; из этой функции нельзя осуществлять выход оператором &lt;strong&gt;return&lt;/strong&gt;.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

Из функции-задачи можно вызывать другие функции (не являющиеся задачами). Локальные переменные всех функций задач занимают одну и ту же область памяти, и после передачи задачей управления планировщику значения локальных переменных будут утеряны. Если есть переменные, значения которых важно сохранить до следующего получения управления, должны быть описаны как &lt;strong&gt;static&lt;/strong&gt;.
&lt;/p&gt;

&lt;p&gt;
Вот типичный пример функции-задачи:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_ucCounter;    &lt;span class=&quot;co1&quot;&gt;// Определение глобальных переменных задачи&lt;/span&gt;
           &lt;span class=&quot;kw4&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; i, j;           &lt;span class=&quot;co1&quot;&gt;// Определение локальных переменных задачи&lt;/span&gt;
&amp;nbsp;
    s_ucCounter &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;                     &lt;span class=&quot;co1&quot;&gt;// Код подготовки (если нужен)&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Осталось только определиться с тем, как операционная система узнает, какие функции являются задачами, а какие - нет. Мы сами ей об этом сообщим через системный сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_task_create&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_task_create&quot;&gt;OS_Task_Create&lt;/a&gt;&lt;/span&gt;, добавив, таким образом, указатель на функцию во внутренний список системы. Сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; в своем цикле просматривает этот список и передает управление по занесенным в него указателям.
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;, Task_1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Теперь система знает, что Task_1 - это задача ОС&lt;/span&gt;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Функции-задачи&quot; [27115-30119] --&gt;
&lt;h2&gt;&lt;a name=&quot;замечание_об_именах_идентификаторов&quot; id=&quot;замечание_об_именах_идентификаторов&quot;&gt;Замечание об именах идентификаторов&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Во всех уроках мы будем придерживаться единого стиля именования идентификаторов, чтобы не возникало путаницы. Вот они:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; имена констант будут даваться заглавными буквами;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; имена переменных будут содержать префиксы:&lt;/div&gt;
&lt;ol&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; области видимости:&lt;/div&gt;
&lt;ul&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;m_&lt;/span&gt;&amp;quot; - глобальная для всех модулей;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;s_&lt;/span&gt;&amp;quot; - статическая переменная внутри функции;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; без префикса - локальная переменная внутри функции или аргумент функции.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; типа переменной:&lt;/div&gt;
&lt;ul&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;uc&lt;/span&gt;&amp;quot; - unsigned char;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;sc&lt;/span&gt;&amp;quot; - signed char;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;c&lt;/span&gt;&amp;quot; - char (в случаях, когда не важно, знаковый или беззнаковый);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;b&lt;/span&gt;&amp;quot; - bit;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;n&lt;/span&gt;&amp;quot; - signed int;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;w&lt;/span&gt;&amp;quot; - unsigned int;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;l&lt;/span&gt;&amp;quot; - signed long;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;dw&lt;/span&gt;&amp;quot; - unsigned long;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level3&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;&lt;span class=&quot;important&quot;&gt;smsg_&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span class=&quot;important&quot;&gt;msg_&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span class=&quot;important&quot;&gt;queue_&lt;/span&gt;&amp;quot; и т.п. - префиксы для глобальных переменных управления сервисами.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; имена функций-задач будут содержать префикс &amp;quot;Task_&amp;quot;.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Такая система имен может показаться запутанной и ненужной, однако моя практика показала, что она позволяет, во-первых, предотвращать ошибки на стадии написания программы, а во-вторых, сильно упрощает чтение чужой программы (или своей спустя год-два). Возможно, у кого-то есть своя система имен, я никому мою не навязываю, но в данных уроках мы будем пользоваться приведенной выше системой. И встретив в программе переменную с именем, например, s_ucCounter, вы сразу поймете, что это статическая переменная внутри задачи (ее значение будет сохраняться после передачи управления планировщику) типа unsigned char.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Замечание об именах идентификаторов&quot; [30120-32681] --&gt;
&lt;h2&gt;&lt;a name=&quot;замечание_о_локальных_переменных_внутри_функций-задач&quot; id=&quot;замечание_о_локальных_переменных_внутри_функций-задач&quot;&gt;Замечание о локальных переменных внутри функций-задач&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Я о локальных переменных в задачах уже упоминал, но остановлюсь на этом вопросе немного подробнее. Дело в том, что ОСРВ OSA является некоей надстройкой над компилятором, и сам компилятор не учитывает ее особенностей. В частности компилятор не знает о том, что в программе есть такие функции, выполнение которых может прерываться в произвольном месте (мы сами точно знаем, что функции прерываются в местах, где происходят вызовы сервисов передающих управление планировщику, но компилятору это неведомо). Поэтому он считает, что локальные переменные, описанные внутри такой функции, являются собственностью этих функций на протяжении всего времени их выполнения. На этапе компиляции строится граф вызовов, опираясь на который, линкер распределяет память под локальные переменные так, чтобы между ними не было пересечений на разных уровнях графа, при этом локальные переменные функций одного уровня могут располагаться в одной и той же области памяти, т.к. предполагается, что эти функции не будут прерывать друг друга. 
&lt;/p&gt;

&lt;p&gt;
Однако в случае с ОСРВ дело обстоит иначе, а именно - все функции-задачи, находящиеся на одном уровне в графе вызовов (первый уровень после main), выполняются параллельно, постоянно сменяя друг друга в ходе выполнения. И т.к. у них под локальные переменные задействована одна и та же область памяти, задачи при переключении между собой будут пользоваться этой областью каждая под свои нужды, затирая данные, записанные туда другими задачами. Поэтому, если важно, чтобы значение переменной сохранилось после передачи управления планировщику (а следовательно - и другим задачам), то ее нужно определять с квалификатором &lt;strong&gt;static&lt;/strong&gt;. Тогда эта переменная будет размещена в другой области памяти и будет закреплена исключительно за той функцией, в которой она определена. По ходу рассмотрения уроков мы будем возвращаться к этой теме.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Замечание о локальных переменных внутри функций-задач&quot; [32682-36167] --&gt;
&lt;h2&gt;&lt;a name=&quot;состояния_задач&quot; id=&quot;состояния_задач&quot;&gt;Состояния задач&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Как описано в документации в параграфе &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/events_and_priority&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:events_and_priority&quot;&gt;&amp;quot;Состояния задач&amp;quot;&lt;/a&gt;, задача может находиться в одном из пяти состояний: не создана (удалена), в ожидании, в готовности, в работе и приостановлена. Ниже схематически изображен граф изменения состояний:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_task_states.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_task_states.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_task_states.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Примечания&lt;/strong&gt;:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;em&gt;Задача может быть создана или продолжена после приостановки только извне.&lt;/em&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;em&gt;На графе состояний не показано, что любая задача в любой момент может быть приостановлена/продолжена/удалена извне.&lt;/em&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Состояния задач&quot; [36168-37129] --&gt;
&lt;h2&gt;&lt;a name=&quot;особенности_отладки&quot; id=&quot;особенности_отладки&quot;&gt;Особенности отладки&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Отладка программы, написанной под ОСРВ, немного отличается от отладки обычной программы. Это связано, главным образом, с тем, что тело основной функции программы (планировщика задач) скрыто от программиста (сам планировщик оформлен в виде макроса, что позволяет запускать его тело исключительно в окне дизассемблера). 
&lt;/p&gt;

&lt;p&gt;
Сейчас этот параграф можно пропустить, т.к. в нем используются термины и куски программ, которые будут рассмотрены в уроках. По ходу уроков мы будем ссылаться на этот параграф для объяснения некоторых моментов, связанных с отладкой.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Особенности отладки&quot; [37130-38190] --&gt;
&lt;h3&gt;&lt;a name=&quot;пошаговая_отладка&quot; id=&quot;пошаговая_отладка&quot;&gt;Пошаговая отладка&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
Два слова о том, как работает пошаговый отладчик (это относится и к симулятору, и к внутрисхемным отладчикам). При выполнении команды Step Over (F8) отладчик делает следующее:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; запоминает адрес следующей за выполняемой строкой строки (при работе в симуляторе он просто запоминается, при работе с внутрисхемными отладчиками на следующей строке устанавливается breakpoint);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; запускает программу на выполнение;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; дойдя до запомненного адреса (или до breakpoint&amp;#039;а) останавливает выполнение программы;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; при работе с внутрисхемными отладчиками удаляет breakpoint.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Зачем такие хитрости с точками останова? Дело в том, что одна строка Си-кода может быть транслирована в несколько (иногда в сотни) инструкций ассемблера. Кроме того, текущая строка может просто-напросто содержать в себе вызов подпрограммы. Чтобы при выполнении каждой инструкции не проверять, дошла ли программа до требуемого адреса, ставится точка останова. К слову сказать, симулятору все равно, как это делать: через точку останова или прямым сравнением текущего адреса с адресом следующей строки; но внутрисхемному отладчику это важно, т.к. проверка адреса после выполнения каждой инструкции очень сильно замедлила бы его работу.
&lt;/p&gt;

&lt;p&gt;
Рассмотрим на конкретном примере. Предположим, программный счетчик в данный момент указывает на строку программы, содержащую вызов функции:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_debug_step.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_debug_step.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_debug_step.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Когда пользователь нажимает F8, запоминается программный адрес следующей за вызовом функции delay(10) строки: &amp;quot;cCounter = 25;&amp;quot;. Далее программа начинает выполняться. Т.е. заходит внутрь подпрограммы delay(), выполняет внутри нее какие-то действия, возможно даже вызов других подпрограмм. Но как только будет произведен возврат из подпрограммы delay(), и программный счетчик станет равным запомненному в начале адресу (или, если мы работаем с внутрисхемным отладчиком, как только программа дойдет до точки останова), отладчик приостановит выполнение программы (удалив при этом точку останова), и мы увидим, что зеленая стрелка теперь указывает на строку присваивания &amp;quot;cCounter = 25;&amp;quot;. 
&lt;/p&gt;

&lt;p&gt;
&lt;em&gt;&lt;strong&gt;Примечание.&lt;/strong&gt; Если в теле функции delay() или в теле одной из функций, которые вызываются из функции delay(), стоит пользовательская точка останова, то отладчик прервет выполнение программы, как только программный счетчик станет равным адресу точки останова.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
Рассмотрим простой пример синхронизации двух задач с помощью бинарного семафора:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Set&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;      &lt;span class=&quot;co1&quot;&gt;// Позволяем выполниться задаче 2&lt;/span&gt;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//--------------------------&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;     &lt;span class=&quot;co1&quot;&gt;// Ждем события от задачи 1&lt;/span&gt;
        PIN_LED &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;            &lt;span class=&quot;co1&quot;&gt;// Мигаем светодиодом&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
&lt;em&gt;&lt;strong&gt;Примечание:&lt;/strong&gt; &lt;acronym title=&quot;Personal Identification Number&quot;&gt;PIN&lt;/acronym&gt;_LED - вывод контроллера, управляющий светодиодом.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
Эта программа включает/выключает светодиод на выводе &lt;acronym title=&quot;Personal Identification Number&quot;&gt;PIN&lt;/acronym&gt;_LED с интервалом в 10 системных тиков. Логика работы программы такова: задача Task1 с интервалом в 10 системных тиков устанавливает бинарный семафор. Задача Task2 находится в режиме ожидания семафора. Как только она видит, что семафор установлен, она становится готовой к выполнению и при первой же возможности получает его (становится в режим работы), при этом семафор сразу сбрасывается (это делается автоматически сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;()). После этого состояние светодиода меняется на противоположное (зажжен/погашен), и задача вновь становится в режим ожидания двоичного семафора (ведь он был сброшен сразу же при входе в задачу). Задача Task1 все это время находится в режимы ожидания задержки. Через 10 системных тиков она станет готовой к выполнению и после его получения вновь установит семафор. 
&lt;/p&gt;

&lt;p&gt;
Схематически программа будет выглядеть так:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_debug_test.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_debug_test.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_debug_test.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Как видно из рисунка, обе задачи выполняются по одному разу, после чего система бездействует (планировщик крутится впустую, т.к. нет готовых задач: одна ждет завершения задержки, другая - установки семафора). В это время у нас происходят прерывания, в коде обработчика которых вызывается сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;, который следит за отсчетом задержки задачи Task1. Как только время задержки истекает, планировщик переводит задачу Task1 в готовность, а так как она единственная готовая к выполнению задача, то она сразу получает управление. Получив его, она вновь устанавливает семафор, делая готовой задачу Task2, а сама опять встает в режим ожидания задержки. И так по кругу.
&lt;/p&gt;

&lt;p&gt;
Рассмотрим, что произойдет, если мы попытаемся пройти эту программу в симуляторе по шагам (F8). 
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Ниже будет рассмотрено поведение отладчика при работе под PICC18, MCC18 и MCC30. При отладке под PICC для контроллеров PIC10, PIC12 и PIC16 есть свои нюансы, которые будут рассмотрены далее.

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;

Первым делом мы попадаем в начало функции main(). Пройдя по шагам вызовы всех подпрограмм инициализации (периферии и системы) и создание задач, мы подойдем к вызову сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;, который запускает планировщик в работу. Здесь мы столкнемся с первой неприятностью. Дело в том, что при попытке выполнить &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; командой Step Over (F8) программа начнет выполняться и никогда не остановится (если мы ее сами не остановим). Произойдет это потому, что отладчик запомнит адрес следующей за &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; строки, но на него программа никогда не попадет, т.к. &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; содержит в себе вечный цикл. 
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Поэтому, если мы хотим отладить какую-нибудь функцию-задачу по шагам, то сперва-наперво следует поставить в ней точку останова. 

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;task1&quot; id=&quot;task1&quot;&gt;Task1&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Итак, попробуем выполнить задачу Task1 по шагам, для чего сперва установим точку останова на вызове сервиса:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_debug_breakpoint.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_debug_breakpoint.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_debug_breakpoint.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Далее хоть по шагам (F8), хоть сразу (F9) - дойдем до этой точки останова. Теперь рассмотрим, что получится, когда мы попытаемся выполнить пошаговую отладку. Если бы программа была написана по принципу суперцикла, то поведение отладчика было бы предсказуемым: после установки семафора мы бы через несколько шагов очутились бы в задаче Task2 на строке, следующей за ожиданием семафора. Однако с программой, написанной под ОСРВ, отладчик поведет себя немного иначе. Нажмем F8, выполним тем самым вызов сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_set&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_set&quot;&gt;OS_Bsem_Set&lt;/a&gt;&lt;/span&gt;(), т.е. установив двоичный семафор. Отладчик сделает шаг и остановится перед вызовом системного сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;(). Сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_set&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_set&quot;&gt;OS_Bsem_Set&lt;/a&gt;&lt;/span&gt; не содержит внутри себя передачи управления планировщику, поэтому с ним трудностей не возникло. Но вот сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; при выполнении передаст управление планировщику. 
&lt;/p&gt;

&lt;p&gt;
Что при этом произойдет. Отладчик запомнит адрес следующей строки за &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, т.е. адрес конца (или начала, как удобнее) цикла, и запустит программу на выполнение. Программа будет выполняться до тех пор, пока программный счетчик не станет равным запомненному адресу. Т.е. за один шаг F8 произойдет следующее:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; управление будет передано планировщику;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; планировщик запустит задачу Task2, т.к. она окажется единственной готовой к выполнению;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Task2 изменит состояние светодиода;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Task2 передаст управление планировщику, встав в режим ожидания;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; планировщик будет крутиться вхолостую, пока вызываемый в прерывании сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; не обнаружит, что время задержки Task1 вышло; при этом Task1 установится в режим готовности;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; планировщик передаст управление единственной готовой задаче Task1.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Другими словами вся работа Task2 выполнится незаметно для нас. Мы нажмем F8, находясь перед вызовом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;() и имея установленный семафор, и сразу же окажемся в начале цикла, перед вызовом сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_set&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_set&quot;&gt;OS_Bsem_Set&lt;/a&gt;&lt;/span&gt;(). К этому моменту мы обнаружим, что светодиод уже поменял свое состояние, а семафор уже сброшен. Схематически это можно изобразить так:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_debug_test_step_task1.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_debug_test_step_task1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_debug_test_step_task1.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Все, что в заштрихованной области, включая все тело Task2, будет выполнено за один шаг.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;task2&quot; id=&quot;task2&quot;&gt;Task2&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Точно так же отладчик поведет себя, если мы попытаемся выполнить по шагам задачу Task2. Дойдя до вызова сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;, который передает управление планировщику, мы будем знать, что при выполнении команды отладчика Step Over (F8) мы за один шаг пропустим весь цикл выполнения задачи Task1, вместе с задержкой в 10 системных тиков. 
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_debug_test_step_task2.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_debug_test_step_task2.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_debug_test_step_task2.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Все, что в заштрихованной области, включая все тело Task1, будет выполнено за один шаг.
&lt;/p&gt;

&lt;p&gt;
При пошаговой отладке задачи Task2 мы будет крутиться в цикле, по очереди выполняя две операции: ожидание семафора, изменении состояния светодиода. Все остальные задачи, которые активны на данный момент, будут выполняться в фоновом режиме незаметно для нас.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;вывод&quot; id=&quot;вывод&quot;&gt;Вывод&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

К чему все это рассказывается? Вот к чему:
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteimportant&quot;&gt;
Если при отладке нам важно проследить цепочку взаимодействия задач между собой, то мы должны во всех местах, имеющих отношение к этому взаимодействию, ставить точки останова (breakpoint&amp;#039;ы). Причем устанавливать их нужно непосредственно &lt;strong&gt;за&lt;/strong&gt; сервисами, переключающими контекст (передающими управление планировщику).

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
В нашем конкретном примере нужно поставить две точки останова: за сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; (а именно - на вызове сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_set&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_set&quot;&gt;OS_Bsem_Set&lt;/a&gt;&lt;/span&gt;) для задачи Task1 и за сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt; (а именно - на операции &lt;acronym title=&quot;Personal Identification Number&quot;&gt;PIN&lt;/acronym&gt;_LED ^= 1) для задачи Task2. 
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;примечание_для_pic10_pic12_и_pic16&quot; id=&quot;примечание_для_pic10_pic12_и_pic16&quot;&gt;Примечание для PIC10, PIC12 и PIC16&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Все выше сказанное относилось к работе с компиляторами PICC18, MCC18 и MCC30. При работе с компилятором PICC нельзя точно предсказать поведение отладчика при попытке выполнить сервис, переключающий контекст, в пошаговом режиме. Поэтому, когда будете производить отладку программы, написанной под PICC, выполняйте сервисы, переключающие контекст, командой отладчика Run (F9), предварительно установив точки останова в интересующих местах. Иногда это бывает сложно (особенно при работе с внутрисхемным отладчиком, который имеет возможность поставить всего одну точку останова), т.к. не всегда удается предсказать, какую задачу планировщик выберет для выполнения. Но другого способа отладки пока нет.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Пошаговая отладка&quot; [38191-55924] --&gt;
&lt;h3&gt;&lt;a name=&quot;просмотр_переменных&quot; id=&quot;просмотр_переменных&quot;&gt;Просмотр переменных&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Работая с сервисами, управляющими пользовательскими данными (сообщения, очереди, флаги, семафоры, таймеры), иногда необходимо следить за их состояниями через окно Watch. С переменными, создаваемыми программистом явно, все понятно: каждая такая переменная имеет свой идентификатор и свою область видимости. Например:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;OST_SMSG   smsg_Sound;
OST_DTIMER dt_Alarm;&lt;/pre&gt;
&lt;p&gt;
Эти две переменные типов &amp;quot;короткое сообщение&amp;quot; и &amp;quot;динамический таймер&amp;quot; могут быть добавлены в окно Watch, в котором за ними можно будет наблюдать. Таким же образом можно наблюдать за переменными следующих типов:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_smsg&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_SMSG&lt;/a&gt;&lt;/span&gt; - короткое однобайтовое сообщение;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_msg&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_MSG&lt;/a&gt;&lt;/span&gt; - указатель на сообщение;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_msg_cb&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_MSG_CB&lt;/a&gt;&lt;/span&gt; - дескриптор управления указателем на сообщение;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_flag&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_FLAG&lt;/a&gt;&lt;/span&gt;, &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_flag&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_FLAG&lt;/a&gt;&lt;/span&gt;16, &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_flag&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_FLAG&lt;/a&gt;&lt;/span&gt;32) - флаги;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_csem&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_CSEM&lt;/a&gt;&lt;/span&gt; - счетный семафор;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_queue&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_QUEUE&lt;/a&gt;&lt;/span&gt;, &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_squeue&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_SQUEUE&lt;/a&gt;&lt;/span&gt; - очереди сообщений;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/data_types#ost_dtimer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:data_types&quot;&gt;OST_DTIMER&lt;/a&gt;&lt;/span&gt; - динамический таймер.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Но OSA имеет два вида пользовательских переменных, которые создаются на этапе компиляции и контролируются самой системой: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; двоичные семафоры;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; статические таймеры.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Т.е. двоичные семафоры и статические таймеры не имеют собственных идентификаторов. Они сгруппированны в массивы, что позволяет сократить код обработки этих данных и сэкономить оперативную память. Однако такая организация затрудняет отслеживание значений этих переменных при отладке. 
&lt;/p&gt;

&lt;p&gt;
Как их наблюдать? 
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;двоичные_семафоры&quot; id=&quot;двоичные_семафоры&quot;&gt;Двоичные семафоры&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Все двоичные семафоры хранятся в массиве:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; OS_BSem&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;

размерность которого зависит от количества используемых в системе семафоров (задается константой &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OS_BSEMS&lt;/a&gt;&lt;/span&gt; в файле конфигурации &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt;) из расчета: один байт на каждую неполную восьмерку. (&lt;strong&gt;Примечание.&lt;/strong&gt; Для MCC30 элементы массива имею тип &lt;strong&gt;unsigned int&lt;/strong&gt;.)
&lt;/p&gt;

&lt;p&gt;
Младший бит в нулевом элементе массива - это нулевой семафор. Байт с маской 0x02 - первый, 0x04 - второй и т.д. Таким образом, чтобы отследить нужный нам семафор при отладке, нам надо следить за состоянием соответствующего бита в массиве &lt;acronym title=&quot;Operating System&quot;&gt;OS&lt;/acronym&gt;_BSem. Это довольно неудобно, но такова плата за экономию оперативной памяти.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;статические_таймеры&quot; id=&quot;статические_таймеры&quot;&gt;Статические таймеры&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Все статические таймеры хранятся в массиве:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;_OST_STIMER OS_STimers&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Тип элементов массива и размерность массива задается в файле &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; константами &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OS_STIMER_SIZE&lt;/a&gt;&lt;/span&gt; и &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OS_STIMERS&lt;/a&gt;&lt;/span&gt;, соответственно. Каждый элемент массива - отдельный таймер. Самый старший бит каждого таймера (7-ой, 15-ый или 31-ый, в зависимости от типа) - бит активности. Если он установлен, значит, таймер считает. Если сброшен, - таймер переполнился и остановлен. Статические таймеры в окне Watch удобно отображать в виде знаковых целых чисел. Тогда будет видно, сколько времени осталось до окончания счета. Например:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_debug_watch_stimers.png?id=osa%3Atutorial%3Aintroduction&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_debug_watch_stimers.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_debug_watch_stimers.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Здесь видно, что статический таймер 0 считает (т.к. число отрицательное), и ему осталось 2000 системных тиков до завершения счета. Статический таймер 1 - не считает, т.к. старший бит сброшен (число не отрицательное).
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Просмотр переменных&quot; [55925-] --&gt;</description>
    </item>
    <item rdf:about="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor1?rev=1295425595">
        <dc:format>text/html</dc:format>
        <dc:date>2011-01-19T11:26:35+03:00</dc:date>
        <title>OSA : Учебник. Урок 1 - OS_Yield</title>
        <link>http://wiki.pic24.ru/doku.php/osa/tutorial/tutor1?rev=1295425595</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;osa_учебник._урок_1_-_os_yield&quot; id=&quot;osa_учебник._урок_1_-_os_yield&quot;&gt;OSA : Учебник. Урок 1 - OS_Yield&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/intro&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:intro&quot;&gt;К оглавлению&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;OSA : Учебник. Урок 1 - OS_Yield&quot; [1-115] --&gt;
&lt;h2&gt;&lt;a name=&quot;тема&quot; id=&quot;тема&quot;&gt;Тема&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Для начала рассмотрим самый простой пример - параллельную работу двух пустых задач. Практически он ничего не будет делать, но для нас может оказаться полезным для понимания механизма работы ОС. Данную программу можно будет погонять в симуляторе, наставив брейкпоинтов. Цель урока - исследование работы сервиса безусловного переключения контекста &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;().
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Тема&quot; [116-825] --&gt;
&lt;h2&gt;&lt;a name=&quot;проект&quot; id=&quot;проект&quot;&gt;Проект&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Для начала создадим проект в оболочке MPLab по шагам, описанным в &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/project&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:project&quot;&gt;документации&lt;/a&gt;. 
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;создание_проекта&quot; id=&quot;создание_проекта&quot;&gt;1. Создание проекта&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; создаем рабочую папку &amp;quot;c:\tutor\t1&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в ней создаем пустой файл &amp;quot;tutor1.c&amp;quot;; &lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; запускаем MPLab (если в ней открыт проект, то закрываем его через меню &amp;quot;File\Close Workspace&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; через меню &amp;quot;Project\Project Wizard…&amp;quot; создаем новый проект:&lt;/div&gt;
&lt;ol&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; в качестве процессора можно пока использовать любой (например, 16F887, т.к. он установлен на демоплате из набора PicKit2); &lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; выбираем инструмент (toolsuite): HI-TECH PICC Toolsuite;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; создаем файл проекта с именем tutor1.mcp в папке &amp;quot;c:\tutor\t1&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; добавляем в проект созданный нами пустой файл tutor1.c и файл системы &amp;quot;c:\osa\osa.c&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; нажимаем кнопку &amp;quot;Готово&amp;quot;.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

Проект создан, можно переходить ко второму шагу.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;конфигурирование_проекта_osacfg.h&quot; id=&quot;конфигурирование_проекта_osacfg.h&quot;&gt;2. Конфигурирование проекта (osacfg.h)&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Создаем файл конфигурации для нашего проекта, для чего воспользуемся утилитой OSAcfg_Tool.exe. После запуска программы перед нами диалоговое окно, позволяющее нам в интерактивном режиме сделать все настройки ОС для конкретного проекта. Для начала укажем программе, где проект будет располагаться, для этого кнопкой &amp;quot;Browse…&amp;quot; открываем диалоговое окно выбора файла и в нем выбираем рабочую папку &amp;quot;c:\tutor\t1&amp;quot;, где будет располагаться наш файл конфигурации. Нажимаем &amp;quot;OK&amp;quot;. Программа сообщит нам, что файл еще не существует и будет создан при сохранении. Жмем &amp;quot;OK&amp;quot;.
&lt;/p&gt;

&lt;p&gt;
Пока не будем вдаваться в подробности, касающиеся назначения различных секций в диалоговом окне, а ограничимся минимальным набором, который будет необходим нам для запуска первого проекта. Единственное, что нам нужно сделать, это установить количество задач в секции &amp;quot;System&amp;quot; равное двум (т.к. у нас будет две задачи). После этого жмем кнопку &amp;quot;Save&amp;quot; в нижней части экрана, читаем сообщение, что файл успешно сохранен, давим &amp;quot;OK&amp;quot; и выходим из программы конфигуратора по кнопке &amp;quot;Exit&amp;quot;. 
&lt;/p&gt;

&lt;p&gt;
Убеждаемся, что файл &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OSAcfg.h&lt;/a&gt;&lt;/span&gt; создан в папке &amp;quot;c:\tutor\t1&amp;quot;. Для интереса можете заглянуть в его содержимое. Там будет только одна значащая строчка (помимо сопровождающих комментариев):

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#define OS_TASKS          2&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;

Эта строчка скажет компилятору при сборке, что нужно зарезервировать память под два дескриптора задач. Сейчас для нас это главное.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;include_osa.h&quot; id=&quot;include_osa.h&quot;&gt;3. #include &amp;lt;osa.h&amp;gt;&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Включаем в tutor1.c используемые заголовочные файлы: pic.h и osa.h.
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;pic.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;указание_путей&quot; id=&quot;указание_путей&quot;&gt;4. Указание путей&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Через меню MPLab &amp;quot;Project\Build options…\Project&amp;quot; открываем параметры проекта и во вкладке &amp;quot;Directories&amp;quot; добавляем два пути в &amp;quot;Include Search Path&amp;quot;:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;c:\osa&amp;quot; - путь к файлам операционной системы;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;c:\tutor\t1&amp;quot; - путь к файлам проекта.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;функция_main&quot; id=&quot;функция_main&quot;&gt;5. Функция main()&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

В функцию main() добавляем вызов двух обязательных системных сервисов: &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt;() и &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;().

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;pic.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Как уже было описано во &amp;quot;Введении&amp;quot;, &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt;() инициализирует все внутренние переменные системы, обнуляет список дескрипторов задач. &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;() организует вечный цикл, в котором просматривает список задач на предмет готовности, и когда обнаруживает готовую задачу, передает ей управление.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Проект&quot; [826-6223] --&gt;
&lt;h2&gt;&lt;a name=&quot;описание_задач&quot; id=&quot;описание_задач&quot;&gt;Описание задач&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Как уже было сказано, задача в OSA - это обычная функция Си, которая содержит внутри себя вечный цикл, внутри которого вызывается хотя бы один сервис ОС, переключающий контекст. Для нашего примера мы воспользуемся самым простым сервисом переключения контекста - &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;(), который просто передает управление обратно планировщику, оставляя задачу в состоянии готовности. Для наглядности мы нагрузим каждую задачу какой-нибудь простой операцией. В большинстве случаев в качестве такой операции приводят увеличение какой-нибудь переменной на 1. Мы не будем мудрить и воспользуемся общим подходом: для каждой задачи будет заведена своя переменная-счетчик, значение которой мы и будем отслеживать в процессе отладки программы. Итак, у нас будут две одинаковые задачи следующего вида:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cCounter1;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cCounter2;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    m_cCounter1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Передача управления операционной системе&lt;/span&gt;
        m_cCounter1++;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    m_cCounter2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Передача управления операционной системе&lt;/span&gt;
        m_cCounter2++;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Как видно, обе функции: Task_T1 и Task_T2 - соответствуют требованиям, предъявляемым к функциям-задачам, а именно:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; они содержат в себе вечный цикл;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; внутри вечного цикла есть вызов сервиса, переключающего контекст.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Все, что нам осталось сделать, - это дописать в функцию main() вызовы сервисов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_task_create&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_task_create&quot;&gt;OS_Task_Create&lt;/a&gt;&lt;/span&gt;, которые сообщат операционной системе, что функции Task_T1 и Task_T2 являются задачами ОС. Эти сервисы должны вызываться после &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt; (т.к. сам &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt;, помимо всего прочего, обнуляет список задач) и перед &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt; (т.к., как уже писалось ранее, этот сервис содержит вечный цикл, и код, стоящий после вызова этого сервиса выполнен не будет).
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Первым параметром в сервисе &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_task_create&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_task_create&quot;&gt;OS_Task_Create&lt;/a&gt;&lt;/span&gt; указывается приоритет создаваемой задачи от 0 (высший) до 7 (низший). Сейчас задачам установлен одинаковый приоритет (позже будет объяснено, почему).
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Описание задач&quot; [6224-9975] --&gt;
&lt;h2&gt;&lt;a name=&quot;полный_текст&quot; id=&quot;полный_текст&quot;&gt;Полный текст&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Итак, полный текст нашей программы теперь будет выглядеть так:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Глобальные переменные&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cCounter1;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cCounter2;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Функции-задачи&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    m_cCounter1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Передача управления операционной системе&lt;/span&gt;
        m_cCounter1++;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
&amp;nbsp;
    m_cCounter2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Передача управления операционной системе&lt;/span&gt;
        m_cCounter2++;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  main&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;                  &lt;span class=&quot;co1&quot;&gt;// Инициализация переменных системы&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;; &lt;span class=&quot;co1&quot;&gt;// Добавление задач в список&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;                   &lt;span class=&quot;co1&quot;&gt;// Запуск планировщика&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  end of file&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- SECTION &quot;Полный текст&quot; [9976-11756] --&gt;
&lt;h2&gt;&lt;a name=&quot;как_работает_программа&quot; id=&quot;как_работает_программа&quot;&gt;Как работает программа&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Как будет работать наша программа? После обработки сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt; список задач пуст. Два последовательно вызванных сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_task_create&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_task_create&quot;&gt;OS_Task_Create&lt;/a&gt;&lt;/span&gt; записывают в свободные ячейки списка задачи Task_T1 и Task_2. Обе задачи после создания находятся в состояния готовности. Далее мы запускаем в работу планировщик сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;. Он будет перебирать все активные (созданные) задачи в списке задач, проверять их готовность, сравнивать приоритеты и запускать самую приоритетную из готовых. Если к выполнению готовы несколько задач с одинаковым приоритетом, то они будут выполняться по очереди. 
&lt;/p&gt;

&lt;p&gt;
Итак, планировщик по очереди просмотрит обе задачи. Они обе готовы и обе имеют одинаковый приоритет, поэтому планировщик передаст управление сперва той, которая была создана первой, т.е. Task_T1. Задача переводится из состояния готовности в состояние &amp;quot;в работе&amp;quot;. При первом запуске задача начинает работать с самого начала функции, в нашем случае первым выполнится присваивание переменной m_cCoutner1 значения &amp;quot;0&amp;quot;. Далее мы попадаем в вечный цикл, в котором первым шагом производится передача управления планировщику сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;. Т.е. &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;() является своего рода эквивалентом return&amp;#039;а (но это не одно и то же). При выполнении сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;() мы покинем функцию-задачу Task_T1 и вернемся в планировщик, задача при это переводится из состояния &amp;quot;в работе&amp;quot; в состояние &amp;quot;готовности&amp;quot; (при этом во внутреннюю переменную системы будет сохранен адрес выхода из задачи, и при следующем входе в нее выполнение продолжится с того места, откуда она была покинута, т.е. со следующей за &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt; строки).
&lt;/p&gt;

&lt;p&gt;
Далее в работе опять планировщик. Он снова проверяет задачи на готовность и сравнивает приоритеты. Т.к. обе задачи опять являются готовыми и приоритеты у них равны, то он берет следующую по очереди задачу, т.е. Task_T2. Теперь Task_T2 переводится из состояния &amp;quot;готовности&amp;quot; в состояние &amp;quot;в работе&amp;quot;, и с ней повторяется все то, что происходило с Task_T1. После обнуления счетчика m_cCounter2 и вызова сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt; управление опять получит планировщик, сохранив при этом адрес возврата в задачу и переведя ее из состояния &amp;quot;в работе&amp;quot; в состояние &amp;quot;готовности&amp;quot;. 
&lt;/p&gt;

&lt;p&gt;
Следующей планировщик запустит задачу Task_T1. Но теперь уже она будет выполняться не с начала, а с того места, откуда мы ее покинули, т.е. со следующей строчки после &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;. Поэтому мы сразу попадаем на увеличение счетчика m_cCounter1. После увеличения счетчика программа переходит на начало цикла. Т.е. вновь выполняется &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;, который передает управление планировщику, сохраняя адрес возврата и переводя задачу в состояние &amp;quot;готовности&amp;quot;. 
&lt;/p&gt;

&lt;p&gt;
Далее все то же самое повторяется с задачей Task_T2. Задачи будут выполняться по очереди в течение всего времени работы программы, увеличивая каждая свой счетчик. Графически это можно изобразить так:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t1_switch.png?id=osa%3Atutorial%3Atutor1&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t1_switch.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t1_switch.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Заметим важную деталь: в данном примере на работу планировщика затрачивается больше времени, чем на работу задач. Это не удивительно, ведь планировщик проверяет все задачи в списке, смотрит, какая из них в каком состоянии, выполняет сравнение приоритетов, вычисляет, какую задачу запустить. А сами задачи делают всего одну команду - увеличение счетчика. Потому и получается так, что большую часть времени контроллер тратит на работу планировщика. 
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Как работает программа&quot; [11757-17951] --&gt;
&lt;h2&gt;&lt;a name=&quot;запуск_в_симуляторе&quot; id=&quot;запуск_в_симуляторе&quot;&gt;Запуск в симуляторе&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Здесь мы проведем несколько экспериментов для исследования работы сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;. Сперва просто прогоним программу в симуляторе и убедимся, что она работает именно так, как было описано выше. 
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Запуск в симуляторе&quot; [17952-18389] --&gt;
&lt;h3&gt;&lt;a name=&quot;работа_программы&quot; id=&quot;работа_программы&quot;&gt;Работа программы&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Включим симулятор через меню &amp;quot;Debugger\Select Tool\MPLAB SIM&amp;quot;. Соберем проект по Ctrl+F10. Установим точки останова так, как показано на рисунке ниже:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t1_breakpoints.png?id=osa%3Atutorial%3Atutor1&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t1_breakpoints.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t1_breakpoints.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Теперь, нажимая кнопку F9 (Run), проследим за тем, в какой последовательности будут получать управление задачи. Первым делом мы попадаем на начало Task_T1, как раз ту строчку, где производится обнуление переменной m_cCounter1. 
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Далее можно попробовать пройти по шагам (F8), но, как было описано во &amp;quot;Введении&amp;quot;, это может привести к непредсказуемому поведению симулятора. Тем не менее, если симулятор где-то и &amp;quot;застрянет&amp;quot;, у нас всегда есть возможность нажать F9, чтобы он автоматически дошел до ближайшей точки останова. 

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
Итак, мы находимся на первой точке останова в задаче Task_T1. Если мы сейчас нажмем F9, то произойдет следующее:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; программа войдет в цикл for(;;) и дойдет до вызова сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;();&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; При выполнении &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;() произойдет выход из задачи Task_T1 (с сохранением точки выхода) и передача управления планировщику;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; планировщик решит, что следующей задачей нужно запустить Task_T2, и передаст ей управление (в самое начало функции Task_T2);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в самом начале Taks_T2 у нас стоит точка останова, где симулятор и остановится, ожидая дальнейших указаний.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
Другими словами, если сейчас нажмем F9, то выйдем из задачи Task_T1 и войдем в Task_T2. Нажимаем F9 и убеждаемся, что так оно и произошло. 
&lt;/p&gt;

&lt;p&gt;
При следующем нажатии F9 произойдет все то же самое, что и в предыдущем абзаце, с той только разницей, что планировщик передаст управление задаче Task_T1 и не в начало, а на следующую за &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;() строчку. Нажимаем F9 и видим, что мы вновь находимся в задаче Task_T1, причем уже на второй точке останова, где производится увеличение счетчика Task_T1.
&lt;/p&gt;

&lt;p&gt;
При дальнейших нажатиях F9 мы увидим, что программа переключается между двумя задачами, каждая из которых увеличивает свой счетчик (значение счетчиков можно наблюдать в окне Watch). Также можем обратить внимание на то, что ни одна из задач больше не начинается сначала, т.е. они обе крутятся в вечном цикле. При этом значения счетчиков растут строго синхронно, т.к. задачи запускаются по очереди, а увеличение счетчика производится при каждом запуске задачи.
&lt;/p&gt;

&lt;p&gt;
Так мы написали простейшую программу с использованием RTOS OSA. Теперь, когда мы разобрались с тем, как передается управление, можно немного поэкспериментировать.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Работа программы&quot; [18390-22664] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_1&quot; id=&quot;эксперимент_1&quot;&gt;Эксперимент 1&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Попробуем добавить в задачу Task_T2 еще один дополнительный вызов сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;():

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    m_cCounter2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        m_cCounter2++;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Пересоберем программу (Ctrl+F10). Теперь, нажимая F9 и наблюдая при этом за поведением счетчиков m_cCounter1 и m_cCounter2, мы увидим, что счетчик во второй задаче растет в два раза медленнее, чем в первой. Почему так происходит? 
&lt;/p&gt;

&lt;p&gt;
Дело в том, что хоть при равных приоритетах готовые задачи запускаются по очереди, но задача Task_T2 переключает контекст в двух местах. Т.е. задача Task_T1, отработав первый раз (после обнуления счетчика), передает управление Task_T2 (на самом деле, конечно, она передает управление планировщику, а уже планировщик передает его задаче Task_T2, но для краткости будем считать, что это Task_T1 передает управление Task_T2). Task_T2, обнулив счетчик, так же по &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;() передает управление Task_T1, которая продолжается с того места, откуда была покинута, т.е. попадаем на строчку m_cCounter1++. После этого Task_T1 снова передает управление задаче Task_T2. А задача Task_T2 продолжается с того места, откуда была покинута, т.е. со следующей за первым &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt; строки, т.е. со второго &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;. Таким образом, не добравшись еще до увеличения счетчика m_cCounter2, задача Task_T2 снова передает управление задаче Taks_T1, которая снова увеличивает счетчик. И только после третьего получения управления задача Task_T2 доберется до увеличения своего счетчика. 
&lt;/p&gt;

&lt;p&gt;
Схематически поведение программы можно изобразить так (для простоты не показан планировщик):
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t1_exp1.png?id=osa%3Atutorial%3Atutor1&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t1_exp1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t1_exp1.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Как видно, из-за одного добавленного вызова сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt; в задаче Task_T2 увеличение счетчика происходит в два раза медленнее.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 1&quot; [22665-25789] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_2&quot; id=&quot;эксперимент_2&quot;&gt;Эксперимент 2&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Следующим экспериментом мы проверим требование N2 к функции-задаче: внутри бесконечного цикла должен быть хотя бы один вызов сервиса, переключающего контекст (передающего управление планировщику). Теперь мы из задачи Task_T2 вообще удалим все сервисы &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;, оставив только операцию увеличения счетчика.

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    m_cCounter2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        m_cCounter2++;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Пересоберем проект (Ctrl+F10). Теперь посмотрим, что будет, если мы начнем выполнять программу. После первого нажатия F9, мы, как обычно, попадаем на начало задачи Task_T1. После обнуления счетчика управление передается задаче Task_T2. Задача Task_T2 обнуляет счетчик и попадает в вечный цикл, в котором будет увеличиваться счетчик m_cCounter2. Вот тут-то мы и прочувствуем, отчего есть требование к задачам иметь в себе хотя бы один вызов, переключающий контекст. Дело в том, что после попадания в задачу Task_T2 мы из нее уже никогда не выберемся, а будем вечно крутиться в цикле. В планировщик мы никогда не вернемся, следовательно, никакие другие задачи управление получить уже не смогут.
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Первое требование к функциям-задачам (должна содержать внутри себя вечный цикл) мы не проверяем по той причине, что при отсутствии вечного цикла мы обязательно дойдем до конца функции, выход из которой будет совершен по команде return, в результате чего произойдет порча стека.

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 2&quot; [25790-28255] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_3&quot; id=&quot;эксперимент_3&quot;&gt;Эксперимент 3&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Теперь проделаем такой опыт: изменим приоритет одной из задач. Пусть задача Task_T2 теперь будет с более низким приоритетом, чем Task_T1. Для этого заменим аргумент в вызове сервиса создания задачи (чем значение больше, тем приоритет ниже):

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;, Task_T2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Пересоберем проект (Ctrl+F10). Теперь, нажимая F9, мы увидим, что задача Task_T2 вообще не получает управления, а программа постоянно выполняет задачу Task_T1. Разберемся, почему это произошло. Обе задачи при начале работы планировщика являются готовыми к выполнению. Управление получит та, приоритет которой выше (или они будут получать управление по очереди, если их приоритеты равны). Очевидно, что управление получит задача Task_T1. Нажимаем F9 и убеждаемся, что так оно и есть. Рассмотрим, что произойдет, если мы нажмем F9 еще раз. После обнуления счетчика m_cCounter1 мы доходим до вызова сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;, который передает управление планировщику, &lt;strong&gt;оставляя задачу в состоянии готовности&lt;/strong&gt;. Далее планировщик пробегается по списку задач, находит все готовые (это опять будут задачи Task_T1 и Task_T2), а потом выбирает из них самую высокоприоритетную, и ей снова окажется задача Task_T1. И так будет при каждом входе в планировщик, т.е. каждый раз самой приоритетной из готовых будет оказываться задача Task_T1, поэтому задача Task_T2 управление никогда не получит.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 3&quot; [28256-30677] --&gt;
&lt;h2&gt;&lt;a name=&quot;заключение&quot; id=&quot;заключение&quot;&gt;Заключение&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

В данном уроке мы рассмотрели работу простейшей программы, написанной с использованием RTOS OSA, просмотрели в симуляторе порядок работы программы и порядок смены задач. В &amp;quot;Эксперименте 2&amp;quot; мы убедились в необходимости соблюдать требования к функциям-задачам, а именно наличие в них вызова сервисов, переключающих контекст. Кроме того, мы исследовали работу сервиса безусловного переключения контекста &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt; и узнали его свойства:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; он передает управление планировщику, оставляя задачу готовой к выполнению;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; при передаче управления планировщику он сперва сохраняет адрес возврата в задачу.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Заключение&quot; [30678-] --&gt;</description>
    </item>
    <item rdf:about="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor2?rev=1332239027">
        <dc:format>text/html</dc:format>
        <dc:date>2012-03-20T14:23:47+03:00</dc:date>
        <title>OSA : Учебник. Урок 2 - Локальные переменные</title>
        <link>http://wiki.pic24.ru/doku.php/osa/tutorial/tutor2?rev=1332239027</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;osa_учебник._урок_2_-_локальные_переменные&quot; id=&quot;osa_учебник._урок_2_-_локальные_переменные&quot;&gt;OSA : Учебник. Урок 2 - Локальные переменные&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/intro&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:intro&quot;&gt;К оглавлению&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;OSA : Учебник. Урок 2 - Локальные переменные&quot; [1-147] --&gt;
&lt;h2&gt;&lt;a name=&quot;тема&quot; id=&quot;тема&quot;&gt;Тема&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Разбирая этот урок, мы убедимся в том, что переменные внутри функций-задач нужно объявлять как static. На простом примере будет показано, к чему может привести пренебрежение этим правилом.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Тема&quot; [148-509] --&gt;
&lt;h2&gt;&lt;a name=&quot;проект&quot; id=&quot;проект&quot;&gt;Проект&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Создадим проект, следуя инструкциям, описанным в &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/tutor1&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:tutor1&quot;&gt;первом уроке&lt;/a&gt;, только создадим его в папке &amp;quot;c:\tutor\t2&amp;quot; и назовем файл &amp;quot;tutor2.c&amp;quot;.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Проект&quot; [510-779] --&gt;
&lt;h2&gt;&lt;a name=&quot;описание_задач&quot; id=&quot;описание_задач&quot;&gt;Описание задач&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Текст нашей второй программы будет очень похож на текст первой: те же две задачи, то же переключение с помощью сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;(). 
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cTest1;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cTest2;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; cTemp1;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        cTemp1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Значение этой переменной будет потеряно&lt;/span&gt;
                                 &lt;span class=&quot;co1&quot;&gt;// после передачи управления системе.&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        m_cTest1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; cTemp1;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; cTemp2;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        cTemp2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Значение этой переменной будет потеряно&lt;/span&gt;
                                 &lt;span class=&quot;co1&quot;&gt;// после передачи управления системе.&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        m_cTest2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; cTemp2;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Переменные m_cTest1 и m_cTest2 сделаны глобальными для того, чтобы их было удобнее отслеживать при отладке в симуляторе. В каждой задаче объявлено по одной локальной переменной. Цель данного урока - продемонстрировать, что значения локальных переменных могут быть потеряны (затерты) после передачи управления ядру операционной системы.
&lt;/p&gt;

&lt;p&gt;
Допишем к программе функцию main(), которая:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; вызовет сервис инициализации ОС;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; объявит системе, что Task_T1 и Task_T2 являются функциями-задачами;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; запустит планировщик на выполнение.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Описание задач&quot; [780-2864] --&gt;
&lt;h2&gt;&lt;a name=&quot;полный_текст&quot; id=&quot;полный_текст&quot;&gt;Полный текст&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Итак, полный текст нашей программы теперь будет выглядеть так:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Глобальные переменные&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cTest1;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cTest2;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Функции-задачи&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; cTemp1;
    m_cTest1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        cTemp1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Значение этой переменной будет потеряно&lt;/span&gt;
                                 &lt;span class=&quot;co1&quot;&gt;// после передачи управления системе.&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        m_cTest1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; cTemp1;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; cTemp2;
    m_cTest2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        cTemp2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Значение этой переменной будет потеряно&lt;/span&gt;
                                 &lt;span class=&quot;co1&quot;&gt;// после передачи управления системе.&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        m_cTest2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; cTemp2;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  main&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;                  &lt;span class=&quot;co1&quot;&gt;// Инициализация переменных системы&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;; &lt;span class=&quot;co1&quot;&gt;// Добавление задач в список&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;                   &lt;span class=&quot;co1&quot;&gt;// Запуск планировщика&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  end of file&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;&lt;/pre&gt;&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Полный текст&quot; [2865-4918] --&gt;
&lt;h2&gt;&lt;a name=&quot;как_работает_программа&quot; id=&quot;как_работает_программа&quot;&gt;Как работает программа&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Порядок переключения между задачами идентичен порядку, описанному в первом уроке. Разница только в содержимом функций-задач: если в первом уроке мы при каждом запуске задачи увеличивали переменную-счетчик, то теперь мы некоей тестовой переменной (m_cTest1 или m_cTest2) присваиваем значение локальной переменной (cTemp1 или cTemp2, соответственно). 
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Как работает программа&quot; [4919-5599] --&gt;
&lt;h2&gt;&lt;a name=&quot;запуск_в_симуляторе&quot; id=&quot;запуск_в_симуляторе&quot;&gt;Запуск в симуляторе&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Запуск в симуляторе&quot; [5600-5649] --&gt;
&lt;h3&gt;&lt;a name=&quot;работа_программы&quot; id=&quot;работа_программы&quot;&gt;Работа программы&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Включим симулятор через меню &amp;quot;Debugger\Select Tool\MPLAB SIM&amp;quot;. Соберем проект по Ctrl+F10. Для наблюдения за состоянием переменных откроем два окна: Watch и Local (оба окна открываются через меню &amp;quot;View&amp;quot;). В окно Watch добавляем две глобальные переменные m_cTest1 и m_cTest2. Установим точки останова так, как показано на рисунке ниже:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t2_breakpoints.png?id=osa%3Atutorial%3Atutor2&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t2_breakpoints.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t2_breakpoints.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Теперь нажимаем F9 (Run) и попадаем на первую точку останова в задаче Task_T1, где локальной переменной cTemp1 присваивается значение &amp;quot;1&amp;quot;. 
Нажимаем F8 (Step Over) и убеждаемся, что локальная переменная cTemp1 приняла значение &amp;quot;1&amp;quot; (ее значение будет отображаться в окне Local). 
&lt;/p&gt;

&lt;p&gt;
Итак, в данный момент курсор симулятора установлен на строке, содержащей вызов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;() из задачи Task_T1. Следующей строкой у нас присваивание m_cTest1 = cTemp1, а сама переменная cTemp1 у нас имеет значение &amp;quot;1&amp;quot;. Мы подошли к главному моменту урока. Как было описано в параграфе &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/intro#особенности_отладки&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:intro&quot;&gt;&amp;quot;Введение. Особенности отладки.&amp;quot;&lt;/a&gt;, сервисы, переключающие контекст нужно выполнять командой Run (F9), предварительно установив точку останова на следующей за сервисом строке. У нас точка останова уже стоит, так что смело давим F9 (Run). 
&lt;/p&gt;

&lt;p&gt;
Сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;() выполнился, и курсор симулятора теперь стоит на строке присваивания m_cTest1 = cTemp1. Но Обратим внимание на самый важный момент: &lt;strong&gt;значение переменной cTemp1 изменилось и стало равно &amp;quot;2&amp;quot;&lt;/strong&gt;.
&lt;/p&gt;

&lt;p&gt;
Разберемся, что с ней произошло. Для начала разберемся с тем, где размещаются локальные переменные.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Работа программы&quot; [5650-8297] --&gt;
&lt;h3&gt;&lt;a name=&quot;локальные_переменные_в_mcc18_и_mcc30&quot; id=&quot;локальные_переменные_в_mcc18_и_mcc30&quot;&gt;Локальные переменные в MCC18 и MCC30&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

В этих двух компиляторах локальные переменные создаются в стеке, причем в MCC18 стек эмулируется программно с помощью указателей FSR1 и FSR2, а в MCC30 используется общий стек, он адресуется регистрами WREG14 и WREG15. 
&lt;/p&gt;

&lt;p&gt;
Рассмотрим, как выделяется память под локальные переменные в этих компиляторах. На этапе компиляции производится подсчет, какой объем памяти требуется под локальные переменные для каждой функции. В начало каждой функции, содержащей локальные переменные, компилятором автоматически вставляется код, который увеличивает указатель стека на значение, соответствующее объему локальных переменных функции. Например, если в функции используются 3 локальных переменных типа unsigned int, то указатель стека будет увеличен на 6. 
&lt;/p&gt;

&lt;p&gt;
Рассмотрим рисунок:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t2_stack_mcc.png?id=osa%3Atutorial%3Atutor2&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t2_stack_mcc.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t2_stack_mcc.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
На рисунке приведен порядок изменения указателей стека для MCC18 и MCC30. Теперь обращение к локальным переменным внутри функции будет производиться через указатель фрейма FSR2 для MCC18 или WREG14 для MCC30. Если из функции func() будет вызвана другая функция func2(), локальные переменные которой занимают 4 байта, то стек будет выглядеть так:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t2_stack2_mcc.png?id=osa%3Atutorial%3Atutor2&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t2_stack2_mcc.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t2_stack2_mcc.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Как видно, локальные переменные функций не пересекаются, когда одна вызывает другую. Более того, при такой организации возможна рекурсия.
&lt;/p&gt;

&lt;p&gt;
Теперь важный момент: если одна функция по очереди вызывает две другие, то при попадании в каждую из них значение регистров указателей стека будет одинаковым. Т.е. если бы функция func1() после вызова func2() вызывала бы еще некую func3():
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; func1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    ...
    &lt;span class=&quot;me1&quot;&gt;func2&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    ...
    &lt;span class=&quot;me1&quot;&gt;func3&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    ...
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
, то для локальных переменных func3() использовалась бы область памяти, начинающаяся с указателя FSR&lt;sub&gt;2&lt;/sub&gt;, т.е. та же самая область, которая была занята под локальные переменные функции func2().
&lt;/p&gt;

&lt;p&gt;
Функция func1 по очереди вызывает func2 и func3. При входе в func2 происходит следующее:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;FSR2 → [FSR1++]&lt;/span&gt; - сохранение текущего значения FSR2&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;FSR2 = FSR1&lt;/span&gt; - FSR2 становится указателем фрейма локальных переменных&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;FSR1 += x&lt;/span&gt; - указаетль стека увеличивается на количество байт, занимаемых под локальные переменные функции func2.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

После того, как функция func2() отработает, перед выполнением return производятся следующие опреации:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;FSR1 -= x&lt;/span&gt; - восстанавливаем прежнее знанчение укаателя стека&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;FSR2 = [–FSR1]&lt;/span&gt; - восстанавливаем указатель фрейма&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

Таким образом, к моменту вызова func3 значения регистров FSR1 и FSR2 те же, что и перед вызовом func2. Очевидно, что при входе в функцию func3 под ее локальные переменные будут заняты те же ячейки памяти, что были заняты и под func2().
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Локальные переменные в MCC18 и MCC30&quot; [8298-12843] --&gt;
&lt;h3&gt;&lt;a name=&quot;локальные_переменные_в_picc_и_picc18&quot; id=&quot;локальные_переменные_в_picc_и_picc18&quot;&gt;Локальные переменные в PICC и PICC18&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Стратегия распределения памяти под локальные переменные в этих компиляторах несколько отличается от стратегий MCC. На этапе линковки строится граф вызовов, который содержит информацию о том, какие функции из каких функций вызываются и сколько каждая функция требует памяти под свои локальные переменные. Такой граф может выглядеть, например, так (в квадратных скобках указан объем памяти под локальные переменные):
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t2_graph_picc.png?id=osa%3Atutorial%3Atutor2&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t2_graph_picc.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t2_graph_picc.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Далее линкер, опираясь на эту информацию, строит все возможные цепочки вызовов от верхушки графа до концевого узла (в нашем случае их 7), и для каждой цепочки строится своя схема выделения локальных переменных. Обратим внимание на функцию func4(), которая встречается в двух цепочках, причем, количество элементов в этих цепях различное. Это также учитывается линкером при распределении памяти под локальные переменные. Рассмотрим для примера три цепочки:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Task_T1 → func1&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Task_T2 → func3 → func4&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Task_T3 → func4&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Для первой цепочки никаких коллизий нет и локальные переменные разных уровней графа вызовов будут следовать непрерывно друг за другом. А вот вторая и третья цепочки графа имеют две общие вершины: main() и func4(). 
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t2_picc_local.png?id=osa%3Atutorial%3Atutor2&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t2_picc_local.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t2_picc_local.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Не вдаваясь в подробности, сосредоточим внимание на том, что под локальные переменные функций, вызываемых из функции main(), выделяется одна и та же область памяти (она может быть разного объема, но начинается для всех с одного и того же адреса).
&lt;/p&gt;

&lt;p&gt;
&lt;em&gt;&lt;strong&gt;Примечание.&lt;/strong&gt; Из-за такой стратегии размещения локальных переменных PICC и PICC18 не позволяют делать рекурсивные вызовы.&lt;/em&gt;
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Локальные переменные в PICC и PICC18&quot; [12844-15712] --&gt;
&lt;h3&gt;&lt;a name=&quot;section&quot; id=&quot;section&quot;&gt;.&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Вернемся к нашему примеру. В ОСРВ OSA все функции задачи вызываются (хоть и не напрямую) планировщиком &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;, который расположен в функции main(). Следовательно, вне зависимости от стратегии выделения памяти под локальные переменные, получается так, что локальные переменные всех функций-задач будут начинаться по одному и тому же адресу. Для MCC при вызове из main() мы в любую задачу попадаем с одними и теми же значениями регистров-указателей стека; для PICC линкер, построив граф вызовов, разместит все задачи на одном уровне после main(). 
&lt;/p&gt;

&lt;p&gt;
Итак, что же происходит с переменной cTemp1 при выполнении &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;()? Сперва производится возврат в планировщик, который, в свою очередь, принимает решение, что нужно запускать задачу Task_T2. Получив управление Task_T2 своей локальной переменной cTemp2, &lt;strong&gt;которая оказывается расположенной в той же области памяти (в той же ячейке), что и локальная переменная cTemp1 из задачи Task_T1&lt;/strong&gt;, присваивает значение &amp;quot;2&amp;quot;. Т.к. cTemp1 и cTemp2 имеют один и тот же адрес, то при записи в любую из этих переменных произойдет запись и во вторую. Далее Task_T2 вызывает сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;, который возвращает управление планировщику, а планировщик передает управление задаче Task_T1 на строчку, следующую за вызовом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;(), т.е. на присваивание m_cTest1 = cTemp1. При этом, как мы уже поняли, значение переменной cTemp1 изменилось задачей Task_T2.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;.&quot; [15713-18246] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_1&quot; id=&quot;эксперимент_1&quot;&gt;Эксперимент 1&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Перепишем задачу Task_T1 так:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_cTemp1;
    m_cTest1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        s_cTemp1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        m_cTest1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; s_cTemp1;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Установим брейкпоинты на тех же местах и попробуем выполнить программу в симуляторе. Дойдя до строки присваивания m_cTest1 = s_cTemp1, мы можем убедиться, что значение переменной s_cTemp1 осталось неизменным после того, как отработала задача Task_T2. Все дело в квалификаторе &lt;span class=&quot;important&quot;&gt;static&lt;/span&gt;, стоящим перед объявлением локальной переменной. Этот квалификатор говорит компилятору, что переменная должна сохранять свое значение после выхода из функции до следующего в нее входа. Эта переменная не будет размещаться в стеке (для MCC) или в области локальных переменных (для PICC), она будет помещена в отдельную область, где за ней на все время выполнения программы закрепится одна ячейка памяти.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 1&quot; [18247-19741] --&gt;
&lt;h2&gt;&lt;a name=&quot;заключение&quot; id=&quot;заключение&quot;&gt;Заключение&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

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

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; i;       &lt;span class=&quot;co1&quot;&gt;// Ошибка здесь. Эта переменная должна быть объявлена&lt;/span&gt;
                  &lt;span class=&quot;co1&quot;&gt;// как static&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        i &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;20&lt;/span&gt;;
        &lt;span class=&quot;kw1&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;sy2&quot;&gt;--&lt;/span&gt;i&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        ...
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Мы можем подвиснуть в этом цикле навсегда, а можем выйти из него на первом же шаге, в зависимости от того, как область памяти, занимаемая авто-переменной i, используется другими задачами.
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteimportant&quot;&gt;
Компилятор не предполагает одновременной работы нескольких функций, расположенных на одном уровне в графе вызовов, поэтому, управляя операционной системой как надстройкой над компилятором, программист должен сообщать ему, какие переменные не должны пересекаться в памяти программы, объявляя их с квалификатором static.

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
Не лишним будет на первых порах работы с ОСРВ все локальные переменные внутри задачи объявлять как статические.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Заключение&quot; [19742-] --&gt;</description>
    </item>
    <item rdf:about="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor3?rev=1260368187">
        <dc:format>text/html</dc:format>
        <dc:date>2009-12-09T17:16:27+03:00</dc:date>
        <title>OSA : Учебник. Урок 3 - Задержки</title>
        <link>http://wiki.pic24.ru/doku.php/osa/tutorial/tutor3?rev=1260368187</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;osa_учебник._урок_3_-_задержки&quot; id=&quot;osa_учебник._урок_3_-_задержки&quot;&gt;OSA : Учебник. Урок 3 - Задержки&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/intro&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:intro&quot;&gt;К оглавлению&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;OSA : Учебник. Урок 3 - Задержки&quot; [1-123] --&gt;
&lt;h2&gt;&lt;a name=&quot;тема&quot; id=&quot;тема&quot;&gt;Тема&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

В данном уроке мы научимся формировать задержки в задачах. Часто бывает нужно какую-либо задачу выполнять не постоянно, а с каким-то интервалом. Например, измерять температуру в помещении вовсе не обязательно каждую миллисекунду, достаточно делать это раз в минуту (или еще реже). Это позволит разгрузить контроллер, дав ему возможность больше ресурсов выделять под остальные задачи, или просто перейти в режим пониженного энергопотребления, что очень важно для батарейных устройств. 
&lt;/p&gt;

&lt;p&gt;
Для формирования задержек в задачах есть сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;(). Целью урока является исследование работы этого сервиса.
&lt;/p&gt;

&lt;p&gt;
Для работы мы уже сможем прошить программу в контроллер и посмотреть ее работу в железе. В качестве отладочной платы мы будем использовать демо-плату из набора PICKit 2 на базе котроллера PIC16F887. Подойдут и другие демо-платы, наконец, можно будет собрать собственную макетку на любом имеющемся под ругой контроллере. Хотя, можно будет ограничиться и симулятором.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Тема&quot; [124-1941] --&gt;
&lt;h2&gt;&lt;a name=&quot;теория&quot; id=&quot;теория&quot;&gt;Теория&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Теория&quot; [1942-1967] --&gt;
&lt;h3&gt;&lt;a name=&quot;os_delay&quot; id=&quot;os_delay&quot;&gt;OS_Delay()&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; по своей функциональности немного похож на сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt; с той только разницей, что при &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt; задача передает управление планировщику, оставаясь готовой к выполнению, и будет запущена при первой же возможности (т.е. как только станет самой приоритетной из всех готовых), а &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; передает управление планировщику, переведя задачу в состояние ожидания на некоторое время, и только по истечении этого времени ставит ее в состояние готовности, позволяя получить управление. При вызова этого сервиса задача как бы засыпает на заданное время, а по его истечении просыпается и продолжает работать. Во время ожидания завершения задержки задача не рассматривается планировщиком (не участвует в сравнениях приоритетов, например), что ускоряет работу планировщика.
&lt;/p&gt;

&lt;p&gt;
Сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; вызывается с числовым параметром, например:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Данная запись говорит планировщику о том, что задача будет находиться в задержке в течение какого-то времени. Какого именно? В нашем примере в параметре указано число 10, но что оно значит? Очевидно, что задержка с параметром 20 продлится дольше, чем 10. Только 10 и 20 чего? Остановимся здесь подробнее. 
&lt;/p&gt;

&lt;p&gt;
Т.к. микроконтроллеры могут решать совершенно разные задачи, которые предъявляют разные требования к скорости работы самого контроллера, невозможно придумать какую-то универсальную временную единицу, от которой можно было бы отталкиваться при формировании задержек для разных проектов. Один контроллер предполагается тактировать кварцевым генератором 20 МГц, другому хватит встроенного генератора 4 МГц, третий обходится с генератором 32 КГц. Операционная система не знает, на какой частоте будут работать контроллеры с конкретной программой; частоту используемого генератора будет знать только разработчик проекта. Поэтому именно сам программист должен подсказать операционной системе ту самую временную единицу, которая будет базовой для формирования всех задержек. Назовем эту временную единицу &lt;strong&gt;системным тиком&lt;/strong&gt; - минимальный квант времени для отсчета задержек.
&lt;/p&gt;

&lt;p&gt;
Для того чтобы разобраться с тем, как объяснять операционной системе, какой длительности мы хотим получить системный тик, разберемся сначала, как работают задержки в задачах.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;OS_Delay()&quot; [1968-6185] --&gt;
&lt;h3&gt;&lt;a name=&quot;os_timer&quot; id=&quot;os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Операционная система для каждой активной задачи хранит свою переменную-счетчик и свой бит состояния этого счетчика (считает/не считает). Когда задача выполняет сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, счетчику, привязанному к этой задаче, присваивает значение, указанное в параметре этого сервиса, а бит состояния устанавливает в &amp;quot;считает&amp;quot;. После этого управление передается планировщику, и он, пока видит, что у задачи бит состояния установлен в значение &amp;quot;считает&amp;quot;, задачу не запускает на выполнение. Счетчик постепенно уменьшается, и, когда он доходит до нуля, бит состояние устанавливается в &amp;quot;не считает&amp;quot;, что служит сигналом планировщику, что задача снова готова к выполнению. 
&lt;/p&gt;

&lt;p&gt;
&lt;em&gt;&lt;strong&gt;Примечание&lt;/strong&gt;. Переменная-счетчик, применяемая для отсчета задержек в задачах, называется &lt;span class=&quot;important&quot;&gt;таймером задачи&lt;/span&gt;.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
Как быстро будет уменьшаться этот счетчик? В OSA есть сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;, при каждом вызове которого все активные счетчики (с битом состояния = &amp;quot;считает&amp;quot;) уменьшаются на 1. В нем же производится проверка на завершение счета и сброс бита состояние в &amp;quot;не считает&amp;quot;. Программист сам решает, когда и с каким периодом вызывать этот сервис. Чаще всего он вызывается в обработчике прерывания по переполеннию какого-нибудь таймера. Удобно (но вовсе не обязательно) вызывать сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; с одинаковым периодом. 
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Системный тик будет равен периоду вызова &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;().

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
Таким образом, программист сам решает, что означает параметр 10 в вызове сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;. Предположим, &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; вызывается в обработчике прерывания TMR2, которое происходит каждые 250 мкс. Тогда время системного тика будет равно 250 мкс, а &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;(10) будет длиться 10*250 мкс = 2.5 мс.
&lt;/p&gt;

&lt;p&gt;
Очевидно, что в ходе программы можно менять длительность системного тика (например, в режиме пониженного энергопотребления системный тик удобно приравнять к периоду таймера watchdog). Очевидно также, что если ни разу не вызывать сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;, то все задачи, вызвавшие сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, окажутся в состоянии вечного ожидания, т.к. счетчики, привязанные к задачам, никогда не обнулятся.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;OS_Timer&quot; [6186-10094] --&gt;
&lt;h3&gt;&lt;a name=&quot;некоторые_свойства_os_delay&quot; id=&quot;некоторые_свойства_os_delay&quot;&gt;Некоторые свойства OS_Delay&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Вызов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;(0) функционально эквивалентен &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;().&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Параметр сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; не должен превышать разрядности таймеров задач (по умолчанию = 16 бит). Подробнее про разрядность речь пойдет ниже.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Последовательный вызов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; с параметрами X и Y эквивалентен одному вызову &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; с параметром X + Y (если сумма не выходит за границы разрядности таймера).&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Ну, а теперь, рассмотрим работу &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; и &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; на конкретном примере.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Некоторые свойства OS_Delay&quot; [10095-11164] --&gt;
&lt;h2&gt;&lt;a name=&quot;проект&quot; id=&quot;проект&quot;&gt;Проект&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Напишем программу, которая будет мигать тремя светодиодами, каждым со своей частотой.
&lt;/p&gt;

&lt;p&gt;
Для начала создадим проект в оболочке MPLab по шагам, описанным в &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/description/project&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:description:project&quot;&gt;документации&lt;/a&gt;. 
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;создание_проекта&quot; id=&quot;создание_проекта&quot;&gt;1. Создание проекта&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; создаем рабочую папку &amp;quot;c:\tutor\t3&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в ней создаем пустой файл &amp;quot;tutor3.c&amp;quot;; &lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; запускаем MPLab (если в ней открыт проект, то закрываем его через меню &amp;quot;File\Close Workspace&amp;quot;);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; через меню &amp;quot;Project\Project Wizard…&amp;quot; создаем новый проект:&lt;/div&gt;
&lt;ol&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; в качестве процессора выбираем 16F887 (или тот, который вы собираетесь использовать); &lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; выбираем инструмент (toolsuite): HI-TECH PICC Toolsuite;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; создаем файл проекта с именем tutor3.mcp в папке &amp;quot;c:\tutor\t3&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; добавляем в проект созданный нами пустой файл tutor3.c и файл системы &amp;quot;c:\osa\osa.c&amp;quot;;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level2&quot;&gt;&lt;div class=&quot;li&quot;&gt; нажимаем кнопку &amp;quot;Готово&amp;quot;.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

Проект создан, можно переходить ко второму шагу.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;конфигурирование_проекта_osacfg.h&quot; id=&quot;конфигурирование_проекта_osacfg.h&quot;&gt;2. Конфигурирование проекта (osacfg.h)&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Создаем файл конфигурации для нашего проекта, для чего воспользуемся утилитой OSAcfg_Tool.exe. После запуска программы перед нами диалоговое окно, позволяющее нам в интерактивном режиме сделать все настройки ОС для конкретного проекта. Для начала укажем программе, где проект будет располагаться, для этого кнопкой &amp;quot;Browse…&amp;quot; открываем диалоговое окно выбора файла и в нем выбираем рабочую папку &amp;quot;c:\tutor\t3&amp;quot;, где будет располагаться наш файл конфигурации. Нажимаем &amp;quot;OK&amp;quot;. Программа сообщит нам, что файл еще не существует и будет создан при сохранении. Жмем &amp;quot;OK&amp;quot;.
&lt;/p&gt;

&lt;p&gt;
Теперь в секции &amp;quot;System&amp;quot; устанавливаем параметр &amp;quot;Tasks&amp;quot; = 3 (у нас будут три задачи). Теперь нам нужно сказать системе, что мы будем использовать задержки в программе. Для этого нам нужно включить таймеры задач: в секции &amp;quot;Timers&amp;quot; устанавливаем галочку напротив пункта &amp;quot;Task timers&amp;quot;.
&lt;/p&gt;

&lt;p&gt;
После этого жмем кнопку &amp;quot;Save&amp;quot; в нижней части экрана, читаем сообщение, что файл успешно сохранен, давим &amp;quot;OK&amp;quot; и выходим из программы конфигуратора по кнопке &amp;quot;Exit&amp;quot;. 
&lt;/p&gt;

&lt;p&gt;
Убеждаемся, что файл &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OSAcfg.h&lt;/a&gt;&lt;/span&gt; создан в папке &amp;quot;c:\tutor\t3&amp;quot;.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;include_osa.h&quot; id=&quot;include_osa.h&quot;&gt;3. #include &amp;lt;osa.h&amp;gt;&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Включаем в tutor3.c используемые заголовочные файлы: pic.h и osa.h.
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;pic.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;указание_путей&quot; id=&quot;указание_путей&quot;&gt;4. Указание путей&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Через меню MPLab &amp;quot;Project\Build options…\Project&amp;quot; открываем параметры проекта и во вкладке &amp;quot;Directories&amp;quot; добавляем два пути в &amp;quot;Include Search Path&amp;quot;:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;c:\osa&amp;quot; - путь к файлам операционной системы;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &amp;quot;c:\tutor\t3&amp;quot; - путь к файлам проекта.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;функция_main&quot; id=&quot;функция_main&quot;&gt;5. Функция main()&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

В функцию main() добавляем вызов двух обязательных системных сервисов: &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_init&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_init&quot;&gt;OS_Init&lt;/a&gt;&lt;/span&gt;() и &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_run&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_run&quot;&gt;OS_Run&lt;/a&gt;&lt;/span&gt;().

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;pic.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Теперь, когда заготовка для проекта готова, можно приступать к написанию программы.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Проект&quot; [11165-15635] --&gt;
&lt;h2&gt;&lt;a name=&quot;программа&quot; id=&quot;программа&quot;&gt;Программа&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Логически программа разделена на четыре части: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; определения - здесь будут определены константы, включены заголовочные файлы, задана конфигурация контроллера;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; задачи - каждая задача будет управлять своим светодиодом;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; инициализация - здесь будет инициализирована периферия контроллера и операционная система;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; прерывание - в нем мы будем вызывать сервис управления задержками &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Программа&quot; [15636-16420] --&gt;
&lt;h3&gt;&lt;a name=&quot;определения&quot; id=&quot;определения&quot;&gt;Определения&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Итак, начнем с определений. Что нам нужно? 
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; включить заголовочные файлы: pic.h и osa.h; &lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; задать биты конфигурации контроллера; &lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; определить выводы контроллера, к которым подключены светодиоды.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;pic.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;// Задаем биты конфигурации:&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - внутренний RC-генератор&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем WDT&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем низковольтное программирование&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем функцию отладки&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
__CONFIG&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;INTIO &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; WDTDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; PWRTEN &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; MCLRDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; LVPDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; UNPROTECT &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; BORDIS
               &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; IESODIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; FCMDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; DEBUGDIS&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Определяем выводы для светодиодов&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED1    RD0&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED2    RD2&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED3    RD4&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Параметры таймера:&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - прескейлер = 4,&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - постскейлер = 1,&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - предел счета = 250&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Тактовая частота контроллера = 4 МГц.&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Период возникновения прерывания по TMR2 получается&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  равным 4 * 1 * 250 * Tcyc = 1 ms&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define PR2_CONST       250-1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define TMR2_PRS        1                           // prs = 4&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define TMR2_POST       0                           // post = 1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define T2CON_CONST     (TMR2_POST&amp;lt;&amp;lt;3) | TMR2_PRS&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- SECTION &quot;Определения&quot; [16421-18459] --&gt;
&lt;h3&gt;&lt;a name=&quot;задачи&quot; id=&quot;задачи&quot;&gt;Задачи&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Как уже было сказано, для демонстрации мы заведем по одной задаче на каждый светодиод. Внутри задачи будет содержаться вызов сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; и операция переключения светодиода. Таким образом, получится, что каждый светодиод будет переключаться с интервалом, указанным в параметре к сервису &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;. Например, задача управления первым светодиодом будет выглядеть так:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED1 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;       &lt;span class=&quot;co1&quot;&gt;// Меняем состояние первого светодиода&lt;/span&gt;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;       &lt;span class=&quot;co1&quot;&gt;// Переводим задачу в режим ожидания на&lt;/span&gt;
                             &lt;span class=&quot;co1&quot;&gt;// время, равное 500 системным тикам&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
По аналогии будут запрограммированы две другие задачи для управления светодиодами 2 и 3, но с той разницей, что параметрами сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; будут числа 1000 и 1500. 
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Задачи&quot; [18460-19908] --&gt;
&lt;h3&gt;&lt;a name=&quot;инициализация&quot; id=&quot;инициализация&quot;&gt;Инициализация&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Инициализация периферии будет вынесена для наглядности в отдельную функцию init(), которая будет вызываться из функции main(). Мы должны проинициализировать следующее:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; установить все порты ввода/вывода на выход;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; инициализировать таймер;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; инициализировать модуль прерываний.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; init &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка портов I/O&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PORTA &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTB &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTC &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTD &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    TRISA &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISB &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISC &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISD &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка таймера 2&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PR2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; PR2_CONST;
    T2CON &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; T2CON_CONST | &lt;span class=&quot;nu12&quot;&gt;0x04&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка прерываний&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PIR1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PIR2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    INTCON &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    TMR2IE &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;         &lt;span class=&quot;co1&quot;&gt;// Разрешаем прерывание по TMR2&lt;/span&gt;
    PEIE &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Разрешаем периферийные прерывания&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// Глобальные бит разрешения прерываний будет&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// установлен непосредственно перед запуском&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// планировщика в функции main()&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Остальная часть кода инициализации будет размещена в main().
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;             &lt;span class=&quot;co1&quot;&gt;// Инициализация периферии&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;          &lt;span class=&quot;co1&quot;&gt;// Инициализация системы&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Создаем задачи&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    OS_EI&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;            &lt;span class=&quot;co1&quot;&gt;// Разрешаем прерывания&lt;/span&gt;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Запускаем планировщик&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Обратим внимание на новый сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_ei&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_ei&quot;&gt;OS_EI&lt;/a&gt;&lt;/span&gt;(). Фактически он всего-навсего устанавливает бит GIE. Но мы предполагаем, что любая программа может быть перенесена на другой контроллер (например, на PIC24, где бита GIE нет), поэтому изначально будет писать программу так, чтобы по возможности свести к минимуму усилия по портированию. Сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_ei&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_ei&quot;&gt;OS_EI&lt;/a&gt;&lt;/span&gt;() для всех контроллеров описан по-своему, поэтому предпочтительнее использовать именно его, а не явное разрешение прерываний через установку бита GIE.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Инициализация&quot; [19909-23371] --&gt;
&lt;h3&gt;&lt;a name=&quot;прерывание&quot; id=&quot;прерывание&quot;&gt;Прерывание&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Как уже говорилось ранее, сервис, управляющий отсчетом задержек (фактически - управляющий таймерами задач), обычно вызывается в периодическом месте программы. Интервал вызовов этого сервиса называется системным тиком. В большинстве случаев удобно, чтобы &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; вызывался с одним и тем же интервалом времени, что обеспечит программу системным тиком фиксированной длительности. Самый удобный способ (но не единственный) - вызывать его в обработчике прерывания по таймеру. В нашей программе мы воспользуемся таймером TMR2.
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; interrupt isr &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_EnterInt&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;TMR2IF&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Timer&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        TMR2IF &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
    OS_LeaveInt&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Прерывание будет возникать 1 раз в миллисекунду, следовательно, системный тик в нашей программе также будет равен 1 мс. 
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Прерывание&quot; [23372-24767] --&gt;
&lt;h3&gt;&lt;a name=&quot;весь_текст_программы&quot; id=&quot;весь_текст_программы&quot;&gt;Весь текст программы&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Для удобства здесь приведен весь текст программы целиком:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Программа для исследования работы задержек в OSA&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;pic.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;// Задаем биты конфигурации:&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - внутренний RC-генератор&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем WDT&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем низковольтное программирование&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем функцию отладки&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
__CONFIG&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;INTIO &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; WDTDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; PWRTEN &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; MCLRDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; LVPDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; UNPROTECT &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; BORDIS
               &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; IESODIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; FCMDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; DEBUGDIS&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Определяем выводы для светодиодов&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED1    RD0&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED2    RD2&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED3    RD4&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Параметры таймера:&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - прескейлер = 4,&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - постскейлер = 1,&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - предел счета = 250&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Тактовая частота контроллера = 4 МГц.&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Период возникновения прерывания по TMR2 получается&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  равным 4 * 1 * 250 * Tcyc = 1 ms&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define PR2_CONST       250-1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define TMR2_PRS        1                           // prs = 4&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define TMR2_POST       0                           // post = 1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define T2CON_CONST     (TMR2_POST&amp;lt;&amp;lt;3) | TMR2_PRS&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Прерывание. Возникает каждую мс&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; interrupt isr &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_EnterInt&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;TMR2IF&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Timer&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        TMR2IF &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
    OS_LeaveInt&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Описание задач управления светодиодами&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED1 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;       &lt;span class=&quot;co1&quot;&gt;// Меняем состояние первого светодиода&lt;/span&gt;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;       &lt;span class=&quot;co1&quot;&gt;// Переводим задачу в режим ожидания на&lt;/span&gt;
                             &lt;span class=&quot;co1&quot;&gt;// время, равное 500 системным тикам&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED2 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;       &lt;span class=&quot;co1&quot;&gt;// Меняем состояние второго светодиода&lt;/span&gt;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;      &lt;span class=&quot;co1&quot;&gt;// Переводим задачу в режим ожидания на&lt;/span&gt;
                             &lt;span class=&quot;co1&quot;&gt;// время, равное 1000 системным тикам&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T3 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED3 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;       &lt;span class=&quot;co1&quot;&gt;// Меняем состояние третьего светодиода&lt;/span&gt;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1500&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;      &lt;span class=&quot;co1&quot;&gt;// Переводим задачу в режим ожидания на&lt;/span&gt;
                             &lt;span class=&quot;co1&quot;&gt;// время, равное 1500 системным тикам&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Инициализация периферии&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; init &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка портов I/O&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PORTA &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTB &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTC &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTD &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    TRISA &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISB &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISC &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISD &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка таймера 2&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PR2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; PR2_CONST;
    T2CON &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; T2CON_CONST | &lt;span class=&quot;nu12&quot;&gt;0x04&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка прерываний&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PIR1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PIR2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    INTCON &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    TMR2IE &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;         &lt;span class=&quot;co1&quot;&gt;// Разрешаем прерывание по TMR2&lt;/span&gt;
    PEIE &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Разрешаем периферийные прерывания&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// Глобальные бит разрешения прерываний будет&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// установлен непосредственно перед запуском&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// планировщика в функции main()&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  MAIN&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;             &lt;span class=&quot;co1&quot;&gt;// Инициализация периферии&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;          &lt;span class=&quot;co1&quot;&gt;// Инициализация системы&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Создаем задачи&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    OS_EI&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;            &lt;span class=&quot;co1&quot;&gt;// Разрешаем прерывания&lt;/span&gt;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Запускаем планировщик&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  END&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;&lt;/pre&gt;&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Весь текст программы&quot; [24768-31035] --&gt;
&lt;h2&gt;&lt;a name=&quot;как_работает_программа&quot; id=&quot;как_работает_программа&quot;&gt;Как работает программа&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

К тому моменту, как будет вызван планировщик, у нас созданы три задачи. Т.к. все они равноприоитетны и готовы к выполнению (после создания задача сразу становится готовой), то планировщик выберет для запуска ту, которая была создана первой, т.е. Task_T1. Получив управление, задача Task_T1 первым изменит состояние светодиода (светодиод был погашен, и теперь он зажжется). Далее она вызывает сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; с параметром 500. При этом происходит следующее:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; задача инициализирует свой внутренний таймер (переменную-счетчик) значением 500;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; переводит себя в состояние ожидания (т.е. она не сможет получить управление, пока не произойдет ожидаемое ей событие, а именно, - пока не обнулится ее таймер);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; передает управление планировщику. &lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

Теперь планировщик видит, что готовы к выполнению только две задачи (одна уже в режиме ожидания): Task_T2 и Task_T3. Т.к. приоритеты их равны, то она выбирает следующую по очереди (порядок очереди определяется последовательностью создания задач сервисов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_task_create&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_task_create&quot;&gt;OS_Task_Create&lt;/a&gt;&lt;/span&gt;), т.е. Task_T2. Эта задача, получив управление, выполняет те же самые операции, только ее внутренний таймер будет инициализирован значением 1000. Задача также становится в режим ожидания, а управление возвращается планировщику.
&lt;/p&gt;

&lt;p&gt;
Теперь готова к выполнению только одна задача - Task_T3, и планировщик передает ей управление. Так же как и первые две, она зажигает свой светодиод, после чего уходит в режим ожидания, инициализируя свой внутренний таймер значением 1500. После этого управление опять возвращается планировщику.
&lt;/p&gt;

&lt;p&gt;
Что у нас получилось в результате? Готовых задач нет, поэтому планировщик будет крутиться теперь сам в себе. Есть три задачи, стоящие в режиме ожидания завершения задержки, с разными значениями таймеров: 500, 1000 и 1500. Эти задачи будут оставаться в режиме ожидания, пока их таймеры не обнулятся. 
&lt;/p&gt;

&lt;p&gt;
Как уже говорилось, за таймерами задач следит сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;, который при каждом вызове уменьшает все активные таймеры на 1. Мы вызываем этот сервис в прерывании, возникающем раз в миллисекунду. Т.е. каждую миллисекунду значения таймеров будут уменьшаться на 1. Таким образом, через 500 мс таймер задачи Task_T1 будет обнулен, и она переведется в режим готовности. А так как она окажется единственной задачей, готовой к выполнению, то планировщик сразу же передаст ей управление. Значения таймеров для задач Task_T2 и Task_T3 за это время уменьшатся на 500 и станут равны 500 и 1000, соответственно. Задача Task_T1, получив управление, повторит все действия, которые были проделаны при предыдущем ее запуске: изменит состояние светодиода (теперь уже погасит его) и вызовом сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; снова уйдет в задержку, вернув управление планировщику.
&lt;/p&gt;

&lt;p&gt;
На этот момент времени готовых задач опять нет. Значения таймеров будут 500, 500 и 1000. Теперь через 500 мс (т.е. через 500 вызовов сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;) у нас одновременно обнулятся таймеры задач Task_T1 и Task_T2, и они обе перейдут в режим готовности. В данном случае трудно предсказать, какая из задач получит управление первой. Предположим, что это будет Task_T1. После того как она отработает (зажжет светодиод и уйдет в задержку), сразу же запустится задача Task_T2, т.к. она уже готова к выполнению. После отработки она также уходит в задержку, передав управление планировщику. И планировщик снова ждет, когда какая-нибудь из задач стает готовой (это произойдет через 500 мс, готовыми станут Task_T1 и Task_T3).
&lt;/p&gt;

&lt;p&gt;
Схематически работу программы можно изобразить так:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t3_switch.png?id=osa%3Atutorial%3Atutor3&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t3_switch.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t3_switch.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
(Для наглядности здесь не показан пятый график - прерывания.) Из графика хорошо видно, что есть участки, где планировщик крутится вхолостую, не выполняя никаких задач. Также видно, что задача Task_T1 получает управление в два раза чаще, чем Task_T2, и в 3 раза чаще, чем Task_T3.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Как работает программа&quot; [31036-37865] --&gt;
&lt;h3&gt;&lt;a name=&quot;примечание_по_рассинхронизации&quot; id=&quot;примечание_по_рассинхронизации&quot;&gt;Примечание по рассинхронизации&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Стоит отметить один важный момент, касающийся счета таймеров задач. Прерывание, в котором производится декремент всех активных таймеров может возникнуть в любой момент, и это может привести к рассинхронизации задач. Поясню на конкретном примере. По нашей схеме предполагается, что задача Task_T1 будет выполняться в два раза чаще, чем Task_T2. Однако есть одна тонкость. Предположим, что таймер первой задачи досчитал до 0, а таймер второй задачи - до 500. Планировщику на то, чтобы просмотреть список задач, выбрать готовую и передать ей управление, требуется некоторое время. Если длительность системного тика сравнительно мала, то за это время может успеть произойти еще одно прерывание, т.е. еще один вызов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;, который в свою очередь вычтет еще одну единицу из таймера задачи Task_T2 (таймер задачи Task_T1 и так уже нулевой, поэтому он останется без изменений). После получения управления Task_T1 обновит свой таймер, и он примет значение = 500, а таймер задачи Task_T2 будет к этому времени уже = 499. Таким образом, получается некоторая рассинхронизация. В общем случае в зависимости от количества задач, от их состояний, от периода вызова &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;, от того, как задачи забирают под себя время процессора, такая рассинхронизация может происходить чаще или реже. В нашем конкретном примере она будет очень редким явлением, но в более навороченной программе, это будет происходить чаще. Поэтому в общем случае не стоит использовать &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; для точной синхронизации задач друг с другом.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Примечание по рассинхронизации&quot; [37866-40711] --&gt;
&lt;h2&gt;&lt;a name=&quot;запуск&quot; id=&quot;запуск&quot;&gt;Запуск&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Запуск&quot; [40712-40737] --&gt;
&lt;h3&gt;&lt;a name=&quot;запуск_в_железе&quot; id=&quot;запуск_в_железе&quot;&gt;Запуск в железе&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Выполним сборку нашей программы (Ctrl+F10) и прошьем ее в контроллер. Убедимся, что светодиоды работают именно так, как описано в предыдущем параграфе, т.е. один светодиод мигает раз в секунду, другой - раз в две секунды, третий - раз в три секунды. Теперь можно переходить к параграфу &amp;quot;Эксперименты&amp;quot;, где мы попытаемся внимательнее исследовать свойства сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;. Но сначала пройдем нашу программу по шагам в симуляторе.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Запуск в железе&quot; [40738-41576] --&gt;
&lt;h3&gt;&lt;a name=&quot;запуск_в_симуляторе&quot; id=&quot;запуск_в_симуляторе&quot;&gt;Запуск в симуляторе&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Расставим брейкпоинты, как показано на рисунке:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t3_breakpoints.png?id=osa%3Atutorial%3Atutor3&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t3_breakpoints.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t3_breakpoints.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Откроем окно &amp;quot;Watch&amp;quot;, куда добавим внутренний массив дескрипторов задач &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_task_vars&quot; class=&quot;wikilink2&quot; title=&quot;osa:ref:allservices:os_task_vars&quot; rel=&quot;nofollow&quot;&gt;OS_Task_Vars&lt;/a&gt;&lt;/span&gt; (это единственный способ проследить за таймерами задач). Раскроем весь массив, как показано на рисунке, чтобы мы смогли наблюдать отдельно за таймером каждой задачи. Теперь установим параметры отображения для каждого таймера, для этого на поле Timer для каждого дескриптора жмем правую кнопку мышки и во всплывающем меню выбираем пункт &amp;quot;Properties…&amp;quot;. В открывшемся диалоговом окне задаем значение &amp;quot;Decimal&amp;quot; в поле &amp;quot;Format&amp;quot; и справа от него устанавливаем галочку в пункте &amp;quot;Signed&amp;quot;, как показано на картинке:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t3_watch_properties.png?id=osa%3Atutorial%3Atutor3&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t3_watch_properties.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t3_watch_properties.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Нам нужно именно знаковое отображение, т.к. на самом деле в переменные, содержащие таймеры задач, пишутся отрицательные значения.
&lt;/p&gt;

&lt;p&gt;
Теперь выберем симулятор для отладки через пункт меню &amp;quot;Debugger/Select Tool…/MPLAB SIM&amp;quot;. Выполним кое-какие настройки: откроем окно &amp;quot;Debugger/Settings…&amp;quot; и в поле &amp;quot;Processor frequency&amp;quot; зададим значение 4 МГц. Откроем окно &amp;quot;Debugger/Stopwatch&amp;quot; (секундомер), в котором будем засекать время выполнения различных кусков программы. Теперь можно приступать к отладке.
&lt;/p&gt;

&lt;p&gt;
Нажимаем F9 (Run). Программа начнет выполняться и остановится на первой встретившейся точке останова, предварительно выполнив все шаги инициализации и создания задач. Первой встретившейся точкой останова будет &lt;acronym title=&quot;Personal Identification Number&quot;&gt;PIN&lt;/acronym&gt;_LED1 ^= 1 в задаче Task_T1. Если мы сейчас нажмем F9 (Run), то окажемся на второй точке останова, но сможем в Watch-окне увидеть, что при выполнении &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; в первой задаче у нас изменилось значение ее таймера (поле Timer), оно стало равным -500. Нажав F9 (Run) еще раз, мы перейдем на третью точку останова (в задаче Task_T3), обнаружив, что и значение поле Timer для второй задачи теперь стало -1000.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t3_breakpoints2.png?id=osa%3Atutorial%3Atutor3&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t3_breakpoints2.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t3_breakpoints2.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Прежде чем выполнять очередную задачу, поставим еще одну точку останова внутри прерывания:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t3_breakpoints3.png?id=osa%3Atutorial%3Atutor3&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t3_breakpoints3.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t3_breakpoints3.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Теперь нажимаем F9. Поставив третью задачу в режим ожидания, программа начинает крутиться в планировщике, который раз в миллисекунду будет прерываться по переполнению таймера TMR2. При первом же переполнении программа остановится на брейкпоинте, который мы установили в прерывании. Указатель симулятора сейчас находится перед вызовом сервиса управления таймерами &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;. Обратим внимание на состояния таймеров задач в окне Watch и убедимся в том, что они имеют значения: -500, -1000, -1500. Сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; выполним командой отладчика Step Over (F8), после чего увидим, что значения всех таймеров увеличилось на 1, и они приняли значения: -499, -999, -1499. Теперь, нажимая F9 (Run) мы будет все время попадать на брейкпоинт, установленный в прерывании, т.к. задачи находятся в режиме ожидания и управление не получают. При каждом попадании в прерывание мы убеждаемся, что значения таймеров по одному шагу приближаются к нулю. Кроме того, по значениям в окне Stopwatch (секундомер) мы можем убедиться, что прерывание происходит раз в миллисекунду. 
&lt;/p&gt;

&lt;p&gt;
Так мы разобрались с тем, как в программе инициализируются таймеры и как они обновляются сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;. Чтобы не нажимать F9 (Run) 500 раз, ожидая, когда же обнулится таймер первой задачи, снимем точку останова, которую мы поставили в прерывании. 
&lt;/p&gt;

&lt;p&gt;
Теперь, нажав F9 (Run), мы запустим программу на выполнение так, что она остановится только тогда, когда хотя бы одна из задач, где установлены брейкпоинты, получит управление. Это произойдет через 500 вызовов сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; - мы снова попадем в задачу Task_T1. По окну Watch можем убедиться в том, что таймер первой задачи теперь обнулен, а по окну Stopwatch - что прошло 500 мс. 
&lt;/p&gt;

&lt;p&gt;
Нажимая F9 (Run) и следя за тем, в каком порядке задачи получают управление, мы через окно Stopwatch будем видеть, что это происходит как раз с заданными нами периодами. Т.е. задача Task_T1 будет выполняться раз в 500 мс, задача Task_T2 - раз в секунду, Task_T3 - в полторы секунды. Таким образом, мы в симуляторе по шагам проверили то, что только что видели в железе. Теперь можно поэкспериментировать.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Запуск в симуляторе&quot; [41577-48812] --&gt;
&lt;h2&gt;&lt;a name=&quot;эксперименты&quot; id=&quot;эксперименты&quot;&gt;Эксперименты&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперименты&quot; [48813-48850] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_1_-_приоритеты&quot; id=&quot;эксперимент_1_-_приоритеты&quot;&gt;Эксперимент 1 - приоритеты&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

В уроке, посвященном изучению сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;, мы сделали эксперимент с заменой приоритета одной из задач, что привело к тому, что она не смогла получить управление. Попробуем сделать то же самое в данной программе:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    &lt;span class=&quot;co1&quot;&gt;// Создаем задачи&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;, Task_T1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Приоритет повышен&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_T2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;, Task_T3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Приоритет понижен&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Выполняем сборку (Ctrl+F10) и прошиваем программу в контроллер. Светодиоды будут мигать так же, как и до изменения приоритетов: первый - раз в секунду, второй - раз в две секунды, третий - раз в три секунды. Это говорит о том, что все задачи получают управление. В чем же отличие от такой же ситуации с &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;? 
&lt;/p&gt;

&lt;p&gt;
Вспомним еще раз: &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;, передавая управление планировщику, оставляет задачу &lt;strong&gt;готовой&lt;/strong&gt; к выполнению. А планировщик передает управление &lt;strong&gt;самой приоритетной&lt;/strong&gt; из &lt;strong&gt;готовых&lt;/strong&gt;. Поэтому в случае с &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt; задача с более низким приоритетом просто не могла получить управление из-за того, что всегда была в наличии готовая задача с более высоким приоритетом. 
&lt;/p&gt;

&lt;p&gt;
В случае с &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; все не так. &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, в отличие от &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;, переводит задачу в режим ожидания. А задача, находящаяся в режиме ожидания, не рассматривается планировщиком как кандидат на запуск, поэтому менее приоритетные задачи получают шанс получить управление. Исключение составляет лишь вызов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;(0), который, как уже писалось, является функциональным эквивалентом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 1 - приоритеты&quot; [48851-51710] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_2_-_конкатенация&quot; id=&quot;эксперимент_2_-_конкатенация&quot;&gt;Эксперимент 2 - конкатенация&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Среди свойств &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; упоминалось такое: &amp;quot;Последовательный вызов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; с параметрами X и Y эквивалентен одному вызову &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; с параметром X + Y&amp;quot;. Рассмотрим его на практике. Перепишем задачу Task_T1 следующим образом:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED1 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Соберем программу (Ctrl+F10) и прошьем контроллер. Мы увидим, что светодиод 1 мигает так же и с той же частотой. Дело в том, что функционально мы ничего не изменили. После выполнения первого &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;(250) задача уйдет в ожидание на 250 системных тиков. Как только задержка закончится, задача станет готовой к выполнению, и когда получит управление, она вернется на вызов второго &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, который также переведет ее в режим ожидания на 250 системных тиков. Т.е. получается, что мы выдерживаем ту же самую задержку в 500 тиков, только другим способом. 
&lt;/p&gt;

&lt;p&gt;
На практике такое встречается редко, однако, у этого способа есть практическое применение: для меньших чисел в параметре сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; мы может использовать таймеры задач меньшей разрядности. Подробнее этого мы коснемся чуть ниже.
&lt;/p&gt;

&lt;p&gt;
Теперь перепишем задачу Task_T1 так:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        PIN_LED1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Соберем программу (Ctrl+F10) и прошьем контроллер. Работа программы также останется без изменений. Мы сделали то же самое, что и было, но только опять же другим способом. Раньше состояние светодиода менялось через каждые 500 тиков, а теперь оно явно задается так же через 500 тиков. Т.е. суммарное время горения и негорения светодиода и в том и в другом случае равно 1 секунде. Но последняя форма записи позволяет нам изменить скважность (например, для экономии заряда батарейки):
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;        PIN_LED1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        PIN_LED1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;950&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Здесь мы видим, что время горения составляет всего 50 тиков, а время негорения - 950. На глаз вспышки будут хорошо заметны, а светодиод стал потреблять в &lt;strong&gt;10 раз&lt;/strong&gt; меньше тока.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 2 - конкатенация&quot; [51711-55394] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_3_-_системный_тик&quot; id=&quot;эксперимент_3_-_системный_тик&quot;&gt;Эксперимент 3 - системный тик&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Поговорим немного о выборе системного тика для проекта. Очевидно, что для нашего случая такой частый вызов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; избыточен. Для нашей конкретной задачи подошел бы системный тик длительностью, например, в 50 мс, в 100 мс или в 500 мс. Перепишем немного нашу программу:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; изменим период генерации прерывания по TMR2 с 1 мс на 10 мс;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; сократим значения всех аргументов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; в 10 раз:&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#define TMR2_POST      9       // Постскейлер = 10&lt;/span&gt;
...
&lt;span class=&quot;co1&quot;&gt;//--------------------------------------------&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        PIN_LED1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;95&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//--------------------------------------------&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED2 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//--------------------------------------------&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_T3 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        PIN_LED3 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//--------------------------------------------&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Выполним сборку (Ctrl+F10) и прошьем контроллер. Работа устройства опять же не изменилась: светодиоды мигают с теми же частотами. Фактически мы и не меняли логику работы программы. Задержки как были 500, 1000 и 1500 мс, так и остались. Просто изменилось время системного тика. Но что мы можем выиграть, удлинив время системного тика? Обратим внимание, что после деления всех значений аргументов в вызовах сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, все они у нас стали меньше 255. А это значит, что для конкретного случая под каждый таймер задач будет достаточно одного байта, а не двух (по умолчанию таймеры двухбайтовые).
&lt;/p&gt;

&lt;p&gt;
Посмотрим на статистику, выданную компилятором при сборке:

&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;Memory Summary:
    Program space        used   18Ah (   394) of  2000h words   (  4.8%)
    Data space           used    1Eh (    30) of   170h bytes   (  8.2%)
    EEPROM space         used     0h (     0) of   100h bytes   (  0.0%)
    Configuration bits   used     1h (     1) of     2h words   ( 50.0%)
    ID Location space    used     0h (     0) of     4h bytes   (  0.0%)&lt;/pre&gt;
&lt;p&gt;
&lt;em&gt;&lt;strong&gt;Примечание&lt;/strong&gt;. Статистика может немного отличаться в зависимости от версии компилятора. Данная статистика приведена для PICC STD 9.60PL3.&lt;/em&gt;
&lt;/p&gt;

&lt;p&gt;
Как видно, у нас занято 30 байт оперативной памяти. И мы знаем, что 6 из них заняты таймерами задач во внутренних переменных операционной системы (3 таймера по 2 байта). Так же мы знаем, что в конкретной программе значения таймеров никогда не превышают по модулю значения 150 (для таймеров используется только отрицательная область значений, поэтому для однобайтового таймера допустимы значения -1..-255). Следовательно, старший байт каждого таймера висит мертвым грузом.
&lt;/p&gt;

&lt;p&gt;
Запустим программу конфигуратор OSAcfg_Tool и откроем в ней конфигурацию для проекта C:\TUTOR\T3 (теперь это можно сделать через выкидной список Path, т.к. там сохраняются все пути, которые были введены). Верхняя правая часть диалогового окна отведена для конфигурирования таймеров. У нас стоит галочка рядом с пунктом &lt;strong&gt;Enable&lt;/strong&gt; для &lt;strong&gt;Task timers&lt;/strong&gt;. А справа от этого пункта есть ComboBox, в котором можно выбрать размерность таймера задач. По умолчанию там стоит &lt;strong&gt;(system)&lt;/strong&gt;, т.е. использовать размерность системного таймера, которая задается чуть выше и по умолчанию имеет тип &lt;strong&gt;default (int)&lt;/strong&gt;. Изменим тип таймера задач на &lt;strong&gt;char&lt;/strong&gt;:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t3_osacfg_timers.png?id=osa%3Atutorial%3Atutor3&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t3_osacfg_timers.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t3_osacfg_timers.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Теперь сохраняем (кнопка &amp;quot;Save&amp;quot;) и выходим (кнопка &amp;quot;Exit&amp;quot;). В файл &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OSAcfg.h&lt;/a&gt;&lt;/span&gt; добавится строчка:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#define OS_TTIMER_SIZE    1&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Пересоберем проект (Ctrl+F10) и прошьем контроллер. Программа работает, как и раньше. А теперь заглянем в статистику компилятора:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;Memory Summary:
    Program space        used   173h (   371) of  2000h words   (  4.5%)
    Data space           used    1Bh (    27) of   170h bytes   (  7.3%)
    EEPROM space         used     0h (     0) of   100h bytes   (  0.0%)
    Configuration bits   used     1h (     1) of     2h words   ( 50.0%)
    ID Location space    used     0h (     0) of     4h bytes   (  0.0%)&lt;/pre&gt;
&lt;p&gt;
Мы увидим, что использованная RAM сократилась на 3 байта (отрезали по одному байту от каждого таймера). Но обратим внимание еще на то, что используемая ROM-память также сократилась (на 23 байта). Это связано с тем, что:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; во-первых, сократился код сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;, который теперь обрабатывает однобайтовые переменные, вместо двухбайтовых;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; во-вторых, в сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; теперь также передается однобайтовый параметр, опять экономится место;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; в-третьих, само нутро сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; теперь тоже работает с однобайтовыми числами.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Сейчас у нас три задачи, которые почти ничего не делают, а кроме них ничего нет. Поэтому выигрыш 3х байт оперативной памяти и 23 слов программной памяти не ощутим. Но когда в программе будет 10 задач и под 50 вызовов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, да еще куча всяких переменных и подпрограмм, тогда мы почувствуем, что выигрыш в 10 байт RAM и в 200 слов ROM уже ощутим. Также не лишним будет упомянуть, что и скорость работы &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; возрастает, т.к. однобайтовые переменные обрабатываются быстрее.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 3 - системный тик&quot; [55395-63445] --&gt;
&lt;h2&gt;&lt;a name=&quot;системный_тик&quot; id=&quot;системный_тик&quot;&gt;Системный тик&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

О каких параметрах нам нужно думать, выбирая время системного тика?
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Системный тик&quot; [63446-63609] --&gt;
&lt;h3&gt;&lt;a name=&quot;диапазон_задержек&quot; id=&quot;диапазон_задержек&quot;&gt;Диапазон задержек&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

В первую очередь, конечно же, о диапазоне формируемых задержек. Например, совершенно понятно, что если системный тик = 10 мс, то мы не сможем сформировать задержку в 5 мс. С другой стороны, имея системный тик в 1 мс, при разрядности таймера задач по умолчанию в 16 бит мы сможем сформировать задержку только в 65.5 секунд, что может оказаться недостаточным для некоторых приложений (например, регистрация температуры и влажности производится раз в 10 минут = 600 секунд). Кроме того, как уже было описано выше, иногда есть возможность (а иногда и необходимость) сократить размерность таймера задач до одного байта. 
&lt;/p&gt;

&lt;p&gt;
Поэтому, первое, о чем нужно думать при выборе длительности системного тика, - это чтобы он позволял при выбранной размерности таймеров задач обеспечивать формирование всего диапазона задержек, применяемых в программе.
&lt;/p&gt;

&lt;p&gt;
Следует добавить, что на особые случаи есть возможность делать таймеры задач 32-битными.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Диапазон задержек&quot; [63610-65321] --&gt;
&lt;h3&gt;&lt;a name=&quot;точность_задержек&quot; id=&quot;точность_задержек&quot;&gt;Точность задержек&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

При написании программы следует помнить, что точность формирования задержки равна одному системному тику. Дело в том, что, вызывая сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, мы не знаем, через какое время будет вызван &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; в первый раз. Если прерывание уже на подходе, а мы вызываем в задаче &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;(10), то практически сразу за вызовом этого сервиса таймер задачи уменьшится на 1. В результате чего задача прождет не 10, а 9 системных тиков. Об этой особенности надо помнить и по возможности избегать вызовов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; с параметром 1, т.к. в этом случае задача может вообще ничего не прождать, а получить управление следующим же шагом.
&lt;/p&gt;

&lt;p&gt;
Чем выше требуемая точность, тем меньше должно быть время системного тика. При этом надо помнить, что чем больше значение параметра в вызове сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, тем больше относительная точность формирования задержки. Если требуется высокая точность при длинных задержках, то есть смысл увеличить разрядность таймеров задач. 
&lt;/p&gt;

&lt;p&gt;
Однако не стоит забывать о трех вещах:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; OSA - кооперативная ОС, и только сама задача может решить, когда отдавать управление планировщику. Поэтому как бы точно не была задана задержка в задаче, например, Task_A, она не получит управление раньше, чем задача, например, Task_B отдаст управление планировщику, даже если ее приоритет ниже.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Сам планировщик на поиск готовых задач и сравнение их приоритетов затрачивает некоторое время. Поэтому если время системного тика сопоставимо или меньше времени работы планировщика, то точность не улучшится.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; Наконец, сам сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; выполняется не мгновенно, а за какой-то промежуток времени (в нашем примере 21 такт для 3х 16-разрядных таймеров). Чем больше активных таймеров, тем дольше выполняется &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;. Если системный тик будет выбран достаточно маленьким, чтобы прерывание успевало выполниться до того, как весь обработчик прерывания отработает, то можно зависнуть в прерывании до тех пор, пока &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; не разгрузится (не обнулит часть таймеров).&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Точность задержек&quot; [65322-69116] --&gt;
&lt;h3&gt;&lt;a name=&quot;прочие_условия&quot; id=&quot;прочие_условия&quot;&gt;Прочие условия&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

К прочим условиям можно отнести все, что угодно. Например, можно вызывать &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; с периодом WDT, который будет использоваться для пробуждения контроллера из Sleep-режима:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_Sleep &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_SLEEP&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        OS_CLRWDT&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        OS_Timer&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;

Очевидно, что системный тик в данном случае будет равен периоду WDT. Обратим внимание на два новых сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_sleep&quot; class=&quot;wikilink2&quot; title=&quot;osa:ref:allservices:os_sleep&quot; rel=&quot;nofollow&quot;&gt;OS_SLEEP&lt;/a&gt;&lt;/span&gt; и &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_clrwdt&quot; class=&quot;wikilink2&quot; title=&quot;osa:ref:allservices:os_clrwdt&quot; rel=&quot;nofollow&quot;&gt;OS_CLRWDT&lt;/a&gt;&lt;/span&gt;. Эти сервисы так же, как и &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_ei&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_ei&quot;&gt;OS_EI&lt;/a&gt;&lt;/span&gt;, были добавлены для упрощения переноса кода на другую платформу.
&lt;/p&gt;

&lt;p&gt;
Также к прочим условиям можно отнести удобство, например, использование круглых чисел: 1 мс, 10 мс, 100 мс, 1 сек.
&lt;/p&gt;

&lt;p&gt;
Можно сделать системный тик зависимым от внешних условий, например, вызывать &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; при приходе каждого импульса на вывод RB0. 
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Прочие условия&quot; [69117-70619] --&gt;
&lt;h2&gt;&lt;a name=&quot;заключение&quot; id=&quot;заключение&quot;&gt;Заключение&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Итак, в этом уроке мы познакомились с очень полезным и удобным сервисом операционной системы для формирования задержек &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;, а также узнали порядок обработки внутренних таймеров, привязанных к задачам, с помощью сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt;. Практически ни одна программа не обходится без задержек, и сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; будет, наверное, одним из самых часто используемых в ваших программах. Поэтому мы так подробно на нем и остановились.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Заключение&quot; [70620-71524] --&gt;
&lt;h3&gt;&lt;a name=&quot;задание&quot; id=&quot;задание&quot;&gt;Задание&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Для особо пытливых могу предложить небольшое задание: модифицировать программу так, чтобы во время простоя контроллер входил в режим пониженного энергопотребления (проще говоря - в Sleep).
&lt;/p&gt;

&lt;p&gt;
Рекомендации к решению:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; включить WDT в битах конфигурации контроллера;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; увеличить количество задач в файле конфигурации ОС;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; убрать вызов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_timer&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_timer&quot;&gt;OS_Timer&lt;/a&gt;&lt;/span&gt; из прерывания, иначе, иногда выполняясь, он будет приводить к более быстрому обнулению таймеров;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; пересчитать все аргументы вызовов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt; с учетом периода WDT.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Задание&quot; [71525-] --&gt;</description>
    </item>
    <item rdf:about="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor4?rev=1274808786">
        <dc:format>text/html</dc:format>
        <dc:date>2010-05-25T21:33:06+03:00</dc:date>
        <title>OSA : Учебник. Урок 4 - Бинарные семафоры</title>
        <link>http://wiki.pic24.ru/doku.php/osa/tutorial/tutor4?rev=1274808786</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;osa_учебник._урок_4_-_бинарные_семафоры&quot; id=&quot;osa_учебник._урок_4_-_бинарные_семафоры&quot;&gt;OSA : Учебник. Урок 4 - Бинарные семафоры&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/intro&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:intro&quot;&gt;К оглавлению&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;OSA : Учебник. Урок 4 - Бинарные семафоры&quot; [1-140] --&gt;
&lt;h2&gt;&lt;a name=&quot;тема&quot; id=&quot;тема&quot;&gt;Тема&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

В предыдущих примерах наши задачи жили самостоятельной жизнью и могли рассматриваться как отдельные независимые программы, которым просто волею судьбы довелось делить один микроконтроллер на всех. Они крутились каждая в своем цикле, временно передавая управление планировщику, а уж что он там делал - их не касалось. На практике - довольно редкая ситуация. Обычно задачи, хоть и живут каждая своей жизнью, но все вместе делают одно дело. Т.е. между ними требуется какое-то взаимодействие, или синхронизация. Например, в системе работают две задачи: измерение температуры и вывод информации на экран. Вторая задача не может вывести на экран значение температуры, пока первая задача не завершила измерение. В данном уроке будет рассмотрен самый простой способ синхронизации задач - использование &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/services/binary_semaphores&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:services:binary_semaphores&quot;&gt;бинарных (двоичных) семафоров&lt;/a&gt;&lt;/span&gt;.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Тема&quot; [141-1715] --&gt;
&lt;h2&gt;&lt;a name=&quot;теория&quot; id=&quot;теория&quot;&gt;Теория&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Бинарный семафор - внутренняя системная переменная, которая может принимать значения &amp;quot;0&amp;quot; и &amp;quot;1&amp;quot;. Фактически - это битовая переменная, которая может быть установлена/сброшена/проверена любой задачей. Чаще всего бинарный семафор применяется тогда, когда из двух задач в один момент времени может работать только одна. Например, из всех работающих задач две задачи одновременно захотели записать какие-то данные во внешнюю EEPROM. Если данных для записи много, то процесс записи может затянуться (поскольку операция записи одной ячейки требует несколько миллисекунд). Разумеется, расходовать время ожидания записи каждой ячейки вхолостую не хочется, ведь в это время по-прежнему можно опрашивать клавиатуру, управлять какими-то внешними исполнительными устройствами и т.д. Т.е. желательно на время ожидания управление передавать другим задачам. Но что делать, если одна из этих других задач тоже хочет произвести запись? Ведь она обратится к внешней EEPROM в тот момент, когда та уже занята записью. Вот здесь на помощь и приходят бинарные семафоры. Из всех желающих произвести запись задач та, которая получает управление первой, сбрасывает семафор в &amp;quot;0&amp;quot;, говоря тем самым всем остальным задачам, что EEPROM уже занята. Теперь все остальные задачи, желающие произвести запись, видя, что семафор сброшен (т.е. EEPROM уже кем-то используется), будут ждать его установки (т.е. освобождения EEPROM). По завершении записи первая задача вновь устанавливает семафор в &amp;quot;1&amp;quot;, говоря остальным, что EEPROM освободилась и может быть использована другими задачами.
&lt;/p&gt;

&lt;p&gt;
Одновременно в программе могут использоваться несколько семафоров: один - для EEPROM, один - для UART, один - еще для каких-то целей и т.д. В OSA доступное количество ограничивается свободной RAM-памятью: один байт вмещает в себя 8 бинарных семафоров. Сами бинарные семафоры хранятся во внутреннем системном массиве, размер которого определяется на этапе компиляции и зависит от предполагаемого количество используемых семафоров. Это количество указывается программистом явно в файле &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; (заданием константы &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OS_BSEMS&lt;/a&gt;&lt;/span&gt;). Для работы с бинарными в OSA есть несколько сервисов:

&lt;/p&gt;
&lt;table class = &quot;fpl&quot;&gt;
	&lt;tr&gt;
		&lt;td&gt;
&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_set&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_set&quot;&gt;OS_Bsem_Set&lt;/a&gt;&lt;/span&gt;		&lt;/td&gt;
		&lt;td&gt;
Установка семафора		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_reset&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_reset&quot;&gt;OS_Bsem_Reset&lt;/a&gt;&lt;/span&gt;		&lt;/td&gt;
		&lt;td&gt;
Сброс семафора		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_switch&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_switch&quot;&gt;OS_Bsem_Switch&lt;/a&gt;&lt;/span&gt;		&lt;/td&gt;
		&lt;td&gt;
Переключение семафора		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
&lt;em&gt;&lt;code&gt;bool &lt;/code&gt;&lt;/em&gt;&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_check&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_check&quot;&gt;OS_Bsem_Check&lt;/a&gt;&lt;/span&gt;		&lt;/td&gt;
		&lt;td&gt;
Проверка семафора		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;		&lt;/td&gt;
		&lt;td&gt;
Ожидание семафора.		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait_to&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait_to&quot;&gt;OS_Bsem_Wait_TO&lt;/a&gt;&lt;/span&gt;		&lt;/td&gt;
		&lt;td&gt;
Ожидание семафора с выходом по таймауту.		&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;

В параметрах каждому сервису передается номер бинарного семафора. Семафоры нумеруются от 0 до &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OS_BSEMS&lt;/a&gt;&lt;/span&gt;-1. Например:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; семафор номер 0 служит для блокировки внешней EEPROM. Все задачи, желающие произвести чтение/запись в EEPROM должны проверять нулевой семафор; &lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; семафор номер 1 служит для блокировки USART. Все задачи, которые хотят передать какие-то данные по USART должны проверять первый семафор;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; и т.д.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Для удобства обращения к семафорам можно задать им идентификаторы (как это сделать, описано ниже).
&lt;/p&gt;

&lt;p&gt;
Разберемся с работой бинарных семафоров на практике.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Теория&quot; [1716-7314] --&gt;
&lt;h2&gt;&lt;a name=&quot;проект&quot; id=&quot;проект&quot;&gt;Проект&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Для знакомства с бинарными семафорами напишем программу, состоящую из двух задач, управляющих светодиодами:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; первая задача будет по очереди зажигать по одному светодиоду слева направо;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; вторая задача будет по очереди гасить по одному светодиоду справа на лево.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Следуя инструкциям, описанным в &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/tutor1&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:tutor1&quot;&gt;первом уроке&lt;/a&gt;, создадим проект в папке &amp;quot;c:\tutor\t4&amp;quot; и назовем его &amp;quot;tutor4.c&amp;quot;. Остановимся только на конфигурировании. 
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;конфигурирование_проекта_osacfg.h&quot; id=&quot;конфигурирование_проекта_osacfg.h&quot;&gt;Конфигурирование проекта (osacfg.h)&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Запустим утилиту OSAcfg_Tool.exe и создадим новый файл конфигурации для нашего проекта (кнопка &amp;quot;Browse…&amp;quot; и выбор папки проекта в открывшемся диалоговом окне). 
&lt;/p&gt;

&lt;p&gt;
Теперь в секции &amp;quot;System&amp;quot; устанавливаем параметр &amp;quot;Tasks&amp;quot; = 2 (у нас будут две задачи). Теперь нам нужно сказать системе, что мы будем использовать задержки в программе (задержки нужны, т.к. иначе программа будет работать слишком быстро, и на глаз будет не заметно, что происходит). Для этого нам нужно включить таймеры задач: в секции &amp;quot;Timers&amp;quot; устанавливаем галочку напротив пункта &amp;quot;Task timers&amp;quot;.
&lt;/p&gt;

&lt;p&gt;
Мы предполагаем использовать в своей программе бинарный семафор, поэтому укажем это в конфигурации, установив количество бинарных семафоров и задав имя.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t4_osacfg.png?id=osa%3Atutorial%3Atutor4&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t4_osacfg.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t4_osacfg.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Имя BS_LEDS_ARE_FREE, которое мы указали, мы будем использовать в качестве идентификатора семафора при обращении к нему в программе. Его, конечно, можно было и не задавать, оставив поле имен (ID name) пустым, но тогда придется обращаться к семафору по номеру, например:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Ждем нулевой семафор&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Однако, запись:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Ждем освобождения порта со светодиодами&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;

намного нагляднее и информативнее. Тем более, если в программе будут использоваться несколько семафоров, то без имен в них можно будет запутаться. Задание же имен в списке &lt;strong&gt;ID names&lt;/strong&gt; в утилите OSAcfg_Tool сделает наш код намного нагляднее и позволит снизить вероятность ошибки.
&lt;/p&gt;

&lt;p&gt;
После этого жмем кнопку &amp;quot;Save&amp;quot; в нижней части экрана, читаем сообщение, что файл успешно сохранен, давим &amp;quot;OK&amp;quot; и выходим из программы конфигуратора по кнопке &amp;quot;Exit&amp;quot;. 
&lt;/p&gt;

&lt;p&gt;
Убеждаемся, что файл &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OSAcfg.h&lt;/a&gt;&lt;/span&gt; создан в папке &amp;quot;c:\tutor\t4&amp;quot;. Обратим внимание, что в файле &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OSAcfg.h&lt;/a&gt;&lt;/span&gt; появилась конструкция enum, в которой описан идентификатор нашего бинарного семафора:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw2&quot;&gt;enum&lt;/span&gt; OSA_BSEMS_ENUM
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    BS_LEDS_ARE_FREE           &lt;span class=&quot;co1&quot;&gt;// Для блокировки светодиодов&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- SECTION &quot;Проект&quot; [7315-11468] --&gt;
&lt;h3&gt;&lt;a name=&quot;описание_задач&quot; id=&quot;описание_задач&quot;&gt;Описание задач&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Для начала создадим задачи без учета того, что порт, к которому подключены светодиоды, является разделяемым ресурсом. Т.е. опишем две задачи, как живущие сами по себе.
&lt;/p&gt;

&lt;p&gt;
Задача для зажигания светодиодов:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LEDS_ON &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_i;      &lt;span class=&quot;co1&quot;&gt;// Счетчик&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_cMask;  &lt;span class=&quot;co1&quot;&gt;// Маска для зажигания светодиодов&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        s_cMask &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;                    &lt;span class=&quot;co1&quot;&gt;// Первым зажигаем нулевой светодиод&lt;/span&gt;
        &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;s_i &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;; s_i &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;8&lt;/span&gt;; s_i&lt;span class=&quot;sy2&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
            PORT_LEDS |= s_cMask;       &lt;span class=&quot;co1&quot;&gt;// Зажигаем текущий светодиод&lt;/span&gt;
            s_cMask &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Берем очередной светодиод&lt;/span&gt;
            OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Пауза в 100 мс&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Эта задача по очереди с интервалом в 100 мс зажжет все 8 светодиодов.
&lt;/p&gt;

&lt;p&gt;
Теперь опишем задачу гашения светодиодов, для разнообразия сделаем в ней время паузы отличное от первой задачи:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LEDS_OFF &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_i;      &lt;span class=&quot;co1&quot;&gt;// Счетчик&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_cMask;  &lt;span class=&quot;co1&quot;&gt;// Маска для гашения светодиодов&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        s_cMask &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x80&lt;/span&gt;;                 &lt;span class=&quot;co1&quot;&gt;// Первым гасим седьмой светодиод&lt;/span&gt;
        &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;s_i &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;; s_i &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;8&lt;/span&gt;; s_i&lt;span class=&quot;sy2&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
            PORT_LEDS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; ~s_cMask;      &lt;span class=&quot;co1&quot;&gt;// Гасим текущий светодиод&lt;/span&gt;
            s_cMask &lt;span class=&quot;sy1&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Берем очередной светодиод&lt;/span&gt;
            OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Пауза в 150 мс&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Эта задача по очереди с интервалом в 150 мс гасит все 8 светодиодов.
&lt;/p&gt;

&lt;p&gt;
Не забудем в функцию main() добавить сервисы, которые:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; инициализируют ОС;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; объявят системе, что Task_LEDS_OFF и Task_LEDS_ON являются функциями-задачами;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; разрешат прерывания;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; запустят планировщик на выполнение.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;// Инициализация периферии&lt;/span&gt;
    init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Инициализация системы&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LEDS_ON&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LEDS_OFF&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Разрешение прерываний&lt;/span&gt;
    OS_EI&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Запуск планировщика&lt;/span&gt;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Описание задач&quot; [11469-14349] --&gt;
&lt;h3&gt;&lt;a name=&quot;полный_текст_программы&quot; id=&quot;полный_текст_программы&quot;&gt;Полный текст программы&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Итак, полный текст нашей программы теперь будет выглядеть так:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;pic.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;// Задаем биты конфигурации:&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - внутренний RC-генератор&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем WDT&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем низковольтное программирование&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем функцию отладки&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
__CONFIG&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;INTIO &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; WDTDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; PWRTEN &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; MCLRDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; LVPDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; UNPROTECT &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; BORDIS
               &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; IESODIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; FCMDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; DEBUGDIS&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Определеяем порт для работы со светодиодами&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define PORT_LEDS   PORTD&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Параметры таймера:&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - прескейлер = 4,&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - постскейлер = 1,&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - предел счета = 250&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Тактовая частота контроллера = 4 МГц.&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Период возникновения прерывания по TMR2 получается&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  равным 4 * 1 * 250 * Tcyc = 1 ms&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define PR2_CONST       250-1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define TMR2_PRS        1                           // prs = 4&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define TMR2_POST       0                           // post = 1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define T2CON_CONST     (TMR2_POST&amp;lt;&amp;lt;3) | TMR2_PRS&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Глобальные переменные&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cCounter1;
&lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; m_cCounter2;
&amp;nbsp;
&amp;nbsp;
&amp;nbsp;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Прерывание. Возникает каждую мс&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; interrupt isr &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    OS_EnterInt&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;TMR2IF&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Timer&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        TMR2IF &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
    OS_LeaveInt&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Функции-задачи&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LEDS_ON &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_i;      &lt;span class=&quot;co1&quot;&gt;// Счетчик&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_cMask;  &lt;span class=&quot;co1&quot;&gt;// Маска для зажигания светодиодов&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        s_cMask &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;                    &lt;span class=&quot;co1&quot;&gt;// Первым зажигаем нулевой светодиод&lt;/span&gt;
        &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;s_i &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;; s_i &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;8&lt;/span&gt;; s_i&lt;span class=&quot;sy2&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
            PORT_LEDS |= s_cMask;       &lt;span class=&quot;co1&quot;&gt;// Зажигаем текущий светодиод&lt;/span&gt;
            s_cMask &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Берем очередной светодиод&lt;/span&gt;
            OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Пауза в 100 мс&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LEDS_OFF &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_i;      &lt;span class=&quot;co1&quot;&gt;// Счетчик&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_cMask;  &lt;span class=&quot;co1&quot;&gt;// Маска для гашения светодиодов&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        s_cMask &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x80&lt;/span&gt;;                 &lt;span class=&quot;co1&quot;&gt;// Первым гасим седьмой светодиод&lt;/span&gt;
        &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;s_i &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;; s_i &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;8&lt;/span&gt;; s_i&lt;span class=&quot;sy2&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
            PORT_LEDS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; ~s_cMask;      &lt;span class=&quot;co1&quot;&gt;// Гасим текущий светодиод&lt;/span&gt;
            s_cMask &lt;span class=&quot;sy1&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Берем очередной светодиод&lt;/span&gt;
            OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Пауза в 150 мс&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Инициализация периферии&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; init &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка портов I/O&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PORTA &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTB &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTC &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTD &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    TRISA &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISB &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISC &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISD &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка таймера 2&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PR2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; PR2_CONST;
    T2CON &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; T2CON_CONST | &lt;span class=&quot;nu12&quot;&gt;0x04&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка прерываний&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PIR1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PIR2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    INTCON &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    TMR2IE &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;         &lt;span class=&quot;co1&quot;&gt;// Разрешаем прерываие по TMR2&lt;/span&gt;
    PEIE &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Разрешаем периферийные прерывания&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// Глобальный бит разрешения прерываний будет&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// установлен непосредственно перед запуском&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// планировщика в функции main()&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  main&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;// Инициализация периферии&lt;/span&gt;
    init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Инициализация переменных системы&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LEDS_ON&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LEDS_OFF&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Разрешение прерываний&lt;/span&gt;
    OS_EI&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Запуск планировщика&lt;/span&gt;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  end of file&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;&lt;/pre&gt;&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Полный текст программы&quot; [14350-20648] --&gt;
&lt;h2&gt;&lt;a name=&quot;работа_программы&quot; id=&quot;работа_программы&quot;&gt;Работа программы&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Работа программы&quot; [20649-20693] --&gt;
&lt;h3&gt;&lt;a name=&quot;без_синхронизации&quot; id=&quot;без_синхронизации&quot;&gt;Без синхронизации&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Соберем проект (Ctlr+F10) и прошьем его в контроллер. Увидим мы совсем не то, что задумали: вместо того, чтобы сначала по очереди зажечь все светодиоды, а потом по очереди их погасить, программа их зажигает и гасит одновременно. Дело в том, что задачи живут сами по себе и ни одна из них не знает о том, что делает другая. Вот схема работы нашей программы. 
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t4_switch_no_bsem.png?id=osa%3Atutorial%3Atutor4&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t4_switch_no_bsem.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t4_switch_no_bsem.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Как видно из схемы, каждая задача работает по своему алгоритму и выполняет со светодиодами те действия, которые мы ей предписали: одна зажигает светодиоды по одному, другая - гасит. 
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Без синхронизации&quot; [20694-21750] --&gt;
&lt;h3&gt;&lt;a name=&quot;с_синхронизацией&quot; id=&quot;с_синхронизацией&quot;&gt;С синхронизацией&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Очевидно, что мы пока не достигли своей цели. Теперь добавим блокировку задач с помощью бинарного семафора. Т.к. на момент получения управления задача не знает, свободен ресурс или нет (установлен семафор или сброшен), она становится в ожидание семафора сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;. Если семафор установлен и задача является самой приоритетной (или же сейчас ее очередь выполняться при равноприоритетности), то она получает управление. Если семафор сброшен (т.е. ресурс уже кем-то занят), то задача остается в режиме ожидания. Отметим одно важное свойство сервиса &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;:
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt; автоматически сбрасывает семафор, когда задача получает управление. 

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
После того, как задача зажжет (погасит) все светодиоды, она должна освободить ресурс, т.е. установить семафор, чтобы другие задачи знали, что можно ресурс занимать.
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;coMULTI&quot;&gt;/*****************************************/&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LEDS_ON &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_i;      &lt;span class=&quot;co1&quot;&gt;// Счетчик&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_cMask;  &lt;span class=&quot;co1&quot;&gt;// Маска для зажигания светодиодов&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;; &lt;span class=&quot;co1&quot;&gt;// Ждем, когда можно будет работать&lt;/span&gt;
                                        &lt;span class=&quot;co1&quot;&gt;// со светодиодами&lt;/span&gt;
        s_cMask &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;                    &lt;span class=&quot;co1&quot;&gt;// Первым зажигаем нулевой светодиод&lt;/span&gt;
        &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;s_i &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;; s_i &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;8&lt;/span&gt;; s_i&lt;span class=&quot;sy2&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
            PORT_LEDS |= s_cMask;       &lt;span class=&quot;co1&quot;&gt;// Зажигаем текущий светодиод&lt;/span&gt;
            s_cMask &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Берем очередной светодиод&lt;/span&gt;
            OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Пауза в 100 мс&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
        OS_Bsem_Set&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Освобождаем ресурс&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/*****************************************/&lt;/span&gt;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LEDS_OFF &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_i;      &lt;span class=&quot;co1&quot;&gt;// Счетчик&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;char&lt;/span&gt; s_cMask;  &lt;span class=&quot;co1&quot;&gt;// Маска для гашения светодиодов&lt;/span&gt;
&amp;nbsp;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;; &lt;span class=&quot;co1&quot;&gt;// Ждем, когда можно будет работать&lt;/span&gt;
                                        &lt;span class=&quot;co1&quot;&gt;// со светодиодами&lt;/span&gt;
        s_cMask &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x80&lt;/span&gt;;                 &lt;span class=&quot;co1&quot;&gt;// Первым гасим седьмой светодиод&lt;/span&gt;
        &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;s_i &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;; s_i &lt;span class=&quot;sy1&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;8&lt;/span&gt;; s_i&lt;span class=&quot;sy2&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
            PORT_LEDS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; ~s_cMask;      &lt;span class=&quot;co1&quot;&gt;// Гасим текущий светодиод&lt;/span&gt;
            s_cMask &lt;span class=&quot;sy1&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Берем очередной светодиод&lt;/span&gt;
            OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;              &lt;span class=&quot;co1&quot;&gt;// Пауза в 150 мс&lt;/span&gt;
        &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
        OS_Bsem_Set&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Освобождаем ресурс&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/*****************************************/&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Остался последний штрих. Т.к. при инициализации системы все бинарные семафоры сбрасываются, то перед началом работы мы должны установить семафор, разрешающий работу со светодиодами. Это можно сделать, например, в функции main после создания задач:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LEDS_ON&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LEDS_OFF&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Разрешить работу со светодиодами&lt;/span&gt;
    OS_Bsem_Set&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Разрешение прерываний&lt;/span&gt;
    OS_EI&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Если этого не сделать, то обе наши задачи будут бесконечно ждать семафор, который никогда не установится.
&lt;/p&gt;

&lt;p&gt;
Соберем проект (Ctrl+F10) и прошьем контроллер. Теперь мы видим, что программа работает так, как мы задумали с самого начала. Разберемся подробнее.
&lt;/p&gt;

&lt;p&gt;
Итак, начальные условия:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; две готовые к запуску задачи (после создания задача сразу готова к выполнению);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; задачи имеют одинаковый приоритет;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; есть установленный семафор BS_LEDS_ARE_FREE.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Когда планировщик начинает работу, он перебирает все задачи в поисках готовых и сравнивает их приоритеты, чтобы вычислить, какую задачу нужно запускать. В нашем случае обе задачи готовы и имеют одинаковый приоритет, поэтому планировщик запустит ту из них, которая была создана первой, т.е. Task_LEDS_ON. Задача, получив управление, входит в свой бесконечный цикл for, где первым делом натыкается на сервис ожидания &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;. Разберемся подробнее, что произойдет. Задача видит, что семафор установлен, поэтому она могла бы продолжить выполнение. Но она ничего не знает об остальных задачах программы. Что если этот же семафор ожидает другая задача, имеющая более высокий приоритет? Ведь в этом случае более приоритетная задача должна получить управление. Поэтому задача не продолжает выполнение, а передает управление планировщику, чтобы он проверил, нет ли более важных задач. Сама задача Task_LEDS_ON останется при этом готовой к выполнению. 
&lt;/p&gt;

&lt;p&gt;
Планировщик проверяет все задачи на предмет готовности (обе задачи сейчас готовы) и сравнивает приоритеты. Приоритеты равны, поэтому управление получит следующая по очереди задача, т.е. Task_LEDS_OFF. Получив управление, она войдет в бесконечный цикл, где так же, как и задача Task_LED_ON, наткнется на сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;. Семафор все еще установлен, и задача проделает те же операции, что и первая задача, т.е. отдаст управление планировщику, чтобы он проверил, нет ли более приоритетных задач. 
&lt;/p&gt;

&lt;p&gt;
Планировщик видит, что обе задачи ждут один и тот же семафор и они имеют одинаковый приоритет. Поэтому он отдаст управление следующей по очереди задаче, т.е. вновь управление получит Task_LEDS_ON. Теперь, когда известно, что нет более приоритетных задач, ожидающих этот же семафор, задача Task_LEDS_ON может продолжить выполнение. При выходе из ожидания семафора сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt; сбрасывает семафор, сообщая остальным задачам, что ресурс уже занят. 
&lt;/p&gt;

&lt;p&gt;
Далее программа входит в цикл, в котором по очереди зажгутся все 8 светодиодов. После зажигания первого светодиода задача выдерживает задержку в 100 мс, переключаясь при этом в режим ожидания и передавая управление планировщику. Планировщик, получив управление, проверяет, нет ли готовых задач. Выясняется, что нет, т.к. одна задача в задержке, а вторая ждет семафор, который был только что сброшен задачей, захватившей ресурс (управление портом со светодиодами). Поэтому в течение 100 мс ни одна задача не получит управления. По истечении 100 мс задача Task_LEDS_ON снова становится готовой к выполнению (задача Task_LEDS_OFF все еще ждет, т.к. семафор остался сброшенным). Получив управление, Task_LEDS_ON зажигает второй светодиод и снова уходит в задержку. И т.д., пока не зажгутся все 8 светодиодов.
&lt;/p&gt;

&lt;p&gt;
После зажжения всех светодиодов задача вновь устанавливает семафор, сообщая остальным задачам, что ресурс (порт, к которому подключены светодиоды, свободен). Теперь она возвращается на начало своего цикла и опят натыкается на сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;. Она видит, что семафор установлен, но ей надо проверить, нет ли других задач ожидающих этот же семафор, поэтому управление передается планировщику. А планировщик видит, что есть две задачи с одинаковым приоритетом, ожидающие семафор, и он отдает управление той, которая следующая по очереди (чтобы не выполнять всегда одну и ту же), т.е. задаче Task_LEDS_OFF. 
&lt;/p&gt;

&lt;p&gt;
Задача Task_LEDS_OFF, получив управление, сразу же сбрасывает семафор (мы уже говорили, что это автоматически делается сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;), а потом работает по той же схеме, что и задача Task_LEDS_ON, только не зажигает светодиоды, а гасит их.
&lt;/p&gt;

&lt;p&gt;
Схематически работу программы можно изобразить так:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t4_switch_bsem.png?id=osa%3Atutorial%3Atutor4&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t4_switch_bsem.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t4_switch_bsem.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
На рисунке видно, что одна задача, получив управление, блокирует другую. После выполнения своей части работы (зажжения/гашения всех светодиодов) задача устанавливает семафор, после чего оказывается сама блокированной другой задачей и остается в этом состоянии до тех пор, пока другая задача не обработает все 8 светодиодов, после чего вновь обретает возможность получить управление.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;С синхронизацией&quot; [21751-34128] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_1_-_приоритеты&quot; id=&quot;эксперимент_1_-_приоритеты&quot;&gt;Эксперимент 1 - приоритеты&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Изменим приоритет одной из задач в функции main:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;, Task_LEDS_OFF&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Соберем проект (Ctrl+F10) и прошьем контроллер. Мы увидим, что светодиоды зажглись с интервалом в 100 мс и остались  этом состоянии. Дело в том, что теперь получается так, что одновременно семафор ожидается двумя задачами с разными приоритетами. Планировщик каждый раз выбирает ту из них, чей приоритет выше, т.е. задачу Task_LEDS_ON.
&lt;/p&gt;

&lt;p&gt;
Однако, стоит нарушить условие одновременности ожидания семафора - и задача Task_LEDS_OFF получит возможность выполниться. Для этого добавим в конец цикла в задаче Task_LEDS_ON короткую задержку:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;        ...
        &lt;span class=&quot;me1&quot;&gt;OS_Bsem_Set&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Освобождаем ресурс&lt;/span&gt;
&amp;nbsp;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;                    &lt;span class=&quot;co1&quot;&gt;// За время этой задержки задача с более&lt;/span&gt;
                                        &lt;span class=&quot;co1&quot;&gt;// низким приоритетом успеет стать единственной&lt;/span&gt;
                                        &lt;span class=&quot;co1&quot;&gt;// готовой к выполнению&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Что произойдет? После установки семафора BS_LEDS_ARE_FREE задача Task_LEDS_ON не сразу же начинает ждать этот семафор, а с некоторой задержкой, в течение которой она будет находиться в режиме ожидания. При этом планировщик увидит, что единственной готовой к выполнению задачей является Task_LEDS_OFF. тут уже приоритет первой задачи значения не имеет, т.к. в сравнении приоритетов участвуют только готовые задачи, а задача Task_LEDS_ON - в ожидании. Получив управление, Task_LEDS_OFF сразу же сбрасывает семафор и начинает выполнять свои операции по гашению светодиодов. По завершении миллисекундной задержки задача Task_LEDS_ON подходит к сервису &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;, но на этот момент семафор уже сброшен, поэтому этой задаче ничего не остается делать, кроме как ждать освобождения ресурса, занятого менее приоритетной задачей.
&lt;/p&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;исключение&quot; id=&quot;исключение&quot;&gt;Исключение&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Есть одно исключение: если семафор устанавливается в прерывании в промежутке между проверкой готовности планировщиком задач с высоким приоритетом (должна проверяться первой) и низким, то выполнение получит задача с более низким приоритетом. Это нужно учитывать при разработке программ, работающих с семафорами в прерываниях.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 1 - приоритеты&quot; [34129-37805] --&gt;
&lt;h3&gt;&lt;a name=&quot;эксперимент_2_-_два_сервиса_ожидания_подряд&quot; id=&quot;эксперимент_2_-_два_сервиса_ожидания_подряд&quot;&gt;Эксперимент 2 - два сервиса ожидания подряд&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Попробуем переписать задачу Task_LEDS_ON, добавив еще один сервис ожидания семафора:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_LEDS_ARE_FREE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        ...&lt;/pre&gt;
&lt;p&gt;
Рассмотрим, что произойдет в этом случае. Задача Task_LEDS_ON, получив управление, первым сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt; сбросит семафор. Ко второму сервису она подойдет с уже сброшенным семафором и дальше пройти не сможет. Т.е. программа повиснет, т.к. есть две задачи, ожидающие один и тот же семафор, который нигде, кроме, самих задач не устанавливается. А так как задачи управления не получают, то и семафор они установить не смогут.
&lt;/p&gt;

&lt;p&gt;
Можете прошить программу с такой задачей в контроллер и убедиться, что работать она не будет.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Эксперимент 2 - два сервиса ожидания подряд&quot; [37806-39143] --&gt;
&lt;h2&gt;&lt;a name=&quot;заключение&quot; id=&quot;заключение&quot;&gt;Заключение&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

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

&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt; блокирует задачу (держит ее в состоянии ожидания), пока семафор не будет установлен;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt; сбрасывает семафор после того, как его дождется;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; если две задачи одновременно ждут один и тот же семафор, то управление получит та из них, чей приоритет выше.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Заключение&quot; [39144-] --&gt;</description>
    </item>
    <item rdf:about="http://wiki.pic24.ru/doku.php/osa/tutorial/tutor5?rev=1295443110">
        <dc:format>text/html</dc:format>
        <dc:date>2011-01-19T16:18:30+03:00</dc:date>
        <title>OSA : Учебник. Урок 5 - Расширенный приоритетый режим</title>
        <link>http://wiki.pic24.ru/doku.php/osa/tutorial/tutor5?rev=1295443110</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;osa_учебник._урок_5_-_расширенный_приоритетый_режим&quot; id=&quot;osa_учебник._урок_5_-_расширенный_приоритетый_режим&quot;&gt;OSA : Учебник. Урок 5 - Расширенный приоритетый режим&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/intro&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:intro&quot;&gt;К оглавлению&lt;/a&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;OSA : Учебник. Урок 5 - Расширенный приоритетый режим&quot; [1-163] --&gt;
&lt;h2&gt;&lt;a name=&quot;тема&quot; id=&quot;тема&quot;&gt;Тема&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Вернемся к вопросу приоритетов. В предыдущих примерах были показаны некоторые особенности приоритетного режима. Сейчас рассмотрим приоритеты более детально. 
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Тема&quot; [164-480] --&gt;
&lt;h2&gt;&lt;a name=&quot;теория&quot; id=&quot;теория&quot;&gt;Теория&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

OSA поддерживает три различных режима обработки приоритетов: неприоритетный, обычный (по умолчанию) и расширенный. Режим выбирается один раз на этапе компиляции и не может быть изменен в ходе выполнения программы. Для выбора режима в файле &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; должна быть определена константа &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration#управление_приоритетами&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OS_PRIORITY_LEVEL&lt;/a&gt;&lt;/span&gt;. Рассмотрим, в чем их особенности, достоинства и недостатки.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Теория&quot; [481-1267] --&gt;
&lt;h3&gt;&lt;a name=&quot;неприоритетный_режим&quot; id=&quot;неприоритетный_режим&quot;&gt;Неприоритетный режим&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Самый простой, самый быстрый и самый нетребовательный к ресурсам режим. Работая в неприоритетном режиме, планировщик по очереди перебирает все задачи одну за другой, проверяя их готовность к выполнению. Как только он обнаруживает готовую задачу, он сразу же передает ей управление. Этот режим чем-то сродни обычному суперциклу, за исключением некоторых удобств, привносимых самой ОС, таких как возможность прервать функцию в середине выполнения с последующим возвратом в точку выхода, синхронизация задач с помощью событий, контроль таймаутов и задержек и т.д.
&lt;/p&gt;

&lt;p&gt;
Для несложных программ такой режим является самым удачным выбором. Недостатком этого режима является невозможность предоставить более важным задачам возможность получать управление чаще и быстрее. Т.е. даже если произошло событие, которого такая задача ожидала, то она должна будет подождать, пока выполнятся все предшествующие ей в очереди задачи.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Неприоритетный режим&quot; [1268-2993] --&gt;
&lt;h3&gt;&lt;a name=&quot;обычный_приоритетный_режим&quot; id=&quot;обычный_приоритетный_режим&quot;&gt;Обычный приоритетный режим&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

В отличие от неприоритетного, в этом режиме планировщик сперва просматривает все задачи на предмет готовности, затем сравнивает приоритеты готовых к выполнению задач, а уже потом передает управление самой приоритетной из них. Т.е. в этом режиме имеется возможность каким-то задачам выделить больше процессорного времени, а каким-то меньше. Платой за это будет скорость работы планировщика: если в неприоритетном режиме для запуска следующей задачи ему иногда достаточно проверить одну, то в обычном приоритетном режиме планировщик каждый раз должен проверять все активные в данный момент времени задачи, что увеличивает время поиска в &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OS_TASKS&lt;/a&gt;&lt;/span&gt; раз (в среднем проверка одной задачи длится 80-100 тактов). 
&lt;/p&gt;

&lt;p&gt;
Если в программе есть две постоянно готовые задачи с разными приоритетами, то та из них, чей приоритет ниже, никогда не получит управления, т.к. всегда есть готовая к выполнению более высокоприоритетная задача. Это также можно отнести к недостаткам данного режима.
&lt;/p&gt;

&lt;p&gt;
Если в программе есть несколько постоянно готовых задач с одинаковым приоритетом, то все они будут получать управление по очереди. За одним исключением, когда равноприоритетные задачи ожидают одно и то же событие, устанавливаемое в другой задаче. Т.к. планировщик проверяет задачи в одном и том же порядке, управление из этих равноприоритетных задач будет получать весгда та задача, которая выполняется первой после той, которая сформировала событие. Ниже это будет пояснено на примере.
&lt;/p&gt;

&lt;p&gt;
Итак, обычный приоритетный режим имеет два основных недостатка:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; блокировка низкоприоритетных задач высокоприоритетными;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; получение управления только одной задачей из весх равноприоритетных, ожидающих одно и то же событие.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Обычный приоритетный режим&quot; [2994-6175] --&gt;
&lt;h3&gt;&lt;a name=&quot;расширенный_приоритетный_режим&quot; id=&quot;расширенный_приоритетный_режим&quot;&gt;Расширенный приоритетный режим&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Расширенный приоритетный режим был введен на смену обычному приоритетному режиму для устранения двух его основных недостатков. В этом режиме важность задачи поределяется не только приоритетом, но и давностью последнего получения управления. Рабтая в этом режиме, планировщик, просматривая список задач и выбирая наиболее приоритетную из готовых, делает еще две вещи:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; увеличивает важность готовой к выполнению, но не получившей управления (т.к. была более приоритетная) задачи;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; меняет порядок просмотра задач так, чтобы только что выполненная задача оказалась в списке последней.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

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

&lt;p&gt;
Недостатками этого метода являются:
&lt;/p&gt;
&lt;ol&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; более низкая, чем в обычном приоритетном режиме, скорость работы планировщика (см. &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/speed&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:speed&quot;&gt;Скоростные характеристики&lt;/a&gt;);&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; на каждую задачу выделяютя дополнительно по два байта ОЗУ, определяющие важность и порядковый номер в очереди планировщика.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;

Теперь рассмотрим работу программы под управлением данных режимов на практике.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Расширенный приоритетный режим&quot; [6176-9294] --&gt;
&lt;h2&gt;&lt;a name=&quot;проект&quot; id=&quot;проект&quot;&gt;Проект&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Для разбора приоритетных режимов напишем программу, состоящую из 4х задач:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; три из них будут дожидаться двоичного семафора и зажигать/гасить каждая свой светодиод;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; четвертая задача имеет самый низкий приоритет, и она будет устанавливать семафор.&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

Следуя инструкциям, описанным в &lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/tutorial/tutor1&quot; class=&quot;wikilink1&quot; title=&quot;osa:tutorial:tutor1&quot;&gt;первом уроке&lt;/a&gt;, создадим проект в папке &amp;quot;c:\tutor\t5&amp;quot; и назовем его &amp;quot;tutor5.c&amp;quot;.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Проект&quot; [9295-9983] --&gt;
&lt;h3&gt;&lt;a name=&quot;конфигурирование_проекта_osacfg.h&quot; id=&quot;конфигурирование_проекта_osacfg.h&quot;&gt;Конфигурирование проекта (osacfg.h)&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Запустим утилиту OSAcfg_Tool.exe и создадим новый файл конфигурации для нашего проекта (кнопка &amp;quot;Browse…&amp;quot; и выбор папки проекта в открывшемся диалоговом окне). 
&lt;/p&gt;

&lt;p&gt;
Теперь в секции &amp;quot;System&amp;quot; устанавливаем параметр &amp;quot;Tasks&amp;quot; = 4 (у нас будут четыре задачи). Далее нам нужно сказать системе, что мы будем использовать задержки в программе, т.к. без задержек мы на глаз не уследим за происхоящим. Для этого нам нужно включить таймеры задач: в секции &amp;quot;Timers&amp;quot; устанавливаем галочку напротив пункта &amp;quot;Task timers&amp;quot;.
&lt;/p&gt;

&lt;p&gt;
Также нам понадобится бинарный семафор: установим количество семафоров в &amp;quot;1&amp;quot; и зададим имя семафору BS_SIGNAL. Это имя будет использоваться нами для обращения к семафору в программе.
&lt;/p&gt;

&lt;p&gt;
Мы предполагаем использовать в своей программе бинарный семафор, поэтому укажем это в конфигурации, установив количество бинарных семафоров и задав имя.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_osacfg.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media wikilink2&quot; title=&quot;osa:tutorial:tutor_t5_osacfg.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_osacfg.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
После этого жмем кнопку &amp;quot;Save&amp;quot; в нижней части экрана, читаем сообщение, что файл успешно сохранен, давим &amp;quot;OK&amp;quot; и выходим из программы конфигуратора по кнопке &amp;quot;Exit&amp;quot;. 
&lt;/p&gt;

&lt;p&gt;
Убеждаемся, что файл &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;OSAcfg.h&lt;/a&gt;&lt;/span&gt; создан в папке &amp;quot;c:\tutor\t5&amp;quot;.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Конфигурирование проекта (osacfg.h)&quot; [9984-11978] --&gt;
&lt;h3&gt;&lt;a name=&quot;описание_задач&quot; id=&quot;описание_задач&quot;&gt;Описание задач&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Для начала опишем задачи, управляющие светодиодами:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LED1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_SIGNAL&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Дожидаемся семафора&lt;/span&gt;
        PIN_LED1 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Изменяем состояние первого светожиода&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Аналогичным образом будут выглядеть задачи, управляющие светодиодами LED2 и LED3.
&lt;/p&gt;

&lt;p&gt;
Терь опишем задачу, сигнализирующую семафором:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_Signal &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Set&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_SIGNAL&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Эта задача каждые 200 мс будет сигналить семафором.
&lt;/p&gt;

&lt;p&gt;
В функцию main(), как всегда, добавляем сервисы инициализации, создания задач и запуска планировщика:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;// Инициализация периферии&lt;/span&gt;
    init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Инициализация системы&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_Signal&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Разрешение прерываний&lt;/span&gt;
    OS_EI&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Запуск планировщика&lt;/span&gt;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Описание задач&quot; [11979-13481] --&gt;
&lt;h3&gt;&lt;a name=&quot;полный_текст_программы&quot; id=&quot;полный_текст_программы&quot;&gt;Полный текст программы&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Итак, полный текст нашей программы теперь будет выглядеть так:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;htc.h&amp;gt;&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;osa.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;// Задаем биты конфигурации:&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - внутренний RC-генератор&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем WDT&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем низковольтное программирование&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//   - отключаем функцию отладки&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
__CONFIG&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;INTIO &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; WDTDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; PWRTEN &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; MCLRDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; LVPDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; UNPROTECT &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; BORDIS
               &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; IESODIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; FCMDIS &lt;span class=&quot;sy3&quot;&gt;&amp;amp;&lt;/span&gt; DEBUGDIS&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Определеяем выводы для управления светодиодами&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED1    RD0&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED2    RD1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define PIN_LED3    RD2&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Параметры таймера:&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - прескейлер = 4,&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - постскейлер = 1,&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  - предел счета = 250&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Тактовая частота контроллера = 4 МГц.&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Период возникновения прерывания по TMR2 получается&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  равным 4 * 1 * 250 * Tcyc = 1 ms&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define PR2_CONST       250-1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define TMR2_PRS        1                           // prs = 4&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define TMR2_POST       0                           // post = 1&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define T2CON_CONST     (TMR2_POST&amp;lt;&amp;lt;3) | TMR2_PRS&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Прерывание. Возникает каждую мс&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; interrupt isr &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;TMR2IF&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Timer&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        TMR2IF &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Функции-задачи&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LED1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_SIGNAL&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Дожидаемся семафора&lt;/span&gt;
        PIN_LED1 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Изменяем состояние первого светожиода&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//-----------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LED2 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_SIGNAL&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Дожидаемся семафора&lt;/span&gt;
        PIN_LED2 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Изменяем состояние второго светожиода&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//-----------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LED3 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Wait&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_SIGNAL&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Дожидаемся семафора&lt;/span&gt;
        PIN_LED3 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Изменяем состояние третьего светожиода&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//-----------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_Signal &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        OS_Bsem_Set&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;BS_SIGNAL&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        OS_Delay&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  Инициализация периферии&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; init &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка портов I/O&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PORTA &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTB &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTC &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PORTD &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    TRISA &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISB &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISC &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    TRISD &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка таймера 2&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PR2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; PR2_CONST;
    T2CON &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; T2CON_CONST | &lt;span class=&quot;nu12&quot;&gt;0x04&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//  Настройка прерываний&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;//------------------------------------------------------------------------------&lt;/span&gt;
&amp;nbsp;
    PIR1 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    PIR2 &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
    INTCON &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;;
&amp;nbsp;
    TMR2IE &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;         &lt;span class=&quot;co1&quot;&gt;// Разрешаем прерываие по TMR2&lt;/span&gt;
    PEIE &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Разрешаем периферийные прерывания&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// Глобальный бит разрешения прерываний будет&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// установлен непосредственно перед запуском&lt;/span&gt;
                        &lt;span class=&quot;co1&quot;&gt;// планировщика в функции main()&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  main&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; main &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;co1&quot;&gt;// Инициализация периферии&lt;/span&gt;
    init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Инициализация системы&lt;/span&gt;
    OS_Init&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_Signal&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Разрешение прерываний&lt;/span&gt;
    OS_EI&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&amp;nbsp;
    &lt;span class=&quot;co1&quot;&gt;// Запуск планировщика&lt;/span&gt;
    OS_Run&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//  end of file&lt;/span&gt;
&lt;span class=&quot;co1&quot;&gt;//******************************************************************************&lt;/span&gt;&lt;/pre&gt;&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Полный текст программы&quot; [13482-19331] --&gt;
&lt;h2&gt;&lt;a name=&quot;работа_программы&quot; id=&quot;работа_программы&quot;&gt;Работа программы&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Работа программы&quot; [19332-19376] --&gt;
&lt;h3&gt;&lt;a name=&quot;неприоритетный_режим1&quot; id=&quot;неприоритетный_режим1&quot;&gt;Неприоритетный режим&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Запустим еще раз конфигуратор OSAcfg_Tool.exe, загрузим в него файл c:\tutor5\&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; и в секции &lt;strong&gt;&amp;quot;System&amp;quot;&lt;/strong&gt; выберем в поле &lt;strong&gt;&amp;quot;Priority level&amp;quot;&lt;/strong&gt; пункт &lt;strong&gt;&amp;quot;Disabed&amp;quot;&lt;/strong&gt;. Сохряняем и выходим. Убеждаемся, что в файле &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; появилась строка:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#define OS_PRIORITY_LEVEL  OS_PRIORITY_DISABLED&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Соберем проект (Ctlr+F10) и прошьем его в контроллер. Мы увидим, что мигает только один светодиод, которым управляет задача Task_LED1. Рассмотрим подробнее, как работает программа в этом режиме. Для удобства на диаграммах рядом с именем задачи показан ее приоритет.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Начало.&lt;/strong&gt;
При старте все светодиоды погашены, а семафор сброшен (запрещен). Готовой к выполнению является только задача Task_Signal, все остальные ожидают семафор.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_step_0.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_step_0.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_step_0.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 1.&lt;/strong&gt; Первой планировщиком просматривается задача Task_Signal, т.к. она была создана первой. Он видит, что она готова к выполнению и передает ей управление. После завершения ее работы семафор BS_SIGNAL установлен в &amp;quot;1&amp;quot;. 
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_disabled_step_1.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_disabled_step_1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_disabled_step_1.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 2.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Задача Task_Signal переведена в режим ожидания (&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;), но три задачи, усправляющие светодиодами, становятся готовыми к выполнению. Планировщик берет для проверки следующую по очереди задачу (т.е. Task_LED1), видит, что она готова, и передает ей управление. Вспомним, что сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt; после того, как задача получает управление, сбрасывает семафор. Задача Task_LED1 изменяет состояние светодиода LED1.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_disabled_step_2.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_disabled_step_2.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_disabled_step_2.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 3.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
После того, как Task_LED1 отработала и переведена в режим ожидания (сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;), семафор вновь сброшен, следовательно, задачи Task_LED2 и Task_LED3 опять переводятся в режим ожидания. Таким образом, на данный момент нет ни одной готовой к выподлнению задачи. И так будет до тех пор, пока не закончится время ожидания в задаче Task_Signal (в нашем примере 100 мс). Задачи и дальше будут проверяться по кругу. Сначала Task_LED2:
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_disabled_step_3.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_disabled_step_3.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_disabled_step_3.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Затем Task_LED3, Task_Signal, Task_LED1, снова Task_LED2, снова Task_LED3 и т.д.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 4.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Когда время ожидания задачи Task_Signal выходит, эта задача становится готовой к выполнению и ждет своей очереди на проверку планировщиком.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_disabled_step_x.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_disabled_step_x.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_disabled_step_x.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 5.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Дождавшись своей очереди, задача получает управление. При этом она снова устанавливает семафор.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_disabled_step_x1.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_disabled_step_x1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_disabled_step_x1.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 6.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Семафор вновь установлен, и задачи Task_LED1, Task_LED2 и Task_LED3 опять готовы к выполнению. Первой по очереди планировщиком проверяется задача Task_LED1, она и получает управление, т.к. является готовой. Семафор BS_SIGNAL сбрасывается, а свтодиод LED1 меняет свое состояние.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_disabled_step_x2.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_disabled_step_x2.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_disabled_step_x2.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Как видим, шаги 1 и 2 идентичны шагам 5 и 6. И дальше программа будет идти по кругу, а задачи Task_LED2 и Task_LED3 так и не получат управления.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Неприоритетный режим&quot; [19377-24170] --&gt;
&lt;h3&gt;&lt;a name=&quot;обычный_приоритетный_режим1&quot; id=&quot;обычный_приоритетный_режим1&quot;&gt;Обычный приоритетный режим&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Запустим конфигуратор OSAcfg_Tool.exe, загрузим в него файл c:\tutor5\&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; и в секции &lt;strong&gt;&amp;quot;System&amp;quot;&lt;/strong&gt; выберем в поле &lt;strong&gt;&amp;quot;Priority level&amp;quot;&lt;/strong&gt; пункт &lt;strong&gt;&amp;quot;Normal&amp;quot;&lt;/strong&gt;. Сохряняем и выходим. Убеждаемся, что в файле &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; появилась строка:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#define OS_PRIORITY_LEVEL  OS_PRIORITY_NORMAL&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Для разнообразия расставим задачам разные приоритеты (в функции main()):

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;7&lt;/span&gt;, Task_Signal&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Самый низкий приоритет&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;5&lt;/span&gt;, Task_LED1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;, Task_LED2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Самый высокий приоритет&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;, Task_LED3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;

Соберем проект (Ctlr+F10) и прошьем его в контроллер. Мы увидим, что мигает только один светодиод, которым управляет задача Task_LED2. Рассмотрим подробнее, как работает программа в этом режиме.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Начало.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
При старте все светодиоды погашены, а семафор сброшен (запрещен). Готовой к выполнению является только задача Task_Signal, все остальные ожидают семафор.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_step_0.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_step_0.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_step_0.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 1.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
В отличие от неприоритетного, в обычном приоритетном режиме планировщик сперва проверяет готовность всех задач и выполняет сравнение приоритетов готовых. Только после этого принимает решение о передаче управления. Причем проверка идет в последовательности, определяемой очередностью создания задач. (Эта очередность может быть нарушена в случае удаления одних задач и создания на их месте новых, но в данном примере одна всегда одна и та же).
&lt;/p&gt;

&lt;p&gt;
Единственной готовой задачей на данный момент является Task_Signal. И хоть она имеет низший приоритет, именно она получит управление, т.к. больше готовых задач нет. Выполнившись, она установила семафор BS_SIGNAL и перейдет в режим ожидания на 100 мс (&lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_delay&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_delay&quot;&gt;OS_Delay&lt;/a&gt;&lt;/span&gt;).
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_normal_diff_step_1.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_normal_diff_step_1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_normal_diff_step_1.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
После выполнения задачи очередь сдвигается так, что первой на проверку будет стоять следующая за выполнившейся, а только что выполнившаяся отправляется в конец очередь. Порядок очередь при этом не меняется, т.е., например, задача Task_LED2 всегда будет идти за Task_LED1, а Task_LED3 - всегда за Task_LED2 И т.д. Смысл циклического сдвига будет пояснен ниже (в Эксперименте 3).
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 2.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Планировщик вновь просматривает все 4 задачи, начиная на этот раз со следующей за только что выполнившейся Task_Signal, т.е. с Task_LED1. На данный момент готовы 3 задачи: Task_LED1, Task_LED2 и Task_LED3. Планировщик сравнивает их приоритеты (помним, что 0 - высший приоритет, 7 - низший), вычисляет, что наивысший приоритет из готовых имеет задача Task_LED2, и именно ей передается управление. Эта задача в свою очередь сбрасывает семафор (это делается автоматически сервисом &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;) и изменяет состояние светодиода LED2.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_normal_diff_step_2.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_normal_diff_step_2.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_normal_diff_step_2.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
После выполнения задачи снова циклически сдвигаются в очереди проверки так, что Task_LED2 оказывается в самом конце очереди. Первой становится та задача, что была за Task_LED2, т.е. Task_LED3.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 3.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Планировщик просматривает все задачи, начиная с Task_LED3, и видит, что готовых к выполнению нет (т.к. все ждут семафор, а Task_Signal выдерживает паузу). Поэтому управление ни одна задача не получает.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_normal_diff_step_3.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_normal_diff_step_3.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_normal_diff_step_3.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
После проверки все задачи циклически сдвигаются на 1, и следующая проверка начнется с задачи Task_Signal. Далее они будет проверятся и проверяться, пока не закончится время задержки в задаче Task_Signal (т.е. в течение 100 мс).
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 4.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Когда время задержки истекает, задача Task_Signal становится готовой к выполнению. Вне зависимости от того, с какой задачи начинается проверка все очереди задач, управление получит именно она, т.к. она на данный момент времени является самой приоритетной из всех готовых (вернее - единственной готовой). После выполнения семафор будет установлен, а задача снова переведена в решим ожидания задержки.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_normal_diff_step_x.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_normal_diff_step_x.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_normal_diff_step_x.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Обратим внимание на то, что циклический сдвиг задач в очереди в данном случае не производится, т.к. последняя выполнившаяся задача и так уже находится в самом конце очереди.
&lt;/p&gt;

&lt;p&gt;

&lt;strong&gt;Шаг 5.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Этот шаг получается идентичным шагу 2. Т.е. снова из трех готовых к выполнению задач будет выбрана та, чей приоритет выше, т.е. Task_LED2. Она снова сбросит семафор и снова изменит состояние светодиода.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_normal_diff_step_x1.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_normal_diff_step_x1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_normal_diff_step_x1.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 6.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Дальше идем по кругу, т.е. шаг 6 идентичен шагу 3. 
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_normal_diff_step_x2.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_normal_diff_step_x2.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_normal_diff_step_x2.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
В результате программа будет крутиться, выполняя только две задачи: Task_Signal и самую приоритетную из ожидающих семафор - Task_LED2.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;эксперимент_1._перестановка_приоритетов&quot; id=&quot;эксперимент_1._перестановка_приоритетов&quot;&gt;Эксперимент 1. Перестановка приоритетов&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Только что мы наблюдали, что при работе программы мигает только один светодиод, которым управляет задача Task_LED2. Попробуем поменять приоритеты задач:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;7&lt;/span&gt;, Task_Signal&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Самый низкий приоритет&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;5&lt;/span&gt;, Task_LED1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;, Task_LED2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu19&quot;&gt;0&lt;/span&gt;, Task_LED3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Самый высокий приоритет&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Теперь самый высокий приоритет у задачи Task_LED3. Запустим программу и убедимся, что теперь мигает только светодиод LED3. Принцип работы тот же, что и описан выше, только на шагах 2 и 5 планировщиком для запуска выбирается не Task_LED2, а Task_LED3 как более приоритетная.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;эксперимент_2._равные_приоритеты&quot; id=&quot;эксперимент_2._равные_приоритеты&quot;&gt;Эксперимент 2. Равные приоритеты&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

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

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_Signal&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Все приоритеты равны&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Соберем эту программу (Ctrl+F10) и запустим на выполнение. Теперь мы видим, что работает только светодиод LED1. Почему? Потому что здесь мы наткнулись на недостаток обычного приоритетного режима, описанный выше: &amp;quot;получение управления только одной задачей из всех равноприоритетных, ожидающих одно и то же событие&amp;quot;. Дело в том, что при сравнении приоритетов готовых задач играет роль последеовательность, в которой планировщик рассматривает задачи и преимущество отдается той, которая была рассмотрена первее. В нашем случае получается, что после работы Task_Signal (т.е. сразу после того момента, как был установлен семафор), первой в очереди оказывается именно Task_LED1. При равных приоритетах Task_LED1, Task_LED2 и Task_LED3 преимущество отдается той, которая была рассмотрена первой, т.е. Task_LED1. Этого недостатка лишен расширенный приоритетный режим.

&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;эксперимент_3._замена_os_bsem_wait_на_os_yield&quot; id=&quot;эксперимент_3._замена_os_bsem_wait_на_os_yield&quot;&gt;Эксперимент 3. Замена OS_Bsem_Wait на OS_Yield&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

Попробуем теперь при равных приоритетах задач заменить сервис &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt; на &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;. Т.е. отменяем ожидание несколькими задачами одного и того же условия.

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; Task_LED1 &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw1&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;;;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
        &lt;span class=&quot;co1&quot;&gt;//OS_Bsem_Wait(BS_SIGNAL);&lt;/span&gt;
        OS_Yield&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
        PIN_LED1 &lt;span class=&quot;sy3&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;// Изменяем состояние первого светожиода&lt;/span&gt;
    &lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;

по аналогии перепишем так же задачи Task_LED2 и Task_LED3. Соберем программу и запустим ее на выполнение. Мы увидим, что теперь загорелись все три светодиода. На самом деле они не горят постоянно, а очень быстро мигают (ожидания семафора-то теперь нет, следовательно нет паузы в 100мс, выдерживаемой между установками семафора). 
&lt;/p&gt;

&lt;p&gt;
Но на что мы должны обратить внимание: все три задачи получают управление. Вспомним еще раз: управление получает наиболее приоритетная из готовых или, если их приоритеты равны, первая готовая из рассмотренных планировщиком. В нашем случае все три задачи, управляющие светодиодом, постоянно готовы. Теперь вспомним, что планировщик после выполнения каждой задачи циклически сдвигает очередь так, чтобы выполненая оказалась в конце очереди. Таким образом получается, что из всех равноприоритетных задач планировщиком первой рассматривается не одна и та же, а разные задачи. Это отдает преимущество первой рассмотренной всем по очереди. В результате этого все задачи имеют возможность выполниться.
&lt;/p&gt;

&lt;p&gt;
Теперь проделаем еще один небольшой эксперимент: одной из задач понизим приоритет:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_Signal&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;// Все приоритеты равны&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;5&lt;/span&gt;, Task_LED2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// А у этой задачи приоритет ниже&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Соберем программу и запустим ее. Теперь мы видим, что горят (т.е. очень быстро мигают) только светодиоды LED1 и LED3, а LED2 потушен. Почему? Потому что здесь мы наткнулись на еще один недостаток обычного приоритетного режима: &amp;quot;блокировка низкоприоритетных задач высокоприоритетными&amp;quot;. Пока есть готовые к выполнению высокоприоритетные задачи (а в нашем случае они есть), низкоприоритеные не смогут получить управление. Этого недостатка лишен расширенный 
приоритетный режим.

&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Обычный приоритетный режим&quot; [24171-38678] --&gt;
&lt;h3&gt;&lt;a name=&quot;расширенный_приоритетный_режим1&quot; id=&quot;расширенный_приоритетный_режим1&quot;&gt;Расширенный приоритетный режим&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Вернем программу в исходное состояние, т.е. расставим всем задачам равные приоритеты и восстановим вызовы сервисов &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_bsem_wait&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_bsem_wait&quot;&gt;OS_Bsem_Wait&lt;/a&gt;&lt;/span&gt;, убрав вызовы &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/allservices/os_yield&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:allservices:os_yield&quot;&gt;OS_Yield&lt;/a&gt;&lt;/span&gt;.
&lt;/p&gt;

&lt;p&gt;
Запустим утилиту OSAcfg_tool.exe и в секции &lt;strong&gt;&amp;quot;System&amp;quot;&lt;/strong&gt; выберем в поле &lt;strong&gt;&amp;quot;Priority level&amp;quot;&lt;/strong&gt; пункт &lt;strong&gt;&amp;quot;Extended&amp;quot;&lt;/strong&gt;. Сохряняем и выходим. Убеждаемся, что в файле &lt;span class=&quot;important&quot;&gt;&lt;a href=&quot;http://wiki.pic24.ru/doku.php/osa/ref/appendix/configuration&quot; class=&quot;wikilink1&quot; title=&quot;osa:ref:appendix:configuration&quot;&gt;osacfg.h&lt;/a&gt;&lt;/span&gt; появилась строка:

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#define OS_PRIORITY_LEVEL  OS_PRIORITY_EXTENDED&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Теперь собираем программу (Ctrl+F10) и прошиваем контроллер. О чудо! Мигают все три светодиода. Разберемся, как работает программа в этом режиме. Обращу ваше внимание на то, что в данном случае рядом с именем задачи будет стоять не приоритет, а ее важность (как уже было написано, эта характеристика меняется в ходе выполнения программы; чем цифра больше, тем важность выше).
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Начало.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
При старте все светодиоды погашены, а семафор сброшен (запрещен). Готовой к выполнению является только задача Task_Signal, все остальные ожидают семафор.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_step_0.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_step_0.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_step_0.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 1.&lt;/strong&gt;
Здесь все так же, как и о бычном приоритетном режиме, т.к. готова только одна задача Task_Signal. Она устанавливает семафор и переходит в режим ожидания задержки.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_1.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_1.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Теперь только что выполненная задача перемещается в конец очереди. Замечу, что хоть внешне этот перенос и выглядит так же, как и в примере с обчным приоритетным режимом, это не совсем то же самое. Там был циклический сдвиг, а здесь просто перенос задачи в конец очереди со сдвигом всех следующих за ней, но предыдущие остаются на своих местах. Это станет понятно чуть ниже.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 2.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Три задачи готовы к выполнению, имея одинаковую важность (т.к. изначально она пропорциональна приоритету, а он у всех трех задач одинаковый). Но планировщик отдаст преимущество задаче Task_LED1, как первой рассмотренной из готовых. Она сбросит семафор и зменит состояние светодиода LED1.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_2.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_2.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_2.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Теперь важный момент: задачи Task_LED2 и Task_LED3 были готовы, но упрвление получить не смогли, т.к. Task_LED1 уже сбросила семафор. Поэтому их важность увеличивается. Важность задачи Task_LED1 должна быть понижена до минимума, т.к. она только что была выполнена, но сейчас остается неизменной, т.к. она и так минимальная. Задача Task_LED1 переносится в конец очереди, а все следующие за ней (в конкретном случае - все оставшиеся задачи) сдвигаются влево, ближе к началу очереди.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 3.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Нет ни одной готовой к выполнению программы, т.к. семафор сброшен, а задача, его устанавливающая, выдерживает паузу. Однако обратим внимание на важности задач Task_LED2 и Task_LED3: они теперь увеличились на 1, повысив вероятность быть избранными планировщиком в следующий раз.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_3.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_3.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_3.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Порядок задач не будет меняться до тех пор, пока не закончится время ожидания Task_Signal (в отличие от обычного приоритета, где все задачи циклически сдвигались при кажлой перепроверке).
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 4.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Время задержки вышло, и задача Task_Signal снова готова к выполнению. Она же его и получает. т.к. является единственной готовой. Семафор устанавливается, а сама задача снова переводится в режим ожидания задержки.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_x.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_x.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_x.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Обратим внимание на то, как изменится очередь после выполнения этого шага: Task_LED2 и Task_LED3 остались на своих местах, т.к. они являются предшествующими только что выполненной; Task_Signal ставится в конец очереди, а все последующие (т.е. Task_LED1) сдвигаются на 1 позицию ближе к началу очереди.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 5.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
На данный момент готовы три задачи: Task_LED1, Task_LED2 и Task_LED3. Но теперь планировщик руководствуется не приоритетами, как в обычном приоритетном режиме, а другой характеристикой - важностью. Задача Task_LED1 отпадает сразу, т.к. имеет самую маленькую важность. А из задач, имеющих одинаковые значения важности, будет выбрана та, которая была рассмотрена планировщиком первее, т.е. Task_LED2. Она же сбросит семафор и изменит состояние светодиода LED2.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_x1.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_x1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_x1.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Теперь важность только что выполенной задачи устанавливается минимальной, а сама задача ставится в конец очереди. Важности готовых, но не получивших управление, задач увеличивается.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 6.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Таким образом, на данный момент самой важной является та из трех ожидающих семафор, которая еще не получала управление, т.е. Task_LED3.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_x2.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_x2.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_x2.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 7.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
По завершению задержки Task_Signal становится готовой к выполнению и получает управление. Опять устанавливается семафор, а задача Task_Signal переводится в паузу.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_x3.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_x3.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_x3.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Так же на схеме видно, что Task_LED3, стоящая в очереди до только что выполненной задачи, остается на своем месте, а Task_LED1 и Task_LED2 сдвигаются на одну позицию ближе к началу очереди. Task_Signal, как обычно, перемещается в конец очереди.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 8.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
Итак снова готовы к выполнению все три задачи, ожидающие семафор. Но самой важной из них является Task_LED3, она и получит управление, сбросит семафор и изменит состояние своего светодиода.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_x4.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_x4.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_x4.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
После выполнения ее важность делается минимальной, а сама задача ставится в конец очереди. Важности задач Task_LED1 и Task_LED2 увеличиваются.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Шаг 9.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
На данный момент времени все задачи отработали, а самой важной является та, которая отработала самой первой. И теперь при установке семафора управление вновь получит Task_LED1.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/osa/tutorial/tutor_t5_extended_step_x5.png?id=osa%3Atutorial%3Atutor5&quot; class=&quot;media&quot; title=&quot;osa:tutorial:tutor_t5_extended_step_x5.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/osa/tutorial/tutor_t5_extended_step_x5.png&quot; class=&quot;media&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Таким образом, мы видим, что в расширенном приоритетном режиме нет блокированных задач.

&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;

&lt;h4&gt;&lt;a name=&quot;эксперимент_1._изменение_приоритетов&quot; id=&quot;эксперимент_1._изменение_приоритетов&quot;&gt;Эксперимент 1. Изменение приоритетов&lt;/a&gt;&lt;/h4&gt;
&lt;div class=&quot;level4&quot;&gt;

&lt;p&gt;

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

&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;    &lt;span class=&quot;co1&quot;&gt;// Создание задач&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_Signal&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;  &lt;span class=&quot;co1&quot;&gt;//&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;, Task_LED1&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Высший приоритет&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;, Task_LED2&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Средний приоритет&lt;/span&gt;
    OS_Task_Create&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;5&lt;/span&gt;, Task_LED3&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;    &lt;span class=&quot;co1&quot;&gt;// Нисший приоритет&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Соберем программу (Ctlr+F10) и прошьем ее в контроллер. Теперь мы видим, что светдиод LED1 мигает быстрее всех, а LED3 - медленнее всех. Это означает, что все задачи получают управление, но те, которые имеют более высокий приоритет, получают его чаще. 
&lt;/p&gt;

&lt;p&gt;
Не вдаваясь особо в детали, скажу, что важность увеличивается не на 1, как схематически показано в примере, а на число пропорциональное приоритету. Т.е. Важность задачи Task_LED1 будет расти быстрее, чем у Task_LED2.

&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Расширенный приоритетный режим&quot; [38679-49559] --&gt;
&lt;h2&gt;&lt;a name=&quot;заключение&quot; id=&quot;заключение&quot;&gt;Заключение&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Итак, мы рассмотрели работу одной программы в трех различных режимах и выяснили, где расширенный приоритет может оказаться полезным. На практике это может выглядеть так: есть несколько задач желающих отправить данные через USART. USART в данном случае является разделяемым ресурсом, доступ к которому блокируется семафором. Если высокоприоритетным задачам всегда есть, что передать, то низкоприоритетные просто никогда не получат управление и, следовательно, никогда не передадут свои данные. И здесь может быть не важна срочность каких-то данных, просто, например, температуру нет смысла передавать чаще, чем раз в секунду, а даные с какого-т оцифрового датчика нужно гнать постоянно. Но это не значит, что температуру вовсе передавать не надо.
&lt;/p&gt;

&lt;p&gt;
Зачем же тогда есть обычный приоритетный режим и, уж тем более, неприоритетный? Не будем забывать про преимущества неприоритетного режима: скорость и компактность - это делает такой режим незаменимым на малоресурсных контроллерах. А также не будем забывать, что несколько задач, ожидающих одно и то же событие, или наличие нескольких постоянно готовых задач (т.е. обе причины недостатков обычного приоритетного режима) - случаи не частые. 
&lt;/p&gt;

&lt;p&gt;
Наконец, следует учесть, что расширенны приоритетный режим появился недавно (с версии 101000), и появился он имено на замену обычному приоритетному режиму. Обычный же оставлен, во-первых, для совместимости со старыми версиями, а во-вторых, на те случаи, когда приоритетность нужна, но выделять дополнительно по 2 байта RAM на каждую задачу нет возможности.
&lt;/p&gt;
&lt;div class=&quot;plugin_uparrow&quot;&gt;
  &lt;a href=&quot;#&quot; title=&quot;Наверх&quot;&gt;
    &lt;img src=&quot;http://wiki.pic24.ru/lib/plugins/uparrow/images/blue_arrow.png&quot; alt=&quot;Наверх&quot;/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Заключение&quot; [49560-] --&gt;</description>
    </item>
</rdf:RDF>
