Вход

Регистрация
Главная
 

 

Пиротехнические пульты, пиротехническое оборудование
и пиротехника
Pyro Alex RF 48
Open Pyro SFX 8 D
Open Pyro SFX 10/120
Pyro Man 200 M
Spets 150
Приём заказов на изготовление пиротехнических пультов
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
Страница 1 из 11
Пиропульты - Электроника Форум » Электроника » Интеграция с ПК » Обработка событий COM-порта (Программирование COM порта на С)
Обработка событий COM-порта
alexval2007Дата: Суббота, 12.12.2009, 10:57 | Сообщение # 1
Электро воспламенитель
Группа: Администраторы
Сообщений: 662
Награды: 7
Репутация: 7
Статус: Offline
Обработка событий COM-порта

Умы всех начинающих программистов устройств сопряжения всегда будоражит вопрос обработки прерывания от портов. Например, в свое время, у меня желание обрабатывать прерывание LPT порта дошло до маниакального на вождения. В конце концов я достиг желаемого, хотя и не был полностью удовлетворен: в Windows XP время обработки этого прерывания от момента его физического возникновения в железе до его получения в пользовательском приложении проходит "целая вечность" (по сравнению с DOS, конечно). Все это вызвано огромным количеством "программной ваты" ("спасибо" парням из Microsoft), сквозь которую информация о прерывании должна к нам пробраться. При этом надо написать такое чудовище в виде драйвера, что у по началу волосы дыбом встают.

К счастью, для COM порта все гораздо проще и события (по сути прерывания) можно легко обрабатывать в пользовательском приложении. Например, вспомним предыдущую статью данного раздела. Для того чтобы мы могли узнать о том, что произошло изменение сигнала на линии CTS или DSR нам приходилось принудительно запускать функцию-обработчик. Наверное, было бы неплохо, чтобы программа сама отслеживала эти события. На практике это можно сделать двумя способами:

* с помощью таймера (периодический опрос состояния линий). Ход имеет право на жизнь, и например, для LPT порта он частенько и используется (скоро планирую написать об этом в разделе о LPT), но обладает недостатком - минимальный интервал опроса составляет всего 10-20 мс, а хотелось бы побыстрее.
* использование специализированных функций-обработчиков для COM порта, которыми мы сейчас и займемся.

Эта функция, а именно SetCommMask() указывает стандартному драйверу порта отслеживать определенные события. В нашем приложении мы сможем узнать о каждом случае возникновения события порта.

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

Далее создайте обработчик для этой кнопки и назовите его, например, OnStartWatch(). Добавьте в него следующий код:

void CTestCOMDlg::OnStartWatch()
{
// TODO: Add your control notification handler code here
SetCommMask(hFile, EV_CTS|EV_DSR);
AfxBeginThread(proc1,this);
}

Теперь каждый раз при нажатии на эту кнопку будет выполняться следующее: сначала с помощью функции SetCommMask() мы указываем драйверу, чтобы он отслеживал изменения на линиях CTS и DSR. Далее, по идее, надо бы было поставить вызов функции, которая ожидала бы пока произойдет событие, но так делать не рекомендуется: приложение просто зависнет, т.к. все отведенное процессорное время для нашего приложения будет уходить полностью на ожидание события. Поэтому далее, идет вызов создания программного потока. Первым параметром идет адрес специализированной функции, в контексте которой будет выполняться программный код потока. Второй параметр - дополнительный параметр; в данном случае, я передаю в эту функцию адрес текущего экземпляра диалога, чтобы функция могла обращаться к данным и функциям нашего класса диалога. Это делается потому что proc1() не является членом класса CTestCOMDlg. Давайте теперь объявим эту "загадочную " функцию. Для этого в самом верху файла TestCOMDlg.cpp запишите следующее:

UINT proc1( LPVOID pParam );

Тем самым, мы дали описание для этой функции. Теперь, в этом же файле давайте ее реализуем. Она должна выглядеть так:

UINT proc1(LPVOID pParam)
{
CTestCOMDlg* CTest = (CTestCOMDlg*)pParam;
ULONG lpEvtMask=0;
WaitCommEvent(CTest->hFile, &lpEvtMask, NULL);
CTest->OnRead();
MessageBox(NULL,"Произошло событие","Info",MB_OK);

return 0;
}

Что здесь происходит? Сначала восстанавливается адрес на класс диалога. Затем вызывается функция WaitCommEvent(), которая останавливает текущий поток, до тех пор, пока не произойдет заказанное драйверу событие. Как только оно происходит, надо бы узнать текущие состояние на линии. Для этого у нас есть готовая функция OnRead(). Но она обьявлена как private. Можно конечно, написать полный аналог OnRead() с атрибутом public, но для наших тестовых целей поступим иначе: просто изменим атрибут на public в описании класса (в файле TestCOMDlg.h).

.....................
// Implementation
protected:
HICON m_hIcon;
public: //измененный атрибут
// Generated message map functions
//{{AFX_MSG(CTestCOMDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnRead();
afx_msg void OnStartWatch();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

Все. Теперь, запускаем приложение. Убеждаемся в удачности открытия порта. Запускаем детектор событий порта с помощью кнопки StartWatch. Самое интересное: если теперь изменить состояние ключа, то выскочит сообщение образуемое функцией MessageBox() и в Edit-окошках появится значения линий, получаемые с помощью функции OnRead(). Что бы снова запустить отслеживание событий, опять запускаем функцию OnStartWatch() нажатием соответствующей кнопки.

Следует обратить внимание, что после первой обработки события при последующем запуске OnStartWatch() может возникнуть неприятная ситуация, заключающаяся в том, что ключ Вы не трогали, а событие будет обнаружено. Это связано с явлением "дребезга контактов". При замыкании механического ключа, контакт устанавливается или разрывается не сразу, а после некоторого количества промежуточных касаний проводников. Драйвер порта при этом зафиксирует несколько событий и при повтором запуске WaitCommEvent() событие уже якобы произошло.

Иванов Д. В.
20 декабря 2006 года
www.pcports.ru

 
Пиропульты - Электроника Форум » Электроника » Интеграция с ПК » Обработка событий COM-порта (Программирование COM порта на С)
Страница 1 из 11
Поиск:


Rambler's Top100 Пиротехника, салюты, фейерверки. Яндекс цитирования
www.alexval2007.ucoz.ru © 2008