Работа с COM портом на C++ в Windows

Последовательные порты полюбились разработчикам за их простоту в обслуживании и использовании.

И конечно же писать в консоль терминальной программы это всё хорошо, но хочеться своё приложение, которое по нажатии клавиши на экране выполняет нужные вам действия ;)

В этой статье опишу как работать с com портом на языке Си++.

Решение простое, но почемуто рабочий пример найден был не сразу. За сим сохраняю его тут.

Конечно вы можете использовать кроссплатформенные решения вроде QSerial - библиотеки в составе Qt, я наверное так и сделаю, но в будующем. Сейчас же речь о "чистом" виндовском C++. Писать будем в Visual Studio. У меня 2010, хотя роли это никакой не играет...

Создаём новый консольный Win32 проект.

Инклудим header файлы:

#include <windows.h>
#include <iostream>
using namespace std;

Объявляем обработчик com порта:

HANDLE hSerial;

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

Дальше начинаем формировать функцию main:

int _tmain(int argc, _TCHAR* argv[])
{

Терпеть не могу виндовский стиль программирования. Обозвали всё посвоему и сидят радуются...

Теперь магия объявления строки с именем порта. Дело в том, что char оно преобразовывать само не умеет.

LPCTSTR sPortName = L"COM1";  

Работа с последоавательными портами в Windows проходит как с файлом. Открываем первый ком порт для записи/чтения:

hSerial = ::CreateFile(sPortName,GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

Проверяем работоспособность:

if(hSerial==INVALID_HANDLE_VALUE)
{
		if(GetLastError()==ERROR_FILE_NOT_FOUND)
	{
		cout << "serial port does not exist.\n";
	}
	cout << "some other error occurred.\n";
}

Теперь нужно настроить параметры соединения:

DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams))
{
	cout << "getting state error\n";
}
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=8;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=NOPARITY;
if(!SetCommState(hSerial, &dcbSerialParams))
{
	cout << "error setting serial port state\n";
}

На msdn советуют сначала получить параметры, а затем менять их. Мы ещё только учимся, поэтому делаем как просят.

Теперь объявим строку, которую будем передавать и переменные необходимые для этого:

char data[] = "Hello from C++";  // строка для передачи
DWORD dwSize = sizeof(data);   // размер этой строки
DWORD dwBytesWritten;    // тут будет количество собственно переданных байт

Посылаем строку. Напомню, что пример простейший, поэтому никаких особо проверок я не делаю:

BOOL iRet = WriteFile (hSerial,data,dwSize,&dwBytesWritten,NULL);

Также я решил вывести для контроля размер строки и количество отосланных байт:

cout << dwSize << " Bytes in string. " << dwBytesWritten << " Bytes sended. " << endl;

В конце программы делаем бесконечный цикл чтения данных:

	while(1)
	{
		ReadCOM();
	}
	return 0;
}

Теперь функция чтения:

void ReadCOM()
{
      DWORD iSize;
      char sReceivedChar;
      while (true)
      {
            ReadFile(hSerial, &sReceivedChar, 1, &iSize, 0);  // получаем 1 байт
			if (iSize > 0)   // если что-то принято, выводим
				cout << sReceivedChar;
      }
}

Вот собственно и весь пример.

Я создал виртуальный com порт. И слал из COM1 в COM2:

Демонстрация работы c COM портом на С++

Из нашей программы было отправлено "Hello from C++", а из терминала "hello how2.org.ua".

Скачать пример.

Просмотров:   70160