//--------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #include #include #include #include //для работы с файлами #include //для работы с файлами #include //для работы с файлами #include "Unt1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //============================================================================= //..................... объявления глобальных переменных ...................... //============================================================================= #define BUFSIZE 255 //ёмкость буфера unsigned char bufrd[BUFSIZE], bufwr[BUFSIZE]; //приёмный и передающий буферы //--------------------------------------------------------------------------- HANDLE COMport; //дескриптор порта //структура OVERLAPPED необходима для асинхронных операций, при этом для операции чтения и записи нужно объявить разные структуры //эти структуры необходимо объявить глобально, иначе программа не будет работать правильно OVERLAPPED overlapped; //будем использовать для операций чтения (см. поток ReadThread) OVERLAPPED overlappedwr; //будем использовать для операций записи (см. поток WriteThread) //--------------------------------------------------------------------------- int handle; //дескриптор для работы с файлом с помощью библиотеки //--------------------------------------------------------------------------- bool fl=0; //флаг, указывающий на успешность операций записи (1 - успешно, 0 - не успешно) unsigned long counter; //счётчик принятых байтов, обнуляется при каждом открытии порта //============================================================================= //.............................. объявления функций ........................... //============================================================================= void COMOpen(void); //открыть порт void COMClose(void); //закрыть порт //============================================================================= //.............................. объявления потоков ........................... //============================================================================= HANDLE reader; //дескриптор потока чтения из порта HANDLE writer; //дескриптор потока записи в порт DWORD WINAPI ReadThread(LPVOID); DWORD WINAPI WriteThread(LPVOID); //----------------------------------------------------------------------------- //............................... поток ReadThead ............................. //----------------------------------------------------------------------------- void ReadPrinting(void); //--------------------------------------------------------------------------- //главная функция потока, реализует приём байтов из COM-порта DWORD WINAPI ReadThread(LPVOID) { COMSTAT comstat; //структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов DWORD btr, temp, mask, signal; //переменная temp используется в качестве заглушки overlapped.hEvent = CreateEvent(NULL, true, true, NULL); //создать сигнальный объект-событие для асинхронных операций SetCommMask(COMport, EV_RXCHAR); //установить маску на срабатывание по событию приёма байта в порт while(1) //пока поток не будет прерван, выполняем цикл { WaitCommEvent(COMport, &mask, &overlapped); //ожидать события приёма байта (это и есть перекрываемая операция) signal = WaitForSingleObject(overlapped.hEvent, INFINITE); //приостановить поток до прихода байта if(signal == WAIT_OBJECT_0) //если событие прихода байта произошло { if(GetOverlappedResult(COMport, &overlapped, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent if((mask & EV_RXCHAR)!=0) //если произошло именно событие прихода байта { ClearCommError(COMport, &temp, &comstat); //нужно заполнить структуру COMSTAT btr = comstat.cbInQue; //и получить из неё количество принятых байтов if(btr) //если действительно есть байты для чтения { ReadFile(COMport, bufrd, btr, &temp, &overlapped); //прочитать байты из порта в буфер программы counter+=btr; //увеличиваем счётчик байтов ReadPrinting(); //вызываем функцию для вывода данных на экран и в файл } } } } } //--------------------------------------------------------------------------- //выводим принятые байты на экран и в файл (если включено) void ReadPrinting() {AnsiString rez; Form1->Memo1->Clear(); Form1->Memo1->Lines->Add((char*)bufrd); //выводим принятую строку в Memo write(handle, bufrd, strlen(bufrd)); //записать в файл данные из приёмного буфера rez=Form1->Memo1->Lines[0][0]; /* if (rez>26100 && rez<26600) { Form1->Image1->Visible=true; Form1->Image3->Visible=true; Form1->Image5->Visible=true; } else if(rez>29500 && rez<30000) { Form1->Image1->Visible=false; Form1->Image2->Visible=true; Form1->Image5->Visible=true; } else if(rez>32000 && rez<32300) { Form1->Image1->Visible=true; Form1->Image4->Visible=true; Form1->Image3->Visible=false; Form1->Image5->Visible=true; } else if(rez>20200 && rez<21000) { Form1->Image1->Visible=true; Form1->Image2->Visible=true; Form1->Image5->Visible=false; Form1->Image6->Visible=true; } else if(rez>50 && rez<80) { Form1->Image1->Visible=true; Form1->Image3->Visible=false; Form1->Image4->Visible=true; Form1->Image5->Visible=false; Form1->Image6->Visible=true; } else if(rez>9500 && rez<9800) { Form1->Image1->Visible=false; Form1->Image2->Visible=true; Form1->Image3->Visible=true; Form1->Image5->Visible=false; Form1->Image6->Visible=true; } else if(rez>11500 && rez<11900) { Form1->Image1->Visible=false; Form1->Image2->Visible=true; Form1->Image3->Visible=false; Form1->Image4->Visible=true; Form1->Image5->Visible=false; Form1->Image6->Visible=true; } */ switch (rez[1]) { case 'a': ////// { Form1->Image1->Visible=true; Form1->Image2->Visible=false; Form1->Image3->Visible=true; Form1->Image4->Visible=false; Form1->Image5->Visible=true; Form1->Image6->Visible=false; break; } case 'b': /////// { Form1->Image1->Visible=false; Form1->Image2->Visible=true; Form1->Image3->Visible=true; Form1->Image4->Visible=false; Form1->Image5->Visible=true; Form1->Image6->Visible=false; break; } case 'c': { Form1->Image1->Visible=true; Form1->Image2->Visible=false; Form1->Image3->Visible=false; Form1->Image4->Visible=true; Form1->Image5->Visible=true; Form1->Image6->Visible=false; break; } case 'd': { Form1->Image1->Visible=true; Form1->Image2->Visible=false; Form1->Image3->Visible=true; Form1->Image4->Visible=false; Form1->Image5->Visible=false; Form1->Image6->Visible=true; break; } case 'e': { Form1->Image1->Visible=false; Form1->Image2->Visible=true; Form1->Image3->Visible=false; Form1->Image4->Visible=true; Form1->Image5->Visible=true; Form1->Image6->Visible=false; break; } case 'f': { Form1->Image1->Visible=false; Form1->Image2->Visible=true; Form1->Image3->Visible=true; Form1->Image4->Visible=false; Form1->Image5->Visible=false; Form1->Image6->Visible=true; break; } case 'g': { Form1->Image1->Visible=true; Form1->Image2->Visible=false; Form1->Image3->Visible=false; Form1->Image4->Visible=true; Form1->Image5->Visible=false; Form1->Image6->Visible=true; break; } case 'h': { Form1->Image1->Visible=false; Form1->Image2->Visible=true; Form1->Image3->Visible=false; Form1->Image4->Visible=true; Form1->Image5->Visible=false; Form1->Image6->Visible=true; break; } //else {ShowMessage('fgdfgdfg'); break;} } memset(bufrd, 0, BUFSIZE); //очистить буфер (чтобы данные не накладывались друг на друга) } //----------------------------------------------------------------------------- //............................... поток WriteThead ............................ //----------------------------------------------------------------------------- //--------------------------------------------------------------------------- //главная функция потока, выполняет передачу байтов из буфера в COM-порт DWORD WINAPI WriteThread(LPVOID) { DWORD temp, signal; //temp - переменная-заглушка overlappedwr.hEvent = CreateEvent(NULL, true, true, NULL); //создать событие while(1) {WriteFile(COMport, bufwr, strlen(bufwr), &temp, &overlappedwr); //записать байты в порт (перекрываемая операция!) signal = WaitForSingleObject(overlappedwr.hEvent, INFINITE); //приостановить поток, пока не завершится перекрываемая операция WriteFile SuspendThread(writer); } } //--------------------------------------------------------------------------- void COMOpen() { String portname; //имя порта (например, "COM1", "COM2" и т.д.) DCB dcb; //структура для общей инициализации порта DCB COMMTIMEOUTS timeouts; //структура для установки таймаутов portname = "COM2"; //получить имя выбранного порта //открыть порт, для асинхронных операций обязательно нужно указать флаг FILE_FLAG_OVERLAPPED COMport = CreateFile(portname.c_str(),GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); //здесь: // - portname.c_str() - имя порта в качестве имени файла, c_str() преобразует строку типа String в строку в виде массива типа char, иначе функция не примет // - GENERIC_READ | GENERIC_WRITE - доступ к порту на чтение/записть // - 0 - порт не может быть общедоступным (shared) // - NULL - дескриптор порта не наследуется, используется дескриптор безопасности по умолчанию // - OPEN_EXISTING - порт должен открываться как уже существующий файл // - FILE_FLAG_OVERLAPPED - этот флаг указывает на использование асинхронных операций // - NULL - указатель на файл шаблона не используется при работе с портами if(COMport == INVALID_HANDLE_VALUE) //если ошибка открытия порта { ShowMessage("Не удалось открыть порт"); return; } //инициализация порта dcb.DCBlength = sizeof(DCB); //в первое поле структуры DCB необходимо занести её длину, она будет использоваться функциями настройки порта для контроля корректности структуры //считать структуру DCB из порта if(!GetCommState(COMport, &dcb)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния { COMClose(); ShowMessage("Не удалось считать DCB"); return; } //инициализация структуры DCB dcb.BaudRate = 115200; //задаём скорость передачи 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(); ShowMessage("Не удалось установить DCB"); return; } //установить таймауты timeouts.ReadIntervalTimeout = 0; //таймаут между двумя символами timeouts.ReadTotalTimeoutMultiplier = 0; //общий таймаут операции чтения timeouts.ReadTotalTimeoutConstant = 0; //константа для общего таймаута операции чтения timeouts.WriteTotalTimeoutMultiplier = 0; //общий таймаут операции записи timeouts.WriteTotalTimeoutConstant = 0; //константа для общего таймаута операции записи //записать структуру таймаутов в порт if(!SetCommTimeouts(COMport, &timeouts)) //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния { COMClose(); return; } //установить размеры очередей приёма и передачи SetupComm(COMport,2000,2000); //создать или открыть существующий файл для записи принимаемых данных handle = open("test.txt", O_CREAT | O_APPEND | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE); PurgeComm(COMport, PURGE_RXCLEAR); //очистить принимающий буфер порта reader = CreateThread(NULL, 0, ReadThread, NULL, 0, NULL); //создаём поток чтения, который сразу начнёт выполняться (предпоследний параметр = 0) writer = CreateThread(NULL, 0, WriteThread, NULL, CREATE_SUSPENDED, NULL); //создаём поток записи в остановленном состоянии (предпоследний параметр = CREATE_SUSPENDED) } //--------------------------------------------------------------------------- //функция закрытия порта void COMClose() { //Примечание: так как при прерывании потоков, созданных с помощью функций WinAPI, функцией TerminateThread // поток может быть прерван жёстко, в любом месте своего выполнения, то освобождать дескриптор // сигнального объекта-события, находящегося в структуре типа OVERLAPPED, связанной с потоком, // следует не внутри кода потока, а отдельно, после вызова функции TerminateThread. // После чего нужно освободить и сам дескриптор потока. if(writer) //если поток записи работает, завершить его; проверка if(writer) обязательна, иначе возникают ошибки {TerminateThread(writer,0); CloseHandle(overlappedwr.hEvent); //нужно закрыть объект-событие CloseHandle(writer); } if(reader) //если поток чтения работает, завершить его; проверка if(reader) обязательна, иначе возникают ошибки {TerminateThread(reader,0); CloseHandle(overlapped.hEvent); //нужно закрыть объект-событие CloseHandle(reader); } CloseHandle(COMport); //закрыть порт COMport=0; //обнулить переменную для дескриптора порта close(handle); //закрыть файл, в который велась запись принимаемых данных handle=0; //обнулить переменную для дескриптора файла } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { int i; randomize; Image7->Visible=false; i=random(5); if (i==1) { Image1->Visible=false; Image2->Visible=true; sndPlaySound("td.wav", SND_SYNC); Image7->Visible=true; } else {Image1->Visible=true; Image2->Visible=false;} i=random(5); if (i==1) { Image3->Visible=false; Image4->Visible=true; sndPlaySound("td.wav", SND_SYNC); Image7->Visible=true; } else {Image3->Visible=true; Image4->Visible=false; } i=random(5); if (i==1) { Image5->Visible=false; Image6->Visible=true; sndPlaySound("td.wav", SND_SYNC); Image7->Visible=true; } else {Image5->Visible=true; Image6->Visible=false;} } //--------------------------------------------------------------------------- void __fastcall TForm1::Button3Click(TObject *Sender) { COMOpen(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button4Click(TObject *Sender) { COMClose(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button5Click(TObject *Sender) { memset(bufwr,0,BUFSIZE); //очистить программный передающий буфер, чтобы данные не накладывались друг на друга PurgeComm(COMport, PURGE_TXCLEAR); //очистить передающий буфер порта strcpy(bufwr,"q"); //занести в программный передающий буфер строку из Edit1 ResumeThread(writer); //активировать поток записи данных в порт } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { COMOpen(); memset(bufwr,0,BUFSIZE); //очистить программный передающий буфер, чтобы данные не накладывались друг на друга PurgeComm(COMport, PURGE_TXCLEAR); //очистить передающий буфер порта strcpy(bufwr,"q"); //занести в программный передающий буфер строку из Edit1 ResumeThread(writer); //активировать поток записи данных в порт COMClose(); } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void __fastcall TForm1::Button7Click(TObject *Sender) { Timer1->Enabled=true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button6Click(TObject *Sender) { Timer1->Enabled=false; } //---------------------------------------------------------------------------