устройство последовательного порта, команды, ответы и C#

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

Пишу фотоакустический сканер. Приложение, которое позволит создавать тепловые изображения.

Я использую USB-устройство для управления более крутыми двигателями и устройство National Instruments для получения сигнала.

Мое приложение управляет двумя шаговыми двигателями (оно должно управлять).

У меня есть встроенный USB-контроллер для управления этими двигателями, он виден в системе как COM-устройство. Я могу управлять им с помощью гипертерминала и простого приложения, поэтому связь не является проблемой.

У меня проблема с созданием двусторонней связи между устройством и моим приложением.

Я отправляю строки на устройство следующим образом:

serial.Write("CAL\r"); - это калибрует устройство. Но он может вернуть два ответа — «CAL OK» или «BUSY» — калибровка в порядке или устройство сейчас делает что-то еще.

Я могу прослушивать событие DataRecived на последовательном порту, а затем выполнять string.equals.

Мое приложение должно управлять двигателями и ждать ответа.

В простом сценарии:

  1. Запустить приложение
  2. Используя входы, введите размер образца, который будет сканироваться.
  3. Нажмите кнопку контура - приложение начнет перемещать моторы сначала в левый верхний угол, затем в правый верхний, правый нижний и левый нижний угол. (Я могу отправить простую команду, но как отправить одну, дождаться ответа, затем отправить другую и после четвертой включить кнопки в графическом интерфейсе?)
  4. Если регион определен правильно, нажмите «Далее» и начнется сканирование.
  5. Моторы перемещаются в точку 1,1 (назовем ее так) и начинается сбор сигнала.
  6. Собранные данные обрабатываются и затем мы переходим к пункту 1,2
  7. Вся область завершена, и пользователь получает сообщение о том, что сканирование завершено.

Я не знаю, как начать с этого последовательного порта. Как реализовать двустороннюю связь.

У меня есть простой класс (singleton), который открывает com-порт, отправляет команды и имеет событие, которое возникает при каждых полученных данных.

Было бы хорошим решением создать стек в моем классе и отправить в него все команды, а затем в цикле взять их и отправить на устройство?

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

Буду благодарен за любой совет.

Я редактирую это, чтобы показать, как мое приложение должно выглядеть/работать

У меня есть простое приложение, в котором есть TabControl (модифицированная версия, которая скрывает вкладки в приложении, я вижу их только в режиме конструктора).

Первая вкладка содержит текст и информацию (в основном, статистику). Второй позволяет приобретение.

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

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

Попробую проиллюстрировать свою мысль схемой или скриншотом.


person Misiu    schedule 28.01.2012    source источник
comment
По сути, это проблема асинхронного программирования. Устройство, которым вы управляете, ведет себя крайне асинхронно не только из-за последовательного порта. Он принимает команду и делает свое дело, часто на выполнение работы уходит несколько секунд. Фундаментальной программной моделью для описания этого поведения является машина состояний.   -  person Hans Passant    schedule 28.01.2012
comment
Спасибо Ганс за ответ. Я читаю о государственной машине прямо сейчас. Не могли бы вы показать/написать пример того, как сделать конечный автомат с последовательным портом? Должен ли конечный автомат быть реализован во всем приложении или только в моем классе, который управляет моим устройством?   -  person Misiu    schedule 28.01.2012
comment
Обычно все приложение. Просто используйте целое число, чтобы отслеживать состояние. 0 = бездействие, 1 = калибровка и т.д. Вы переходите от 0 к 1 при отправке команды CAL. Вернуться к 0, когда вы получите DONE. Вы проверяете состояние повсюду в своем коде. Вы не можете разрешить пользователю нажимать кнопку «Калибровать», если, например, состояние не равно 0. Может потребоваться дополнительное состояние, например, другое, указывающее «Калибровка». Таким образом, вы можете запретить измерение до выполнения калибровки.   -  person Hans Passant    schedule 28.01.2012
comment
Я отредактировал свой вопрос, потому что мой комментарий был слишком длинным :)   -  person Misiu    schedule 28.01.2012
comment
Это просто еще один конечный автомат, состояние которого увеличивается мотором в зависимости от положения контроллера.   -  person Hans Passant    schedule 28.01.2012
comment
Но как это реализовать в моем случае? Буду очень благодарен за совет. Сейчас я создаю свой класс, который управляет шаговыми двигателями. Но, может быть, мне стоит начать с этих состояний. Какие-нибудь фрагменты, пожалуйста? :)   -  person Misiu    schedule 28.01.2012
comment
ответ Джульетты в другом вопросе - хорошее место для начала изучения конечных автоматов в C#. Поскольку приложение WinForms уже очень ориентировано на события, вы можете использовать события (щелчки управления, последовательный порт DataRecieved, BeginInvoke из потока обработки данных, если ваша обработка займет некоторое время) для управления конечным автоматом. На самом деле вам не нужно использовать поток в этом случае для обработки конечного автомата.   -  person tinman    schedule 28.01.2012
comment
Я понимаю ответ Джульетты, но в моем случае, если у меня есть 12 команд и 4 ответа, это дает мне много состояний и переходов состояний. И конечно же 3 или 4 просмотра в моем приложении. КСТАТИ. Как обрабатывать конечный автомат в winforms? Допустим, как сделать простую форму с кнопкой, которая будет вызывать команду на моем устройстве, и когда это будет сделано, она активирует вторую кнопку. Не могли бы вы написать мне образец?   -  person Misiu    schedule 28.01.2012