Применение SWITCH-технологии при разработке программного обеспечения для микроконтроллеров. Часть 2

№ 12’2006
PDF версия
В предыдущей статье цикла мы начали рассматривать применение SWITCH-технологии для программирования микроконтроллерных устройств. В данной статье мы продолжим рассмотрение реализации различных конструкций, лежащих в основе предлагаемой концепции программирования.

Все статьи цикла.

Итак, мы привели код простейшего конечного автомата, имеющего два состояния и представляющего собой автомат Мили. Автомат переходит из одного состояния в другое под воздействием двух сообщений: MSG_FSM1_ACTIVATE и MSG_FSM1_DEACTIVATE. У читателя может возникнуть вопрос: откуда берутся и как обрабатываются сообщения, если мы не используем операционную систему? Ответ на этот вопрос очень важен, поэтому разберем его подробно.

Обработка сообщений

Широкое применение сообщений является ключевой особенностью всех современных операционных систем — от Windows до «маленьких» ОСРВ, предназначенных для встраиваемых приложений. Механизм сообщений настолько удобен для программиста, что было бы странно отказаться от его применения в автоматной технологии. Перед тем как перейти к реализации собственного механизма обработки сообщений, рассмотрим, как устроены соответствующие механизмы в ОС Windows. В Windows сообщение может быть отправлено с помощью одной из двух функций: SendMessage и PostMessage:

Эти функции имеют одинаковые списки параметров. Параметр hWnd определяет окно (а точнее, процедуру обработки сообщений окна, window procedure), которому адресовано сообщение, параметр Msg является собственно идентификатором сообщения, wParam и lParam определяют параметры сообщения. Параметры могут передаваться непосредственно в виде числовых значений в полях wParam и/или lParam, могут содержаться в отдельной структуре, при этом wParam и/или lParam содержат указатель на эту структуру, и, наконец, могут вовсе отсутствовать. Конкретный смысл полей wParam и lParam определяется сообщением и приведен в документации Windows для каждого сообщения. Также мы можем заметить, что функции SendMessage и PostMessage имеют несколько различные возвращаемые значения, но для наших дальнейших рассуждений это не столь важно. Главное различие между обеими функциями состоит в том, что они отправляют сообщение по-разному. Функция SendMessage отправляет сообщение непосредственно адресату (то есть при ее вызове, по сути, напрямую вызывается соответствующая оконная процедура), а функция PostMessage размещает сообщение в очереди сообщений. Соответственно, в зависимости от способа отправки сообщения делятся на синхронные (queued) и асинхронные (nonqueued). Очередь сообщений представляет собой FIFO-буфер. В ОС Windows существует системная очередь сообщений и отдельные очереди сообщений для каждого потока (с целью экономии системных ресурсов поток после инициализации не имеет очереди сообщений, она создается по мере надобности). Таким образом, передача сообщений в Windows осуществляется посредством взаимодействия множества очередей сообщений: системной очереди и очередей приложений. Передача сообщений может осуществляться от ОС к приложению, от приложения к ОС, от приложения к другим приложениям и внутри одного приложения. Более подробно с механизмом обмена сообщениями Windows можно ознакомиться в [1].

Очередь сообщений

В различных вариантах многопоточных систем программирования для микроконтроллеров можно встретить различные реализации механизма обмена сообщениями. Например, весьма популярная ОСРВ uC/OS II поддерживает два механизма обмена сообщениями: Message Mailbox (почтовый ящик сообщений) и Message Queue (очередь сообщений). Почтовый ящик фактически представляет собой переменную-указатель, содержащую ссылку на собственно сообщение. Очередь сообщений представляет собой буфер фиксированного размера, также содержащий указатели. Потоки и обработчики прерываний могут создавать и удалять очереди и почтовые ящики, размещать в них сообщения и получать их. В uC/OS II существует и специальный механизм, освобождающий очереди и ящики от сообщений, не принятых в течение определенного времени. Система предоставляет программисту полную свободу действий в создании ящиков и очередей сообщений: любой поток может создавать любое количество этих объектов, размер очередей и время «жизни» сообщений определяется программистом [2].

Другой подход к организации обмена сообщениями описан в статье «Get by without an RTOS» Майкла Мелкониана [3]. В рамках концепции, предлагаемой Мелконианом, каждая задача имеет собственную очередь сообщений, представляющую собой простой FIFO-буфер. При этом само сообщение является переменной структурного типа, определяемой программистом для каждого потока отдельно. Поток может извлекать сообщения только из «своей» очереди и размещать сообщения в очередях любых других потоков. Очевидно, что такой подход имеет целый ряд недостатков. Мы не можем вызовом одной функции послать сообщения всем потокам сразу, нам придется посылать сообщения каждому потоку в отдельности. Если поток не «принял» сообщение, то есть не извлек его из очереди, оно останется там неограниченно долгое время, что может вызвать серьезные сбои в работе программы.

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

А сейчас зададим провокационный вопрос: а нужны ли вообще очереди сообщений? Не является ли их применение в ПО встроенных систем скорее результатом устоявшегося стереотипа, чем жизненной необходимостью? И в каких случаях их применение оправдано?

Рассмотрим этот вопрос на примере нашей концепции программирования. Все потоки в программе представлены в виде автоматов, которые «физически» реализованы в виде функций типа ProcessFSM (будем называть эти функции функциями автоматов). На каждой итерации главного цикла программы вызываются все функции автоматов. Таким образом, сообщение, отправленное любым автоматом, может быть принято любым другим автоматом за время, не превышающее полное время исполнения главного цикла программы. Соответственно, мы можем сделать вывод: во всяком случае, в рамках описываемой нами концепции очередь сообщений не нужна. Здесь может возникнуть два вопроса. Первый: что делать с сообщениями, не принятыми в течение цикла? Второй: если в течение цикла будет передано несколько сообщений с различными параметрами, то какое из них будет активно при приеме? Ответы на данные вопросы станут ясны из последующего обсуждения.

Простейшие сообщения: без очереди, без параметров

Во многих случаях передача сообщений с параметрами просто не нужна. При этом каждое сообщение представляет собой, по сути, флаг. Автомат, передающий сообщение, устанавливает соответствующий флаг, а автомат, принимающий сообщение, проверяет состояние этого флага. Очередь сообщений тоже не нужна, так как несколько флагов (то есть несколько различных сообщений) могут быть установлены одновременно без всякой очереди, а отсутствие у сообщений параметров приводит к тому, что держать в очереди два одинаковых сообщения бессмысленно. Разумеется, автомат, принимающий сообщение, должен его удалить, иначе оно останется активным навсегда. Теперь вспомним из предыдущей статьи, как реализован главный цикл программы:

Пусть автомат FSM1 передает некоторое сообщение автомату FSM3, а автомат FSM3 его принимает, то есть переходит под его действием в новое состояние. В этом случае все работает правильно, то есть флаг, соответствующий данному сообщению, устанавливается и сбрасывается в пределах одного цикла программы.

В том случае если автомат FSM3 передает сообщение автомату FSM1, все тоже сработает как надо. Однако на практике такая реализация все же непригодна. И вот почему. Представим себе ситуацию, в которой автомат FSM1 передал сообщение, но оно не принято ни одним автоматом. Такая ситуация может произойти, например, в том случае, если пользователь нажал какую-либо кнопку микроконтроллерного устройства, автомат, контролирующий клавиатуру, послал сообщение MSG_KEY_PRESSED, но устройство в этот момент находится в состоянии, не предусматривающем какое-либо вмешательство пользователя, и, соответственно, ни один автомат не «ждет» сообщение MSG_KEY_PRESSED. В результате флаг, соответствующий MSG_KEY_PRESSED, останется установленным в единичное состояние до тех пор, пока по логике работы программы какой-либо автомат не попадет в состояние, условием выхода из которого является именно это сообщение, и этот переход сработает. Причем случиться это может когда угодно: через миллисекунду или через неделю. В первом случае пользователь, может быть, ничего и не заметит, зато во втором он будет немало удивлен. Ив любом случае нормальная логика работы программы будет нарушена. Вот почему все необработанные сообщения-флаги должны сбрасываться в конце каждого цикла. Для этого и служит функция ProcessMessages(), вызываемая в главном цикле после вызовов функций ProcessFSM() всех автоматов. Но если мы будем просто удалять все сообщения, не принятые в течение рабочего цикла программы, например, вот так:

то нас ждет еще один сюрприз, а именно сообщения в этом случае смогут передаваться только сверху вниз по списку вызовов автоматов, но не в обратном направлении. Для того чтобы избежать такого неприятного эффекта, нужно несколько усложнить механизм передачи сообщений — сделать его двухступенчатым. Пусть сообщениефлаг имеет не два состояния: «неактивно» и «активно», а три: «неактивно», «установлено, но неактивно» и «активно». Тогда сообщение, изначально находящееся в неактивном состоянии, при вызове функции SendMessage перейдет в состояние, «установлено, но неактивно», и автоматы, находящиеся ниже по списку, на него реагировать не будут. При достижении программой конца цикла сообщение переходит в состояние «активно» и находится в этом состоянии в следующем цикле программы до его сброса принявшим его автоматом либо до конца цикла (рис. 3). Такой подход совпадает с принятым в [4]: «все сообщения должны быть обработаны на следующем шаге после генерации».

Рис. 3. Граф переходов сообщений

Приведем и программную реализацию такого механизма:

У такой реализации, тем не менее, есть одно свойство: принять сообщение может только один автомат, причем находящийся выше по списку вызовов функций ProcessFSM(). Однако это не является большой проблемой. В большинстве случаев в каждый конкретный момент времени каждое конкретное сообщение и должен принимать какой-либо конкретный автомат. К примеру, если программа реализует пользовательский интерфейс устройства, то сообщения, передаваемые автоматомменеджером клавиатуры, должен принимать только автомат, отвечающий за элемент интерфейса, находящийся в фокусе ввода. Если же необходима передача сообщения сразу всем автоматам программы (назовем такие сообщения широковещательными, или broadcast messages), то и такой вариант вполне реализуем:

Передача параметров: два варианта

Однако в ряде случаев без параметров не обойтись. Простейшим примером является та же обработка сообщений клавиатуры: нам мало знать, что пользователь нажал на клавишу, нам нужно знать, на какую именно клавишу он нажал. Конечно, можно присвоить отдельное сообщение каждой клавише, например, так:

Но тогда можно представить себе, во что выльется условие типа «пользователь нажал любую клавишу»:

Как-то не очень красиво, правда? Гораздо лучше иметь только одно сообщение MSG_KEY_PRESSED, а код конкретной клавиши получать с помощью специальной функции:

В данном случае передача параметра (кода клавиши) отделена от механизма трансляции сообщений. Код клавиши хранится в отдельной переменной в модуле сканирования клавиатуры, заполняется автоматом модуля сканирования непосредственно перед передачей сообщения MSG_KEY_PRESSED и доступен для получателя по вызову функции GetKeyCode. Такой способ передачи параметров прост, но можно и передавать параметры непосредственно вместе с сообщениями. Все, что для этого нужно: заменить в вышеприведенном модуле messages.c строку

на:

где MSG_DATA может быть определено, например, как:

и, соответственно, скорректировать функции InitMessages, SendMessage, ProcessMessages, GetMessage.

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

У внимательного читателя может возникнуть следующий вопрос: как сообщения передаются в главный цикл программы из обработчиков прерываний? Не могут ли при этом возникать какие-либо коллизии? С обсуждения этого вопроса мы начнем следующую статью.

Продолжение статьи.

xosotin chelseathông tin chuyển nhượngcâu lạc bộ bóng đá arsenalbóng đá atalantabundesligacầu thủ haalandUEFAevertonxosofutebol ao vivofutemaxmulticanaisonbetbóng đá world cupbóng đá inter milantin juventusbenzemala ligaclb leicester cityMUman citymessi lionelsalahnapolineymarpsgronaldoserie atottenhamvalenciaAS ROMALeverkusenac milanmbappenapolinewcastleaston villaliverpoolfa cupreal madridpremier leagueAjaxbao bong da247EPLbarcelonabournemouthaff cupasean footballbên lề sân cỏbáo bóng đá mớibóng đá cúp thế giớitin bóng đá ViệtUEFAbáo bóng đá việt namHuyền thoại bóng đágiải ngoại hạng anhSeagametap chi bong da the gioitin bong da lutrận đấu hôm nayviệt nam bóng đátin nong bong daBóng đá nữthể thao 7m24h bóng đábóng đá hôm naythe thao ngoai hang anhtin nhanh bóng đáphòng thay đồ bóng đábóng đá phủikèo nhà cái onbetbóng đá lu 2thông tin phòng thay đồthe thao vuaapp đánh lô đềdudoanxosoxổ số giải đặc biệthôm nay xổ sốkèo đẹp hôm nayketquaxosokq xskqxsmnsoi cầu ba miềnsoi cau thong kesxkt hôm naythế giới xổ sốxổ số 24hxo.soxoso3mienxo so ba mienxoso dac bietxosodientoanxổ số dự đoánvé số chiều xổxoso ket quaxosokienthietxoso kq hôm nayxoso ktxổ số megaxổ số mới nhất hôm nayxoso truc tiepxoso ViệtSX3MIENxs dự đoánxs mien bac hom nayxs miên namxsmientrungxsmn thu 7con số may mắn hôm nayKQXS 3 miền Bắc Trung Nam Nhanhdự đoán xổ số 3 miềndò vé sốdu doan xo so hom nayket qua xo xoket qua xo so.vntrúng thưởng xo sokq xoso trực tiếpket qua xskqxs 247số miền nams0x0 mienbacxosobamien hôm naysố đẹp hôm naysố đẹp trực tuyếnnuôi số đẹpxo so hom quaxoso ketquaxstruc tiep hom nayxổ số kiến thiết trực tiếpxổ số kq hôm nayso xo kq trực tuyenkết quả xổ số miền bắc trực tiếpxo so miền namxổ số miền nam trực tiếptrực tiếp xổ số hôm nayket wa xsKQ XOSOxoso onlinexo so truc tiep hom nayxsttso mien bac trong ngàyKQXS3Msố so mien bacdu doan xo so onlinedu doan cau loxổ số kenokqxs vnKQXOSOKQXS hôm naytrực tiếp kết quả xổ số ba miềncap lo dep nhat hom naysoi cầu chuẩn hôm nayso ket qua xo soXem kết quả xổ số nhanh nhấtSX3MIENXSMB chủ nhậtKQXSMNkết quả mở giải trực tuyếnGiờ vàng chốt số OnlineĐánh Đề Con Gìdò số miền namdò vé số hôm nayso mo so debach thủ lô đẹp nhất hôm naycầu đề hôm naykết quả xổ số kiến thiết toàn quốccau dep 88xsmb rong bach kimket qua xs 2023dự đoán xổ số hàng ngàyBạch thủ đề miền BắcSoi Cầu MB thần tàisoi cau vip 247soi cầu tốtsoi cầu miễn phísoi cau mb vipxsmb hom nayxs vietlottxsmn hôm naycầu lô đẹpthống kê lô kép xổ số miền Bắcquay thử xsmnxổ số thần tàiQuay thử XSMTxổ số chiều nayxo so mien nam hom nayweb đánh lô đề trực tuyến uy tínKQXS hôm nayxsmb ngày hôm nayXSMT chủ nhậtxổ số Power 6/55KQXS A trúng roycao thủ chốt sốbảng xổ số đặc biệtsoi cầu 247 vipsoi cầu wap 666Soi cầu miễn phí 888 VIPSoi Cau Chuan MBđộc thủ desố miền bắcthần tài cho sốKết quả xổ số thần tàiXem trực tiếp xổ sốXIN SỐ THẦN TÀI THỔ ĐỊACầu lô số đẹplô đẹp vip 24hsoi cầu miễn phí 888xổ số kiến thiết chiều nayXSMN thứ 7 hàng tuầnKết quả Xổ số Hồ Chí Minhnhà cái xổ số Việt NamXổ Số Đại PhátXổ số mới nhất Hôm Nayso xo mb hom nayxxmb88quay thu mbXo so Minh ChinhXS Minh Ngọc trực tiếp hôm nayXSMN 88XSTDxs than taixổ số UY TIN NHẤTxs vietlott 88SOI CẦU SIÊU CHUẨNSoiCauVietlô đẹp hôm nay vipket qua so xo hom naykqxsmb 30 ngàydự đoán xổ số 3 miềnSoi cầu 3 càng chuẩn xácbạch thủ lônuoi lo chuanbắt lô chuẩn theo ngàykq xo-solô 3 càngnuôi lô đề siêu vipcầu Lô Xiên XSMBđề về bao nhiêuSoi cầu x3xổ số kiến thiết ngày hôm nayquay thử xsmttruc tiep kết quả sxmntrực tiếp miền bắckết quả xổ số chấm vnbảng xs đặc biệt năm 2023soi cau xsmbxổ số hà nội hôm naysxmtxsmt hôm nayxs truc tiep mbketqua xo so onlinekqxs onlinexo số hôm nayXS3MTin xs hôm nayxsmn thu2XSMN hom nayxổ số miền bắc trực tiếp hôm naySO XOxsmbsxmn hôm nay188betlink188 xo sosoi cầu vip 88lô tô việtsoi lô việtXS247xs ba miềnchốt lô đẹp nhất hôm naychốt số xsmbCHƠI LÔ TÔsoi cau mn hom naychốt lô chuẩndu doan sxmtdự đoán xổ số onlinerồng bạch kim chốt 3 càng miễn phí hôm naythống kê lô gan miền bắcdàn đề lôCầu Kèo Đặc Biệtchốt cầu may mắnkết quả xổ số miền bắc hômSoi cầu vàng 777thẻ bài onlinedu doan mn 888soi cầu miền nam vipsoi cầu mt vipdàn de hôm nay7 cao thủ chốt sốsoi cau mien phi 7777 cao thủ chốt số nức tiếng3 càng miền bắcrồng bạch kim 777dàn de bất bạion newsddxsmn188betw88w88789bettf88sin88suvipsunwintf88five8812betsv88vn88Top 10 nhà cái uy tínsky88iwinlucky88nhacaisin88oxbetm88vn88w88789betiwinf8betrio66rio66lucky88oxbetvn88188bet789betMay-88five88one88sin88bk88xbetoxbetMU88188BETSV88RIO66ONBET88188betM88M88SV88Jun-68Jun-88one88iwinv9betw388OXBETw388w388onbetonbetonbetonbet88onbet88onbet88onbet88onbetonbetonbetonbetqh88mu88Nhà cái uy tínpog79vp777vp777vipbetvipbetuk88uk88typhu88typhu88tk88tk88sm66sm66me88me888live8live8livesm66me88win798livesm66me88win79pog79pog79vp777vp777uk88uk88tk88tk88luck8luck8kingbet86kingbet86k188k188hr99hr99123b8xbetvnvipbetsv66zbettaisunwin-vntyphu88vn138vwinvwinvi68ee881xbetrio66zbetvn138i9betvipfi88clubcf68onbet88ee88typhu88onbetonbetkhuyenmai12bet-moblie12betmoblietaimienphi247vi68clupcf68clupvipbeti9betqh88onb123onbefsoi cầunổ hũbắn cáđá gàđá gàgame bàicasinosoi cầuxóc đĩagame bàigiải mã giấc mơbầu cuaslot gamecasinonổ hủdàn đềBắn cácasinodàn đềnổ hũtài xỉuslot gamecasinobắn cáđá gàgame bàithể thaogame bàisoi cầukqsssoi cầucờ tướngbắn cágame bàixóc đĩaAG百家乐AG百家乐AG真人AG真人爱游戏华体会华体会im体育kok体育开云体育开云体育开云体育乐鱼体育乐鱼体育欧宝体育ob体育亚博体育亚博体育亚博体育亚博体育亚博体育亚博体育开云体育开云体育棋牌棋牌沙巴体育买球平台新葡京娱乐开云体育mu88qh88
Литература
  1. Программирование для Windows 95; 2 т. СПб.: BHV — Санкт-Петербург, 1997.
  2. MicroC/OS II: The Real Time Kernel. Jean J. Labrosse, CMP Books, 2002.
  3. Get by Without an RTOS. Michael Melkonian.// Embedded System Programming, 2000, vol. 13, N 10.
  4. Гуисов М. И., Кузнецов А. Б., Шалыто А. А. Интеграция механизма обмена сообщениями в Switch-технологию. СПб.. 2003.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *