Современные технологии автоматизации» («СТА») —  журнал для квалифицированных специалистов по промышленной автоматизации Форум СТА — современные технологии автоматизации Домашняя страница
Домашняя страница форума CTA Домашняя страница форума CTA > II. АСУТП и SCADA > Программное обеспечение
  Активные темы Активные темы
  FAQ FAQ  Искать в форуме   Зарегистрироваться Зарегистрироваться  Вход в систему Вход в систему

Обращение к com порту

 Ответить Ответить Страница  <123>
Автор
Сообщение
Arm Смотреть выпадающим
Новичок
Новичок
Аватар

Присоединился: 23 Январь 2010
Online Status: Offline
Публикации: 27
Свойства публикации Свойства публикации   Ответить, цитируя автора - Arm Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Тема сообщения: Обращение к com порту
    Опубликовано: 15 Июль 2010 10:02
#include <vcl.h>
#pragma hdrstop
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include "Unit1.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

#define BUFSIZE 255 //ёмкость буфера

unsigned char bufrd[BUFSIZE], bufwr[BUFSIZE];

//---------------------------------------------------------------------------

HANDLE COMport;

/OVERLAPPED overlapped;
OVERLAPPED overlappedwr;
//---------------------------------------------------------------------------

int handle;

//---------------------------------------------------------------------------

bool fl=0;

unsigned long counter;
//---------------------------------------------------------------------------
void COMOpen(void);
void COMClose(void);

//=============================================================================
//.............................. объявления потоков ...........................
//=============================================================================

//---------------------------------------------------------------------------

//поток для чтения последовательности байтов из COM-порта в буфер
class ReadThread : public TThread
{
private:
void __fastcall Printing(); //вывод принятых байтов на экран и в файл
protected:
void __fastcall Execute(); //основная функция потока
public:
__fastcall ReadThread(bool CreateSuspended); //конструктор потока
};

//---------------------------------------------------------------------------

//поток для записи последовательности байтов из буфера в COM-порт
class WriteThread : public TThread
{
private:
void __fastcall Printing(); //вывод состояния на экран
protected:
void __fastcall Execute(); //основная функция потока
public:
__fastcall WriteThread(bool CreateSuspended); //конструктор потока
};

/*---------------------------Поток чтения с порта-----------------------------*/

ReadThread *reader;

//---------------------------------------------------------------------------

__fastcall ReadThread::ReadThread(bool CreateSuspended) : TThread(CreateSuspended)
{}
void __fastcall ReadThread::Execute()
{
COMSTAT comstat;
DWORD btr, temp, mask, signal;

overlapped.hEvent = CreateEvent(NULL, true, true, NULL);
SetCommMask(COMport, EV_RXCHAR);
while(!Terminated) //пока поток не будет прерван, выполняем цикл
{
WaitCommEvent(COMport, &mask, &overlapped);
signal = WaitForSingleObject(overlapped.hEvent, INFINITE);
if(signal == WAIT_OBJECT_0)
{
if(GetOverlappedResult(COMport, &overlapped, &temp, true))
if((mask & EV_RXCHAR)!=0)
{
ClearCommError(COMport, &temp, &comstat);
btr = comstat.cbInQue;
if(btr)
{
ReadFile(COMport, bufrd, btr, &temp, &overlapped);
counter+=btr;
Synchronize(Printing);
}
}
}
}
CloseHandle(overlapped.hEvent); /*перед выходом из потока закрыть объект-событие*/
}

//---------------------------------------------------------------------------


void __fastcall ReadThread::Printing()
{

Form1->Memo1->Lines->Add((char*)bufrd); //выводим принятую строку в Memo
/* Form1->StatusBar1->Panels->Items[2]->Text = "Всего принято " + IntToStr(counter) + " байт"; //выводим счётчик в строке состояния*/

if(Form1->CheckBox3->Checked == true) //если включен режим вывода в файл
{
write(handle, bufrd, strlen(bufrd)); //записать в файл данные из приёмного буфера
}
memset(bufrd, 0, BUFSIZE);
}

WriteThread *writer;

/*--------------------------поток записи данных в порт-------------------------*/


__fastcall WriteThread::WriteThread(bool CreateSuspended) : TThread(CreateSuspended)
{}

//---------------------------------------------------------------------------


void __fastcall WriteThread::Execute()
{
DWORD temp, signal;

overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL); //создать событие
WriteFile(COMport, bufwr, strlen(bufwr), &temp, &overlappedwr); //записать байты в порт
signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE);
if((signal == WAIT_OBJECT_0) && (GetOverlappedResult(COMport, &overlappedwr, &temp, true))) fl = true;
else fl = false;
Synchronize(Printing);
CloseHandle(overlappedwr.hEvent); //перед выходом из потока закрыть объект-событие
}

//---------------------------------------------------------------------------

//вывод состояния передачи данных на экран
void __fastcall WriteThread::Printing()
{
if(!fl) //проверяем состояние флажка
{
Form1->StatusBar1->Panels->Items[0]->Text = "Ошибка передачи";
return;
}
Form1->StatusBar1->Panels->Items[0]->Text = "Передача прошла успешно";
}

///////////////////////////////////////////////////////////////////////////////
/// форма ///
///////////////////////////////////////////////////////////////////////////////

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
//инициализация элементов формы при запуске программы
Form1->Label5->Enabled = false;
Form1->Label6->Enabled = false;
Form1->Button1->Enabled = false;
Form1->CheckBox1->Enabled = false;
Form1->CheckBox2->Enabled = false;
}

//---------------------------------------------------------------------------

//обработчик нажатия на кнопку "Открыть порт"
void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
{
if(SpeedButton1->Down)
{
COMOpen();

Form1->ComboBox1->Enabled = false;
Form1->ComboBox2->Enabled = false;
Form1->Button1->Enabled = true;
Form1->CheckBox1->Enabled = true;
Form1->CheckBox2->Enabled = true;

Form1->SpeedButton1->Caption = "Закрыть порт";
counter = 0;
Form1->CheckBox1Click(Sender);
Form1->CheckBox2Click(Sender);
}

else
{
COMClose();
Form1->SpeedButton1->Caption = "Открыть порт";
Form1->StatusBar1->Panels->Items[0]->Text = ""; //очистить первую колонку строки состояния
Form1->ComboBox1->Enabled = true;
Form1->ComboBox2->Enabled = true;
Form1->Button1->Enabled = false;
Form1->CheckBox1->Enabled = false;
Form1->CheckBox2->Enabled = false;
}
}

//---------------------------------------------------------------------------

//обработчик закрытия формы
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if(reader)reader->Terminate(); //завершить поток чтения из порта, проверка if(reader) обязательна, иначе возникают ошибки
if(writer)writer->Terminate(); //завершить поток записи в порт, проверка if(writer) обязательна, иначе возникают ошибки
if(COMport)CloseHandle(COMport); //закрыть порт
if(handle)close(handle); //закрыть файл, в который велась запись принимаемых данных

}
//---------------------------------------------------------------------------

//галочка "Сохранить в файл"
void __fastcall TForm1::CheckBox3Click(TObject *Sender)
{
if(Form1->CheckBox3->Checked) //если галочка включена
{
//активировать соответствующие элементы на форме
Form1->Label5->Enabled = true;
Form1->Label6->Enabled = true;

//вывести индикатор записи в файл в строке состояния
Form1->StatusBar1->Panels->Items[1]->Text = "Вывод в файл!";
}

else //если галочка выключена
{
//отключить соответствующие элементы на форме
Form1->Label5->Enabled = false;
Form1->Label6->Enabled = false;

//убрать индикатор записи в файл из строки состояния
Form1->StatusBar1->Panels->Items[1]->Text = "";
}

}
//---------------------------------------------------------------------------

//кнопка "Передать"
void __fastcall TForm1::Button1Click(TObject *Sender)
{
memset(bufwr,0,BUFSIZE); //очистить программный передающий буфер, чтобы данные не накладывались друг на друга
PurgeComm(COMport, PURGE_TXCLEAR); //очистить передающий буфер порта
strcpy(bufwr,Form1->Edit1->Text.c_str()); //занести в программный передающий буфер строку из Edit1

writer = new WriteThread(false); //создать и активировать поток записи данных в порт
writer->FreeOnTerminate = true; //установить это свойство, чтобы поток автоматически уничтожался после завершения

}

//---------------------------------------------------------------------------

//кнопка "Очистить поле"
void __fastcall TForm1::Button3Click(TObject *Sender)
{
Form1->Memo1->Clear(); //очистить Memo1
}

//---------------------------------------------------------------------------

//галочка "DTR"
void __fastcall TForm1::CheckBox1Click(TObject *Sender)
{
//если установлена - установить линию DTR в единицу, иначе - в ноль
if(Form1->CheckBox1->Checked) EscapeCommFunction(COMport, SETDTR);
else EscapeCommFunction(COMport, CLRDTR);
}

//---------------------------------------------------------------------------

//галочка "RTS"
void __fastcall TForm1::CheckBox2Click(TObject *Sender)
{
//если установлена - установить линию RTS в единицу, иначе - в ноль
if(Form1->CheckBox2->Checked) EscapeCommFunction(COMport, SETRTS);
else EscapeCommFunction(COMport, CLRRTS);
}

//---------------------------------------------------------------------------

//=============================================================================
//........................... реализации функций ..............................
//=============================================================================

//---------------------------------------------------------------------------

//функция открытия и инициализации порта
void COMOpen()
{
String portname; //имя порта (например, "COM1", "COM2" и т.д.)
DCB dcb; //структура для общей инициализации порта DCB
COMMTIMEOUTS timeouts; //структура для установки таймаутов

portname = Form1->ComboBox1->Text; //получить имя выбранного порта


if(COMport == INVALID_HANDLE_VALUE) //если ошибка открытия порта
{
Form1->SpeedButton1->Down = false; //отжать кнопку
Form1->StatusBar1->Panels->Items[0]->Text = "Не удалось открыть порт"; //вывести сообщение в строке состояния
return;
}

//инициализация порта

dcb.DCBlength = sizeof(DCB); //в первое поле структуры DCB необходимо занести её длину, она будет использоваться функциями настройки порта для контроля корректности структуры

//считать структуру DCB из порта
if(!GetCommState(COMport, &dcb)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
{
COMClose();
Form1->StatusBar1->Panels->Items[0]->Text = "Не удалось считать DCB";
return;
}

//инициализация структуры DCB
dcb.BaudRate = StrToInt(Form1->ComboBox2->Text); //задаём скорость передачи 115200 бод
dcb.fBinary = TRUE; //включаем двоичный режим обмена
dcb.fOutxCtsFlow = FALSE; //выключаем режим слежения за сигналом CTS
dcb.fOutxDsrFlow = FALSE; //выключаем режим слежения за сигналом DSR
dcb.fDtrControl = DTR_CONTROL_DISABLE; //отключаем использование линии DTR
dcb.fDsrSensitivity = FALSE; //отключаем восприимчивость драйвера к состоянию линии DSR
dcb.fNull = FALSE; //разрешить приём нулевых байтов
dcb.fRtsControl = RTS_CONTROL_DISABLE; //отключаем использование линии RTS
dcb.fAbortOnError = FALSE; //отключаем остановку всех операций чтения/записи при ошибке
dcb.ByteSize = 8; //задаём 8 бит в байте
dcb.Parity = 0; //отключаем проверку чётности
dcb.StopBits = 0; //задаём один стоп-бит

//загрузить структуру DCB в порт
if(!SetCommState(COMport, &dcb)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
{
COMClose();
Form1->StatusBar1->Panels->Items[0]->Text = "Не удалось установить DCB";
return;
}

//установить таймауты
timeouts.ReadIntervalTimeout = 0; //таймаут между двумя символами
timeouts.ReadTotalTimeoutMultiplier = 0; //общий таймаут операции чтения
timeouts.ReadTotalTimeoutConstant = 0; //константа для общего таймаута операции чтения
timeouts.WriteTotalTimeoutMultiplier = 0; //общий таймаут операции записи
timeouts.WriteTotalTimeoutConstant = 0; //константа для общего таймаута операции записи

//записать структуру таймаутов в порт
if(!SetCommTimeouts(COMport, &timeouts)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
{
COMClose();
Form1->StatusBar1->Panels->Items[0]->Text = "Не удалось установить тайм-ауты";
return;
}

//установить размеры очередей приёма и передачи
SetupComm(COMport,2000,2000);

//создать или открыть существующий файл для записи принимаемых данных
handle = open("test.txt", O_CREAT | O_APPEND | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE);

if(handle==-1) //если произошла ошибка открытия файла
{
Form1->StatusBar1->Panels->Items[1]->Text = "Ошибка открытия файла"; //вывести сообщение об этом в командной строке
Form1->Label6->Hide(); //спрятать надпись с именем файла
Form1->CheckBox3->Checked = false; //сбросить и отключить галочку
Form1->CheckBox3->Enabled = false;
}
else { Form1->StatusBar1->Panels->Items[0]->Text = "Файл открыт успешно"; } //иначе вывести в строке состояния сообщение об успешном открытии файла

PurgeComm(COMport, PURGE_RXCLEAR); //очистить принимающий буфер порта

reader = new ReadThread(false); //создать и запустить поток чтения байтов
reader->FreeOnTerminate = true; //установить это свойство потока, чтобы он автоматически уничтожался после завершения

}

//---------------------------------------------------------------------------

//функция закрытия порта
void COMClose()
{
if(writer)writer->Terminate(); //если поток записи работает, завершить его;
if(reader)reader->Terminate(); //если поток чтения работает, завершить его;
CloseHandle(COMport); //закрыть порт
COMport=0; //обнулить переменную для дескриптора порта
close(handle); //закрыть файл для записи принимаемых данных
handle=0; //обнулить переменную для дескриптора файла
}

//---------------------------------------------------------------------------


Наверх
casey Смотреть выпадающим
Новичок
Новичок
Аватар

Присоединился: 19 Июль 2005
Категория: Ukraine
Online Status: Offline
Публикации: 39
Свойства публикации Свойства публикации   Ответить, цитируя автора - casey Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 15 Июль 2010 10:50
На первый взгляд в функции COMOpen() нет вызова CreateFile(....), но это видимо так скопировано просто. Скажи, а что происходит через 2 часа работы программы?
Наверх
Arm Смотреть выпадающим
Новичок
Новичок
Аватар

Присоединился: 23 Январь 2010
Online Status: Offline
Публикации: 27
Свойства публикации Свойства публикации   Ответить, цитируя автора - Arm Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 15 Июль 2010 10:57
Компьютер зависает или датчик сигнал перестает передовать
Наверх
casey Смотреть выпадающим
Новичок
Новичок
Аватар

Присоединился: 19 Июль 2005
Категория: Ukraine
Online Status: Offline
Публикации: 39
Свойства публикации Свойства публикации   Ответить, цитируя автора - casey Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 15 Июль 2010 11:31

Сделай так:

в функции WriteThread::Execute()
signal = WaitForSingleObject(overlappedwr.hEvent, 1000);
потому как возможно(лень искать) если strlen(bufwr)==0, то поток будет висеть вечно

то же самое в ReadThread::Execute()
signal = WaitForSingleObject(overlapped.hEvent, 1000);
потому как если датчик не ответит, то тоже получается поток-висяк.

Не знаю как для асинхронного режима, но длоя синхронного всегда таймауты я ставлю так:

timeouts.ReadIntervalTimeout = 0; //таймаут между двумя символами
timeouts.ReadTotalTimeoutMultiplier = 0; //общий таймаут операции чтения
timeouts.ReadTotalTimeoutConstant = 250; //константа для общего таймаута операции чтения
timeouts.WriteTotalTimeoutMultiplier = 0; //общий таймаут операции записи
timeouts.WriteTotalTimeoutConstant =250; //константа для общего таймаута операции записи

А вообще ты конечно пишешь слишком сложный код для такой простой задачи - чтобы записать 2 байта и прочитать 4
совсем не обязательно заморачиваться с асинхронным вводом/выводом, событиями и отдельными потоками для чтения и записи в порт


Наверх
Arm Смотреть выпадающим
Новичок
Новичок
Аватар

Присоединился: 23 Январь 2010
Online Status: Offline
Публикации: 27
Свойства публикации Свойства публикации   Ответить, цитируя автора - Arm Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 15 Июль 2010 12:01
Я проще некаких объяснений к доступу не нашел. Вообще мне потом надо все это дело зациклить. и чтобы работало хотябы 12 часов!Confused
Наверх
casey Смотреть выпадающим
Новичок
Новичок
Аватар

Присоединился: 19 Июль 2005
Категория: Ukraine
Online Status: Offline
Публикации: 39
Свойства публикации Свойства публикации   Ответить, цитируя автора - casey Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 15 Июль 2010 12:19

Хочешь я выложу программку в 10 раз проще, не виснущую, когда-то сделал для "общения" с не помню каким датчиком. Можно отправлять посылки и читать ответы в 16-ричном виде.


Наверх
Arm Смотреть выпадающим
Новичок
Новичок
Аватар

Присоединился: 23 Январь 2010
Online Status: Offline
Публикации: 27
Свойства публикации Свойства публикации   Ответить, цитируя автора - Arm Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 15 Июль 2010 12:21
Буду очень благодарен. Можешь даже скинуть ее на почту: carmogedon@mail.ru.
Наверх
casey Смотреть выпадающим
Новичок
Новичок
Аватар

Присоединился: 19 Июль 2005
Категория: Ukraine
Online Status: Offline
Публикации: 39
Свойства публикации Свойства публикации   Ответить, цитируя автора - casey Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 15 Июль 2010 12:24
Да я уже выложил тут http://casey.at.ua/load/com_port_read_write/1-1-0-1   . Может кому еще будет интересно.
Наверх
Zlatoust Смотреть выпадающим
Новичок
Новичок


Присоединился: 28 Декабрь 2009
Online Status: Offline
Публикации: 18
Свойства публикации Свойства публикации   Ответить, цитируя автора - Zlatoust Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 16 Июль 2010 11:52
2 часа - это много. А что происходит через 2 часа? Может дисковая память закончилась.
Можно перезапускать программу каждые 2 часа.

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

Присоединился: 23 Январь 2010
Online Status: Offline
Публикации: 27
Свойства публикации Свойства публикации   Ответить, цитируя автора - Arm Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 20 Июль 2010 10:42
Сбрось пожалуйста свой код посмотреть, а то я сделать не могу а сроки уже поджимают
Наверх
 Ответить Ответить Страница  <123>

Переход на форум Права доступа на форуме Смотреть выпадающим

Bulletin Board Software by Web Wiz Forums® version 9.64
Powered by Web Wiz Forums Free Express Edition
Copyright ©2001-2009 Web Wiz