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

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

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

 

1
2
3
4
5
/* Infinite loop */
while(1)
{
/* Check the button is pressed */
}

 

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

 

1
2
3
4
5
6
/* Infinite loop */
while(1)
{
/* Check the button is pressed (1 nanosecond) */
/* Print message to the panel (5 seconds) */
}

 

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

 

1
2
3
4
5
6
7
8
9
10
11
12
/* Infinite loop */
while(1)
{
/* Print message to the panel (5 seconds) */
}
 
/* Called when interrupt event occurs */
INTERRUPT_HANDLER()
{
/* Now we know that button is pressed */
/* Do some job */
}

 

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

Конечно среди дорогих читателей найдется тот, кто скажет что-то вроде: «Но зачем мне все это надо? Я сейчас просто установлю операционную систему «RTOS» и не буду заморачиваться!». Тут есть подводные камни. Во-первых для «RTOS» требуется дополнительная память флеша, а во-вторых производительность «RTOS» систем зачастую ниже производительности так называемых «нативных» встроенных систем. Ведь и вправду, зачем изобретать реактивный самолет, если нам нужно транспортное средство для поездки в магазин за хлебом (я о велосипеде).:)

Дописав до конца эту статью, я решил всё-таки предоставить читателю реальный пример всего, что было напечатано выше. Для меня было проще и удобней всего создать программу в среде разработки «VMLAB», так как можно запустить тест программы, даже не имея в наличии микропроцессор. Эта замечательная IDE разрешает симулировать работу реальных устройств, таких как процессор, кнопки и ещё много чего.

Кто хочет запустить этот проект должен скачать и установить:

Теперь запускаем «VMLAB». После запуска выбираем «Project->Open Project» и переходим в директорию скачанного и распакованного проекта. Выбираем файл проекта и открываем его. Теперь для надежности нужно проверить правильность настроек проекта. Для этого нужно перейти «View->Project  File». Мы должны увидеть следующее:

 

 

Если имя директории ранее установленной «WinAVR» отличается от того, что вы увидите в этом файле, тогда нужно подкорректировать файл.

Если все сделано правильно, тогда можно переходить к процессу моделирования. Прочувствовать, как работает псевдомногопоточность вместе с прерываниями. Для того чтобы этого добиться, необходимо открыть такие окна как:

  • «Scope» (осциллограф) – «Alt+Shift+S»,
  • «Control Panel» (тут есть панель кнопок) – «Alt+Shift+C»
  • «Code Notebook» (собственно сам исходный файл проекта) – «Alt+Shift+N».

Не важно как, но Вам нужно сделать как-то так:

 

 

Дальше:

  1. Собираем проект.
  2. Запускаем симуляцию.
  3. Устанавливаем горизонтальную развертку для осциллографа.
  4. Тицяємо кнопочку «0».
  5. Смотрим на осциллограммы осциллографа и анализируем код.

 

Порядок, что за чем делать, указан на рисунке красными цифрами:

 

 

Ну вот и все… Я сказал всё, что хотел. Ниже, традиционно выкладываю ссылку для скачивания проекта. Удачи!

 

Загрузка

Скачать исходный код проекта