Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab1-2.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
488 Кб
Скачать
☆

2.3. Програма роботи

Використовуючи одну з мов об’єктно-орієнтованого програмування (наприклад Builder чи Delphi) написати програму для прийому та передачі даних через СОМ-порт використовуючи потоки.

2.4. Обладнання та програмне забезпечення

2.4.1. Персональний комп’ютер.

2.4.2. Одна з мов об’єктно-орієнтованого програмування.

2.5. Порядок виконання роботи і опрацювання результатів Варіант 1 (Порядок виконання лабораторної роботи

на мові програмування С++ Builder)

Відриємо програму створену в минулому проекті. Для цього виконаємо команду File | Open, і в стандартному діалозі виберемо проект який створили минулого разу.

Створимо модуль для потоку. Для цього виберіть пункт меню File | New | Other для відкриття вікна створення нового модуля(рис.1).

Рис.1.Відкриття вікна створення нового модуля

Знайдіть у цьому вікні на вкладці New пункт Thread Object. Виділите його й натисніть кнопку ОК (рис2.).

Рис.2. Вибір пункта Thread Object

У результаті з'явиться вікно, показане на рис. 3. У цьому вікні потрібно вказати ім'я потоку який створюється . Назвемо потік - TReadThread.

Рис. 3. Задаєм ім'я потоку

В результаті Builder C++ автоматично згенерує 2 файли Unit2.cpp і Unit2.h . Переключатись між ними можна натискаючи на вкладки як показано на рисунку 4.

Рис.4. Вікно з текстом програми потоку

Збережемо дані файли зі стандартними іменами (Unit2.cpp і Unit2.h) і перейдемо до розгляду коду.

Перейдемо на вкладку Unit2.h і розглянемо код:

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

#ifndef Unit2H

#define Unit2H

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

#include <Classes.hpp>

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

class TReadThread : public TThread

{

private:

protected:

void __fastcall Execute();

public:

__fastcall TReadThread(bool CreateSuspended);

};

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

#endif

Перед нами клас TReadThread унаслідуваний від стандартного класа Tthread. Builder автоматично створив дві функції:

  1. __fastcall TReadThread(bool CreateSuspended); - це функція-конструктор, яка використовується при створення нового об’єкту класу, поки на неї не потрібно звертати увау, але до неї ще вернемся;

  2. void __fastcall Execute(); - в тілі данної функції ми прописуємо код який буде виконувати потік.

Перейдемо до розділу private і пропишемо змінні та методи:

DWORD dwRead;

BYTE Buf[1024];

void __fastcall DoRead(void);

Перейдемо тепер до файлу Unit2.cpp (права вкладка на рис4.) :

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

// Important: Methods and properties of objects in VCL can only be

// used in a method called using Synchronize, for example:

//

// Synchronize(UpdateCaption);

//

// where UpdateCaption could look like:

//

// void __fastcall TReadThread::UpdateCaption()

// {

// Form1->Caption = "Updated in a thread";

// }

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

__fastcall TReadThread::TReadThread(bool CreateSuspended)

: TThread(CreateSuspended)

{

}

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

void __fastcall TReadThread::Execute()

{

//---- Place thread code here ----

}

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

Перш за все нам неохідно підключити модуль форму основної програми, для цього необхідно написати #include “Unit1.h” одразу після #include “Unit2.h” (код виділений червоним шрифтом в наступному лісингу).

Всі рядки котрі розпочинаються з символу // закоментовані , тобто на них не звертаємо уваги. Поки нас цікавить функція Execute() (виділена ширним шрифтом). Як вже зазначалось вище, в тілі функції (між { } ) ми пишемо код, який буде виконувати наш потік (тобто вставимо сюди код який ми писали для кнопки «Зчитати з порту» на минулій лабораторній):

{

HANDLE hPort;

COMSTAT CommStat;

DWORD dwError;

DWORD dwRead;

OVERLAPPED OverRead;

int i;

AnsiString STR;

hPort = Form1->GetPortHandle();

if (!SetCommMask (hPort, EV_RXCHAR))

{

ShowMessage("ПОМИЛКА ВСТАНОВЛЕННЯ МАСКИ ПОРТУ");

};

OverRead.hEvent = CreateEvent(NULL, True, False, NULL);

if (OverRead.hEvent == Null)

{ShowMessage("Помилка при спробі зчитування порту");}

if(!ClearCommError(hPort,&dwError,&CommStat)) {

MessageBox(NULL,"Помилка очищення порта","Помилка",MB_ICONERROR);}

dwRead = CommStat.cbInQue;

if (dwRead > 0)

{

Buf = new BYTE[dwRead];

if (!ReadFile(hPort,Buf,dwRead,&dwRead,&OverRead))

{

MessageBox(NULL,"Помилка читання порта","Помилка",MB_ICONERROR);

}

// В chReadBuff знаходяться прочитані байти

// Далі йде обробка отриманих байтів

for(i=0; i<dwRead; ++i)

{

STR=STR+char(Buf[i]);/* IntToStr(short(Buf[i])) + " "; */

}

Synchronize(DoRead);

delete Buf;

}

В результаті файл Unit2.cpp буде виглядати наступним чином (код який потрібно дописати виділений жирним шрифтом):

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

#include <vcl.h>

#pragma hdrstop

#include "Unit2.h"

#include "Unit1.h"

#pragma package(smart_init)

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

// Important: Methods and properties of objects in VCL can only be

// used in a method called using Synchronize, for example:

//

// Synchronize(UpdateCaption);

//

// where UpdateCaption could look like:

//

// void __fastcall TReadThread::UpdateCaption()

// {

// Form1->Caption = "Updated in a thread";

// }

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

__fastcall TReadThread::TReadThread(bool CreateSuspended)

: TThread(CreateSuspended)

{

}

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

void __fastcall TReadThread::Execute()

{

HANDLE hPort;

COMSTAT CommStat;

DWORD dwError;

OVERLAPPED OverRead;

int i;

AnsiString STR;

FreeOnTerminate = true;

hPort = Form1->GetPortHandle();

if (!SetCommMask (hPort, EV_RXCHAR))

{

ShowMessage("ПОМИЛКА ВСТАНОВЛЕННЯ МАСКИ ПОРТУ");

};

OverRead.hEvent = CreateEvent(NULL, True, False, NULL);

if (OverRead.hEvent == Null)

{ShowMessage("Помилка при спробі зчитування порту");}

if(!ClearCommError(hPort,&dwError,&CommStat)) {

MessageBox(NULL,"Помилка очищення порта","Помилка",MB_ICONERROR);}

dwRead = CommStat.cbInQue;

if (dwRead > 0)

{

Buf = new BYTE[dwRead];

if (!ReadFile(hPort,Buf,dwRead,&dwRead,&OverRead))

{

MessageBox(NULL,"Помилка читання порта","Помилка",MB_ICONERROR);

}

Synchronize(DoRead);

delete Buf;

}

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

Розглянемо детальніше потік.

FreeOnTerminate = true; - даний рядок означає, що об’єкт потоку, що знаходиться в оперативній пам’яті, буде самознищуватись (звільняти пам’ять) автоматично після завершення роцедури Execute() .

while (!this->Terminated) – даний рядок означає, що метод Execute() буде виконуватись до тих пір, поки в коді, який викликає потік, не зустрінеться інкапсульований наслідуваний метод класу Tthread – Terminate().

if (!ClearCommError(hPort, &dwError, &ComStat)) – якщо не виникне помилки очищення стану порта то функція ClearCommError заповняє поля структури COMSTAT в якій знаходиться інформація про стан порту, інакше – з’явиться вікно із повідомленням "Помилка очищення порта.".

dwRead = ComStat.cbInQue; - запам’ятовуєм кількість прочитаної інформації з порту.

if (dwRead > 0) – перевіряємо чи прийняли дані.

if (!ReadFile(hPort,Buf,dwRead,&dwRead,&OverRead)) – заповнюєм масив Buf інформацією яку отримали з порта.

Synchronize(DoRead); - для того, щоб керувати графічним інтерфейсом основної програми, наші дії необхідно синхронізувати з основним потоком, для цього використовуєм фунцію Synchronize , параметром якої є назва функції, з якої відбувається звертання до графічного інтерфейсу програми.

Нам залишилось тільки прописати функцію DoRead з якої будем управляти формою основної програми:

void __fastcall TReadThread::DoRead(void)

{

AnsiString STR;

for(int i=0; i<dwRead; ++i)

{

STR=STR+char(Buf[i]);/* IntToStr(short(Buf[i])) + " "; */

}

Form1->Memo1->Lines->Add(STR);

delete Buf;

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

Form1->Memo1->Lines->Add(STR) - даний рядок додає в поле Memo1 основної форми додає символ з масива Buf , в котрий ми записуємо дані отримані з порту.

На даному етапі робота з потоком звершена, перейдемо до основної програми.

Для підключення потоку до тіла основної програми виконаємо наступні дії:

1. Підключим модуль потуку до коду основної програми, та об’явимо об’єкт класу TReadThread як показано на рисунку 5:

Рис.5

2. Двічі клацнем по кнопці яка відповідає за «Зчитування з порту».

3. В кінці вікна яке відкриється напишемо наступний код

potik1 = new TReadThread(true);

potik1->Resume();

potik1->Priority = tpLower;

4. Для зупинки потоку клацнемо 2 рази по кнопці «Деініціалізація порту»

5. У відритому вікні напишемо слідуючий код:

potik1->Terminate();

6. Вкінці файлу Unit1.cpp допишемо:

HANDLE __fastcall TForm1::GetPortHandle(void)

{

return this->hPort;

}

7. У файлі Unit1.h у розділі оголошення public запишемо наступне

HANDLE __fastcall GetPortHandle(void);

Пояснення:

potik1 = new TReadThread(true); - створюємо новий об’єкт потоку.

potik1->Resume(); - запускаємо потік на виконання.

potik1->Terminate(); - зупинка та знищення потоку.

potik1->Priority = tpLower – задання приорітету для потоку.

Зберігаємо проект і запускаємо на виконання.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]