Witam wszystkich w części drugiej. Na początek dziękuje wszystkim za miłe słowa oraz oddane głosy. Jak obiecywałem w części pierwszej dzisiaj zapoznamy się z kodem programu na komputer. Na wstępie pragnę jeszcze zaznaczyć, że nie jestem programistą ani zawodowo ani amatorsko. Napisany kod może zawierać błędy, lub pewnie można to zrobić w sposób bardziej elegancki oraz bardziej optymalnie. Bardzo mile widziana wszelaka konstruktywna krytyka :-)
Co nam będzie niezbędne:
- Komputer i kawa
- C++ Bulider w wersji 6 Personal
- Poskładany układ z części pierwszej
Aplikacja Bulider w wersji 6 Personal jest podlinkowana do blogu Pana Mirosława Zalent. Znajdująca się tam wersja jest gotowa do instalacji na komputerze. Jednocześnie serdecznie zapraszam na blog Pana Mirosława. Przygotowane kursy są kapitalne .
Aplikacja, która dzisiaj wspólnie przygotujemy umożliwi komunikowanie się przez port szeregowy z naszym układem. Oczywiście można by to samo osiągnąć wysyłając odpowiednio przygotowane komunikaty wpisywane w jakikolwiek program do komunikacji szeregowej (np wbudowany w Arduino IDE serial monitor). Rozwiązanie takie jest jednak strasznie nie eleganckie. My będziemy mieli program w wersji okienkowej.
W skład interfejsu programu wchodzić będą:
Samo rozmieszczeni elementów oczywiście jest dowolne. Nic nie stoi na przeszkodzie aby go dowolnie zmodyfikować do własnych potrzeb.
Komunikować się z naszym mC będziemy przez Winapi. Zaczynamy od dodania potrzebnych na bibliotek.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> //główna biblioteka wejścia.wyjścia #include <vcl.h> //Visual Component Library #include <windows.h>//środowisko Winapi #include <time.h>//biblioteka obsługująca czas np funkcję Sleep #include <fstream>//biblioteka do pracy z plikami #include <string>//biblioteka pozwalająca na obsługę napisów tekstowy (typ string) using namespace std; string port;//zmienna przechowująca nr portu który będziemy otwierać DCB dcb;//struktura dcb HANDLE hNumPort;// uchwyt do naszego portu char lpBuffor_read[13], lpBuffor_write[8];//tablice odczytu i odbioru danych DWORD RS_ile;//liczba faktycznie odebranych danych DWORD fdwEvtMask; |
Przy okazji zadeklarowaliśmy też zmienne potrzebne nam do pracy oraz strukturę DCB obsługującą port COM.
Aby zaoszczędzić wam sporo czasu omówię w tylko po jednym przycisku z grupy. Przyciski te robią dokładnie to samo zmienia się tylko kod IR, którego obsługą w danym momencie się zajmujemy.
Na sam start musimy się z naszym mC się połączyć. Wypadało więc by stworzyć blok konfiguracyjny gdzie będziemy mogli wybrać numer portu COM naszego urządzenia oraz prędkość jaką będziemy nadawać i odczytywać dane. Zdecydowałem się, na ukrycie blogu konfiguracji ponieważ będzie nam on potrzebny tylko raz. Wybieramy więc z menu File->New->Form. Należy także pamiętać żeby w kodzie programu załączyć nową formę(#include “Unit2.h”). Na nowej formie tworzymy dodajemy nowe elementy:
Pola wyboru ComboBox1 oraz ComboBox2 są na chwile obecną puste i trzeba by je wypełnić numerami portów COM oraz dostępnymi szybkościami połączeń. Można to zrobić albo w kodzie programu zaraz po utworzeniu nowej formy (FormCreate) lub w inspektorze obiektów. Ja w Form Create wpisałem po prostu ComboBox1->Items->Add(“COM1”); i tak dla każdego numeru portu COM oraz ComboBox2->Items->Add(“4800”); dla każdej możliwej szybkości.
Przycisk >> Powinien zapisać do pliku txt z ustawieniami nr portu oraz szybkość transmisji oraz w etykiecie Label3 oraz Label4 zapisać stosowne ustawiania. Kod przycisku poniżej:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void __fastcall TForm2::Button1Click(TObject *Sender) { if(ComboBox1->Items->Strings[ComboBox1->ItemIndex]!="" && ComboBox1->Items->Strings[ComboBox1->ItemIndex]!="")//jeżeli w polu ComboBox1/2 wybrano jakąś wartość to { nr_port=ComboBox1->Items->Strings[ComboBox1->ItemIndex].c_str();//do zmiennej nr_port zapisz wartość z pola ComboBox1 szybkosc=ComboBox2->Items->Strings[ComboBox2->ItemIndex].c_str();//do zmiennej szybkosc zapisz wartość z pola ComboBox2 Label3->Caption=ComboBox1->Items->Strings[ComboBox1->ItemIndex];//oraz podmień etykiety Label4->Caption=ComboBox2->Items->Strings[ComboBox2->ItemIndex];//oraz podmień etykiety fstream plik;//tworzy uchwyt do pliku plik.open("ust.txt",ios::out);//otwiera plik do zapisu i odczytu. Jeżeli pliku nie ma na dysku zostanie on utworzony plik << nr_port<<endl;//do pliku zostaje zapisana wartość zmiennej nr_port plik << szybkosc<<endl;// do pliku zostaje zapisana wartość zmiennej szybkosc plik.close();//!!! po zakończonym odczycie zapisie plik trzeba koniecznie zmknąć } else//jeżeli któryś Combobox był pusty program wyświetli nam info o tym ShowMessage("Może najpierw byś wybrał/a"); } |
No to mamy na dysku plik tekstowy z ustawieniami portu COM. Pora połączyć się po raz pierwszy z urządzaniem. Aplikacja po wybraniu przycisku połącz powinna sprawdzić czy na dysku znajduje się odpowiedni plik z ustawieniami. Jeśli plik udało się odczytać to pobrać z niego odpowiednie ustawienia a w przeciwnym wypadku otworzyć okienko z konfiguracją COM.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
void __fastcall TForm1::polaczClick(TObject *Sender) { unsigned long szybkosc;// nowa zmienna na szybkość połączenia string nr_port;// nowa zmienna na numer portu fstream plik;//uchwyt do pliku plik.open("ust.txt");//polecenia otwierające plik if(plik.good()==false)// jeżeli pliku nie ma na dysku lub jest on uszkodzony... { Form2->ShowModal();//...automatycznie otworzy się okienko z ustawieniami portu } else// jeżeli się udało { string linia;//zmienna przechowująca wczytane dane int nr_linii=1;// zmienna przełączająca numer wczytanej linii while(getline(plik,linia))//funkcja getline() sprawdza czy udało się wczytać linie { switch(nr_linii)//przełącza numer wczytywanej linii { case 1: nr_port=linia;//do zmiennej nr_port wczytujemy numer portu break; case 2: szybkosc=atoi(linia.c_str());//do zmiennej szybkosc wczytujemy szybkość połączenia. break; } nr_linii++; } } plik.close();//!!!pamiętamy żeby zamknąć otwarty plik hNumPort = CreateFile(nr_port.c_str(), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING,0, NULL);//tworzymy nowy uchwyt do odczytywania danych z portu COM. Zmienna nr portu określa o jaki numer nam chodzi. dcb.DCBlength = sizeof(dcb); GetCommState(hNumPort, &dcb); dcb.BaudRate = szybkosc;//szybkość transmisji dcb.ByteSize = 8;//Liczba bitów wysyłanych/odebranych danych dcb.Parity = NOPARITY;//parzystość dcb.StopBits = ONESTOPBIT;//jedn bit stopu dcb.fDtrControl = TRUE; SetCommState(hNumPort, &dcb); if(SetCommState(hNumPort, &dcb)==TRUE)//funkcja do sprawdzania czy udało nam się połączyć. Dobrze przed każdą próbą odebrania czy wysyłania danych sprawdzić czy możemy to robić { stan->Picture->LoadFromFile("img/online.bmp");//podmień obrazek z czerwonego na zielony polacz->Enabled=false;//parametr Enabled określa czy w przycisk możemy kliknąć czy nie. Nam się udało połączyć więc przycisk powinien się wyszarzyć rozlacz->Enabled=true;//włączenie przycisku off_all->Enabled=true;//włączenie przycisku eeprom->Enabled=true;//włączenie przycisku s_1->Enabled=true;//włączenie przycisku s_2->Enabled=true;//włączenie przycisku s_3->Enabled=true;//włączenie przycisku s_4->Enabled=true;//włączenie przycisku CheckBox1->Enabled=true;//włączenie boxa UstawieniaCOM1->Enabled=false;//nie można zmieniać parametrów transmisji w trakcie połączenia } else ShowMessage("Nie mogę połączy z COM. Sprawdź ustawienia portów");//info o nie udanym połączeniu } |
Należy pamiętać, że dane przychodzące z pliku tekstowego zawsze są traktowane jako tekst. Do zmiennej szybkość potrzebna nam liczba całkowita. Funkcja atoi zmienia ten tekst na liczbę.
Wszystko poszło dobrze i mamy już połączenia z portem COM. Jako, że wszystko co zostało otwarte należy później zamknąć. Osoba sumienna na pewno najpierw rozłączy port COM (przycisk rozłącz) później zamknie aplikację ja natomiast jestem leniwy i użyje do tego przycisku X(ten obok maksymalizuj) na belce programu. Trzeba będzie temu zaradzić. W inspektorze obiektów dla Form1 przełączamy się na zakładkę Events i z listy wybieramy (2xclic). W zdarzeniu wystarczy napisać if(SetCommState(hNumPort, &dcb)==TRUE) CloseHandle(hNumPort). Funkcja najpierw sprawdza czy port jest otwarty i jeśli tak zamyka go po czym włącza aplikację. Przy okazji tworzenia MainMenu opiszę jeszcze jak dodać zdarzenie do pozycji menu zamknij.
Więc tak do przycisku rozłącz dodajemy kod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void __fastcall TForm1::rozlaczClick(TObject *Sender) { CloseHandle(hNumPort);//zamyka port UstawieniaCOM1->Enabled=true;// włącza podmenu ustawienia com if(SetCommState(hNumPort, &dcb)==FALSE)// sprawda czy udało się zamknąć port { stan->Picture->LoadFromFile("img/offline.bmp");//zmiana kwadracika na zielony polacz->Enabled=true;//włącza przycisk rozlacz->Enabled=false;//wyłącza przycisk off_all->Enabled=false;//wyłącza przycisk eeprom->Enabled=false;//wyłącza przycisk s_1->Enabled=false;//wyłącza przycisk s_2->Enabled=false;//wyłącza przycisk s_3->Enabled=false;//wyłącza przycisk s_4->Enabled=false;//wyłącza przycisk CheckBox1->Enabled=false;//wyłącza przycisk } } |
Wszystko poszło dobrze i mamy już połączenia z portem COM. Możemy zabrać się za okodowanie przycisków do włączania i wyłączania światła. Jak wspomniałem wcześniej omówię tylko jeden z nich. Analogicznie modyfikujemy kod pozostałych przycisków. Dla przycisku wyłącz wszystkie wysyłamy 5.
1 2 3 4 5 |
void __fastcall TForm1::s_1Click(TObject *Sender)// zdarzenie OnClick { strcpy(lpBuffor_write, "1");// zapisz do bufora zapisu wartość 1 WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0);//wyślij do bufora zapisu zmienną lpBuffor_write } |
Na tym etapie program potrafi już nawiązać połączenie, poprawie je zamykać oraz włączać i wyłączać światło. Pora na dodanie możliwości zmiany kodów IR pilota. Do wpisywania kodów mamy utworzone cztery pola Edit. Możemy je sobie najpierw sprawdzić i po prostu wpisać do okienka a następie wysłać. Tyle, że gdybym kazał wam przepisywać je najpierw na kartkę później przyklepywać do aplikacji Łukasz z pewnością usunął by ten wpis. Przypominamy sobie, że nasz mC także potrafi się odezwać a w dodatku ostatni odebrany kod cały czas przechowuje w zmiennej kod. Wystarczy go o niego zapytać. Biorąc to wszystko pod uwagę zdecydowałem się, że samo kliknięcie w pole Edit powinno je nam odpowiednio przygotować. Tzn wyczyścić bieżącą wartość, zapytać o ostatni kod mC, odebrać gotowy kod i wkleić go w pole, które przed momentem kliknęliśmy. Jako, że pod ostatnim artykułem pojawiły się głosy, że jestem leniwy to wysłać do mC będę go już musiał sam(przycisk >>).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
void __fastcall TForm1::Edit2Click(TObject *Sender) { strcpy(lpBuffor_write, "6");//zapisuje do lpBuffor_write 6 WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0);//wysyła lpBuffor_write do mC Edit2->Clear();//czyści pole Sleep(200);//usypia program na 200ms char kod_odb[8];//deklaracja tablicy do zapisywania odebranego kodu int ile=0;//zmienna pomocnicza do obliczenia długości odebranego kodu do//instrukcja warunkowa do...while działa jak nastolatek najpierw robi a później sprawdza czy może { ReadFile(hNumPort, &lpBuffor_read, 1, &RS_ile, 0);//zapisuje w zmiennej lpBuffor_read znak który siedzi w buforze kod_odb[ile]=lpBuffor_read[0];//do tablicy kod_odb znak z bufora ile++;//zwiększa nasz licznik } while (lpBuffor_read[0]!='Q');//sprawdza czy znakiem nie było Q jeśli nie działa dalej string kod;//zmienna tekstowa do przechowywania kod sklejonego razem for (int i=0 ; i<ile ; i++)//pęta sklejająca kod do kupy { if (kod_odb[i]!='Q') kod+=kod_odb[i]; jeżeli znakiem nie było Q dodaj ten znak do listy else break;//przeciwnie zerwij pętle for } Edit2->Text=kod.c_str();// zapisz odebrany kod do pola Edit } |
Myślę, że wyjaśnienia wymaga co to jest to tajemnicze Q. Jako, że instrukcja ReadFile wymaga podania ilości znaków do odczynia a my na chwile obecną nie wiemy ile to będzie znaków. Pamiętamy z poprzedniego artykułu, że nasz mC po tym jak odbierze 6 wyśle nam aktualny kod oraz samotną literkę Q. Będziemy więc odczytywać 1 znak odebrany przez aplikacje i sprawdzać czy to nie jest przypadkiem Q. Jeżeli tak to przerywamy pętle jeśli nie to czytamy dalej. Jako, że pętla do … while najpierw wykonuje polecenie z sekcji do a później sprawdza warunek while to znak Q i tak trafi nam do naszej tablicy. Koniecznie trzeba się go pozbyć. Jako, że z zmiennej i wiemy ile odebraliśmy znaków to można napisać pętle for. Tam prosty warunek if wywali nam już niepotrzebne Q. Jezyk C++ udostępnia nam nowy pojemnik na dane którym jest typ string. Typ ten został specjalnie opracowany do przechowywania napisów czyli łańcuchów znaków a co dla nas w tym momencie najważniejsze znaki te można do siebie dodawać. Oczywiście nie jak liczby (1+1=2) tylko łączyć z całość (a+b+c=abc) i to właśnie odbywa się w pętli for.
Kod przycisku >> wyślij jest prawie tak samo porosty jak przycisków 1,2,3,4. Drobną różnicą jest to, że najpierw musimy wysłać zero aby poinformować mC, że za chwile dostanie kod później 1 lub dwa lub 3 lub 4 (info który to będzie kod) a na samym końcu właściwy ciąg znaków z pola Edit.
1 2 3 4 5 6 7 8 |
void __fastcall TForm1::wyslij_1Click(TObject *Sender) { strcpy(lpBuffor_write, "01");// zapisuje do zmiennej lpBuffor_write 01 WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0);//wysyła zmienną lpBuffor_write strcpy(lpBuffor_write, Edit2->Text.c_str());//zapisuje do zmiennej lpBuffor_write kod z pola Edit WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0);//wysyła zmienną lpBuffor_write } |
Jak, że miło by mieć zawsze pod ręką zestaw kodów naszego ulubionego pilota zdecydowałem się na wczytywania i zapisywanie kodów do pliku tekstowego.
1 2 3 4 5 6 7 8 9 10 |
void __fastcall TForm1::z_txtClick(TObject *Sender) { fstream plik;// uchwyt do pliku plik.open("IR.txt", ios::out);//otworzenie pliku to zapisu plik<<Edit2->Text<<endl;//zapisuje kod z pola edit do pliku plik<<Edit3->Text<<endl;//zapisuje kod z pola edit do pliku plik<<Edit4->Text<<endl;//zapisuje kod z pola edit do pliku plik<<Edit5->Text<<endl;//zapisuje kod z pola edit do pliku plik.close();// zamyka plik } |
Kod wydaje się jasny więc przejdźmy do odczytu
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
void __fastcall TForm1::w_txtClick(TObject *Sender) { fstream plik;//uchwyt do pliku plik.open("IR.txt");//otwiera plik do odczytu if(plik.good()==false)//sprawdza czy się nie udało { ShowMessage("Otwarcie pliku IR.txt nie powidło się"); } else { string linia;//zmienna przechwująca wczytane dane int nr_linii=1;//zmienna pomocnicza sterująca przechowująca numer wczytywanej lini while(getline(plik,linia))//dopuki udało się wczytać { switch(nr_linii) { case 1: Edit2->Text=linia.c_str();//zapisz wartość lini do pola Edit break; case 2: Edit3->Text=linia.c_str();//zapisz wartość lini do pola Edit break; case 3: Edit4->Text=linia.c_str();//zapisz wartość lini do pola Edit break; case 4: Edit5->Text=linia.c_str();//zapisz wartość lini do pola Edit break; } nr_linii++; } } plik.close();//zamknij plik } |
Kod dla przycisku Zapisz IR do EEPROM każdy już może napisać samodzielnie. Przypominam tylko, że mC zapisze do pamięci wartość które przechowuje w zmiennych Kod1/2/3/4 a nie te z pól edit. Do uruchomienia funkcji zapisu do EEPROM wystarczy mu wysłać 9.
Na koniec dodamy sobie menu do programu. Opcje które wpadało by dodać do Ustawienia COM oraz Zamknij reszta jest zupełnie opcjonalna. Dodajemy na formę nowy komponent o nazwie MainMenu. Po dwukrotnym kliknięciu na dodawany komponent otworzy się okienko z możliwością dodawania nowych elementów. Po zakończonej edycji z paska na górze wybieramy Ustawienia COM i dodajemy kod:
1 2 3 4 |
void __fastcall TForm1::UstawieniaCOM1Click(TObject *Sender) { Form2->ShowModal(); } |
Ustawienia zostaną dodanie modalnie. Co to znaczy? Wyświetlone okienko nie będzie się dało maksymalizować minimalizować i przed zamknięciem tego okienka nie będzie można wprowadzać zmian w głównej formie aplikacji.
Do przycisku zamknij należy dodać kod:
1 2 3 4 5 |
void __fastcall TForm1::Zakocz1Click(TObject *Sender) { if(SetCommState(hNumPort, &dcb)==TRUE) CloseHandle(hNumPort); Application->Terminate(); } |
Pierwsze polecenie sprawdzi nam czy obecnie jesteśmy połączeni z COM i jeśli tak to otwarte połączenie zostanie zamknięte. Druga linia kodu zamyka nam całą aplikację.
Nasz program kiedy jest nie używany a nie chcemy go zamykać nie powinien nam przeszkadzać w normalnej pracy na komputerze. Dlatego dodamy do niego komponent umożliwiający nam po zminimalizowaniu schowanie aplikacji do systemowego traya. Dodajmy nowy komponent o nazwie TryIcon. Poniżej kod:
1 2 3 4 5 |
void __fastcall TForm1::TrayIcon1Create(TObject *Sender) { Show(); Application->BringToFront(); } |
Tutaj określamy jak ma się zachować nasza aplikacja po kliknięciu w ikonkę na pasku.
Pozostaje nam jeszcze zająć się kosmetycznymi sprawami. Chodzi o to aby uniemożliwić przypadkową maksymalizację okna programu oraz zamianę jego wielkości, określić rozmiar okna, miejsce otwarcia na ekranie monitora po uruchomieniu. Podam tylko nazwy elementów odpowiedzialnych za te zachowania oraz ich ustawienia. Oczywiście to kwesta gustu i wybór odpowiednich parametrów pozostawiam otwarty.
Nazwa | Właściwość | Co zmienia |
AutoSize | True | Wielkość formy dopasowana do zawartośći |
BorderIcon | biMinimize: true | Możliwość minimalizowania okna |
BorderIcon | biMaximize: false | Możliwość maksymalizowania okna |
Caption | Sterownik swiatla 1.0 | Nazwa programu na belce tytułowej |
Color | clCream | Kolor tła aplikacji |
Poniżej zamieszczam jeszcze kod całej aplikacji. Aby był bardziej czytelny jest bez komentarzy – to co jest ważne skomentowałem na górze. Zachęcam także do pobrania archiwum paczka_majsterkowo gdzie jest udostępniony kod źródłowy programu, mC, oraz gotowa skompilowana aplikacja. Jako, że zapomniałem o tym w pierwszej części załączam do paczki pliki exela pozwalające lepiej zrozumieć kroki zamiany liczb oraz użyte w programie dla mC biblioteki.
Mam nadzieję że artykuł się podobał i bardzo proszę o zostawienie komentarza. Chętnie odpowiem na wszystkie pytania. W kolejnej częsci artykułu spotkamy się przy projektowaniu płytki PCB, wytrawianiu oraz lutowaniu. Jeżeli sprzęt pozowli chciałem z tych etapów nagrać filmiki.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
//--------------------------------------------------------------------------- #include <iostream> #include <vcl.h> #include <windows.h> #include <time.h> #include <fstream> #include <string> #include <stdio.h> #pragma hdrstop #include "Unit1.h" #include "Unit2.h" #include "Unit3.h" using namespace std; //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "trayicon" #pragma resource "*.dfm" TForm1 *Form1; string port; DCB dcb; HANDLE hNumPort; char lpBuffor_read[13], lpBuffor_write[8]; DWORD RS_ile; DWORD fdwEvtMask; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { stan->Picture->LoadFromFile("img/offline.bmp"); } //--------------------------------------------------------------------------- void __fastcall TForm1::polaczClick(TObject *Sender) { unsigned long szybkosc; string nr_port; fstream plik; plik.open("ust.txt"); if(plik.good()==false) { Form2->ShowModal(); } else { string linia; int nr_linii=1; while(getline(plik,linia)) { switch(nr_linii) { case 1: nr_port=linia; break; case 2: szybkosc=atoi(linia.c_str()); break; } nr_linii++; } } plik.close(); hNumPort = CreateFile(nr_port.c_str(), GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING,0, NULL); dcb.DCBlength = sizeof(dcb); GetCommState(hNumPort, &dcb); dcb.BaudRate = szybkosc; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fDtrControl = TRUE; SetCommState(hNumPort, &dcb); if(SetCommState(hNumPort, &dcb)==TRUE) { stan->Picture->LoadFromFile("img/online.bmp"); polacz->Enabled=false; rozlacz->Enabled=true; off_all->Enabled=true; eeprom->Enabled=true; s_1->Enabled=true; s_2->Enabled=true; s_3->Enabled=true; s_4->Enabled=true; CheckBox1->Enabled=true; UstawieniaCOM1->Enabled=false; } else ShowMessage("Nie mogę połączy z COM. Sprawdź ustawienia portów"); } //--------------------------------------------------------------------------- void __fastcall TForm1::rozlaczClick(TObject *Sender) { CloseHandle(hNumPort); UstawieniaCOM1->Enabled=true; if(SetCommState(hNumPort, &dcb)==FALSE) { stan->Picture->LoadFromFile("img/offline.bmp"); polacz->Enabled=true; rozlacz->Enabled=false; off_all->Enabled=false; eeprom->Enabled=false; s_1->Enabled=false; s_2->Enabled=false; s_3->Enabled=false; s_4->Enabled=false; CheckBox1->Enabled=false; } } //--------------------------------------------------------------------------- void __fastcall TForm1::off_allClick(TObject *Sender) { if(SetCommState(hNumPort, &dcb)==TRUE) { strcpy(lpBuffor_write, "5"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } else ShowMessage("Nie mogę połączy z COM. Sprawdź ustawienia portów"); } //--------------------------------------------------------------------------- void __fastcall TForm1::Zakocz1Click(TObject *Sender) { if(SetCommState(hNumPort, &dcb)==TRUE) CloseHandle(hNumPort); Application->Terminate(); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { if(SetCommState(hNumPort, &dcb)==TRUE) CloseHandle(hNumPort); } //--------------------------------------------------------------------------- void __fastcall TForm1::UstawieniaCOM1Click(TObject *Sender) { Form2->ShowModal(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Majsterkowopl1Click(TObject *Sender) { ShellExecute(NULL, "open","http://www.majsterkowo.pl", NULL, NULL, SW_SHOWNORMAL); } //--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { if(SetCommState(hNumPort, &dcb)==TRUE) { } } //--------------------------------------------------------------------------- void __fastcall TForm1::TrayIcon1Create(TObject *Sender) { Show(); Application->BringToFront(); } //--------------------------------------------------------------------------- void __fastcall TForm1::CheckBox1Click(TObject *Sender) { if(CheckBox1->Checked==true) { rozlacz->Enabled=false; wyslij_1->Enabled=true; wyslij_2->Enabled=true; wyslij_3->Enabled=true; wyslij_4->Enabled=true; Edit2->Enabled=true; Edit3->Enabled=true; Edit4->Enabled=true; Edit5->Enabled=true; } else { rozlacz->Enabled=true; wyslij_1->Enabled=false; wyslij_2->Enabled=false; wyslij_3->Enabled=false; wyslij_4->Enabled=false; Edit2->Enabled=false; Edit3->Enabled=false; Edit4->Enabled=false; Edit5->Enabled=false; } } //--------------------------------------------------------------------------- void __fastcall TForm1::wyslij_1Click(TObject *Sender) { strcpy(lpBuffor_write, "01"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); strcpy(lpBuffor_write, Edit2->Text.c_str()); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- void __fastcall TForm1::wyslij_2Click(TObject *Sender) { strcpy(lpBuffor_write, "02"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); strcpy(lpBuffor_write, Edit3->Text.c_str()); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- void __fastcall TForm1::wyslij_3Click(TObject *Sender) { strcpy(lpBuffor_write, "03"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); strcpy(lpBuffor_write, Edit4->Text.c_str()); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- void __fastcall TForm1::wyslij_4Click(TObject *Sender) { strcpy(lpBuffor_write, "04"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); strcpy(lpBuffor_write, Edit5->Text.c_str()); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- void __fastcall TForm1::Edit2Click(TObject *Sender) { strcpy(lpBuffor_write, "6"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); Edit2->Clear(); Sleep(200); char kod_odb[8]; int ile=0; do { ReadFile(hNumPort, &lpBuffor_read, 1, &RS_ile, 0); kod_odb[ile]=lpBuffor_read[0]; ile++; } while (lpBuffor_read[0]!='Q'); string kod; for (int i=0 ; i<ile ; i++) { if (kod_odb[i]!='Q') kod+=kod_odb[i]; else break; } Edit2->Text=kod.c_str(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Edit3Click(TObject *Sender) { strcpy(lpBuffor_write, "6"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); Edit3->Clear(); Sleep(200); char kod_odb[8]; int ile=0; do { ReadFile(hNumPort, &lpBuffor_read, 1, &RS_ile, 0); kod_odb[ile]=lpBuffor_read[0]; ile++; } while (lpBuffor_read[0]!='Q'); string kod; for (int i=0 ; i<ile ; i++) { if (kod_odb[i]!='Q') kod+=kod_odb[i]; else break; } Edit3->Text=kod.c_str(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Edit4Click(TObject *Sender) { strcpy(lpBuffor_write, "6"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); Edit4->Clear(); Sleep(200); char kod_odb[8]; int ile=0; do { ReadFile(hNumPort, &lpBuffor_read, 1, &RS_ile, 0); kod_odb[ile]=lpBuffor_read[0]; ile++; } while (lpBuffor_read[0]!='Q'); string kod; for (int i=0 ; i<ile ; i++) { if (kod_odb[i]!='Q') kod+=kod_odb[i]; else break; } Edit4->Text=kod.c_str(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Edit5Click(TObject *Sender) { strcpy(lpBuffor_write, "6"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); Edit5->Clear(); Sleep(200); char kod_odb[8]; int ile=0; do { ReadFile(hNumPort, &lpBuffor_read, 1, &RS_ile, 0); kod_odb[ile]=lpBuffor_read[0]; ile++; } while (lpBuffor_read[0]!='Q'); string kod; for (int i=0 ; i<ile ; i++) { if (kod_odb[i]!='Q') kod+=kod_odb[i]; else break; } Edit5->Text=kod.c_str(); } //--------------------------------------------------------------------------- void __fastcall TForm1::w_txtClick(TObject *Sender) { fstream plik; plik.open("IR.txt"); if(plik.good()==false) { ShowMessage("Otwarcie pliku IR.txt nie powidło się"); } else { string linia; int nr_linii=1; while(getline(plik,linia)) { switch(nr_linii) { case 1: Edit2->Text=linia.c_str(); break; case 2: Edit3->Text=linia.c_str(); break; case 3: Edit4->Text=linia.c_str(); break; case 4: Edit5->Text=linia.c_str(); break; } nr_linii++; } } plik.close(); } //--------------------------------------------------------------------------- void __fastcall TForm1::eepromClick(TObject *Sender) { strcpy(lpBuffor_write, "9"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- void __fastcall TForm1::Informacje1Click(TObject *Sender) { Form3->ShowModal(); } //--------------------------------------------------------------------------- void __fastcall TForm1::z_txtClick(TObject *Sender) { fstream plik; plik.open("IR.txt", ios::out); plik<<Edit2->Text<<endl; plik<<Edit3->Text<<endl; plik<<Edit4->Text<<endl; plik<<Edit5->Text<<endl; plik.close(); } //--------------------------------------------------------------------------- void __fastcall TForm1::s_1Click(TObject *Sender) { strcpy(lpBuffor_write, "1"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- void __fastcall TForm1::s_2Click(TObject *Sender) { strcpy(lpBuffor_write, "2"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- void __fastcall TForm1::s_3Click(TObject *Sender) { strcpy(lpBuffor_write, "3"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- void __fastcall TForm1::s_4Click(TObject *Sender) { strcpy(lpBuffor_write, "4"); WriteFile(hNumPort, lpBuffor_write, strlen(lpBuffor_write), &RS_ile, 0); } //--------------------------------------------------------------------------- |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
//--------------------------------------------------------------------------- #include <vcl.h> #include <string> #include <iostream> #include <fstream> #pragma hdrstop using namespace std; #include "Unit2.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm2 *Form2; string nr_port; string szybkosc; //--------------------------------------------------------------------------- __fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm2::FormCreate(TObject *Sender) { ComboBox1->Items->Add("COM1"); ComboBox1->Items->Add("COM2"); ComboBox1->Items->Add("COM3"); ComboBox1->Items->Add("COM4"); ComboBox1->Items->Add("COM5"); ComboBox1->Items->Add("COM6"); ComboBox1->Items->Add("COM7"); ComboBox1->Items->Add("COM8"); ComboBox1->Items->Add("COM9"); ComboBox1->Items->Add("COM10"); ComboBox1->Items->Add("COM11"); ComboBox2->Items->Add("4800"); ComboBox2->Items->Add("9600"); ComboBox2->Items->Add("14400"); ComboBox2->Items->Add("19200"); ComboBox2->Items->Add("28800"); ComboBox2->Items->Add("38400"); ComboBox2->Items->Add("57600"); ComboBox2->Items->Add("115200"); fstream plik; plik.open("ust.txt"); if(plik.good()==false) { Label3->Caption="NO"; Label4->Caption="NO"; } else { string linia; int nr_linii=1; while(getline(plik,linia)) { switch(nr_linii) { case 1: nr_port=linia; break; case 2: szybkosc=linia; break; } nr_linii++; } plik.close(); Label3->Caption=nr_port.c_str(); Label4->Caption=szybkosc.c_str(); } } //--------------------------------------------------------------------------- void __fastcall TForm2::Button1Click(TObject *Sender) { if(ComboBox1->Items->Strings[ComboBox1->ItemIndex]!="" && ComboBox1->Items->Strings[ComboBox1->ItemIndex]!="") { nr_port=ComboBox1->Items->Strings[ComboBox1->ItemIndex].c_str(); szybkosc=ComboBox2->Items->Strings[ComboBox2->ItemIndex].c_str(); Label3->Caption=ComboBox1->Items->Strings[ComboBox1->ItemIndex]; Label4->Caption=ComboBox2->Items->Strings[ComboBox2->ItemIndex]; fstream plik; plik.open("ust.txt",ios::out); plik << nr_port<<endl; plik << szybkosc<<endl; plik.close(); } else ShowMessage("Może najpierw byś wybrał/a"); } //--------------------------------------------------------------------------- |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit3.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm3 *Form3; //--------------------------------------------------------------------------- __fastcall TForm3::TForm3(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm3::FormCreate(TObject *Sender) { Image1->Picture->LoadFromFile("img/link.bmp"); } //--------------------------------------------------------------------------- void __fastcall TForm3::Button1Click(TObject *Sender) { Form3->Close(); } //--------- |
To C++ Bulder 6 jeszcze nie wymarł? Wybrałeś go celowo, odrzucając np. C#?
Jest darmowy i kiedyś miałem już nim styczność. Kod można skompilować w dowolnym innym kompilatorze oczywiście fragmenty odpowiedzialne za konkretne funkcje
Visual Studio 2013 Express też jest darmowy a możliwości i przyjemność pracy nieporównywalnie większe ;). Ale co kto lubi. Nie sądzisz że takie kontrolki przyklejone do krawędzi okna jakoś tak dziwnie wyglądają? Tak się czepiam, zboczenie zawodowe ;)
I jeszcze pytanie końcowe, ile zajęło Ci czasu opracowanie tego wszystkiego i jak kształtuję się koszty? Pytam, bo ostatnio wdrożyłem podobny projekt i chcę porównać powyższe do możliwości obu systemów.
Projekt nie jest jeszcze skończony na chwile obecną obecną realny koszt całości to 11 zł atmega, i około 4 zł (jak dobrze pamiętam USB-UART). Trochę drobnicy elektronicznej. Nie mam jeszcze przycisków do ręcznej zmiany światła i na chwile obecną wychodzi, że właśnie to będzie najdroższym elementem układu. Jest to hobby więc ciężko przeliczać to na wydane złotówki czy spędzone godziny. Tematem zajmuje się chyba od połowy sierpnia ale nie jest to typowe siedzenie nad programem układem po parę godzin dziennie tylko w wolnych chwilach czasami pół godzinki dziennie a czasami raz w tygodniu.
Pingback: max
Pingback: gabriel
Pingback: trevor
Pingback: Calvin
Pingback: Ken
Pingback: Gregory
Pingback: herbert
Pingback: Micheal
Czekam na 3 część. Artykuł godny uwagi! Aż miło poczytać :)