Witam wszystkich
Chciałem zaprezentować mój projekt do testowania układów logicznych poprzez arduino. Pomysł takiego rozwiązania wziął się stąd, że nie chciałem używać do tego zwykłych przycisków tylko sterować wszystkim z komputera. Postanowiłem, że będę w tym celu używał arduino, gdyż dzięki niemu można bez problemu wysyłać stany do układu oraz odcztywć
Jak już wiedziałem jak można przełączać wartości na wejściu do układu, to przydałoby się znaleźć sposób na sterowanie wszystkimi wartościami i wizualizacją wyjść układu – tu pomyślałem, że bardzo ciekawym pomysłem może być podłączenie arduino do komputera poprzez USB i komunikowanie się poprzez napisany specjalnie na tą okazję program w Visual Studio w języku C#.
Wykorzystane materiały
Arduino Leonardo, płytkę stykową, przewody oraz kabel USB znalazłem w zakupionym wcześniej StarterKit Elektro Przewodnik – z modułem Arduino Leonardo dostępnego tutaj link układy scalone z bramkami i przerzutnikami kupiłem w lokalnym sklepie.
Zaprojektowanie płytki do tworzenia układów
Jedną z pierwszych rzeczy za jakie wziąłem się podczas tworzenia projektu było stworzenie płytki do montowania układów. Wykorzystałem do tego 2 płytki stykowe 830 pól, układy scalone z wybranymi elementami do układów logicznych, oraz przewody żeby wszystko odpowiednio zasilić. Oto efekt końcowy – powkładane w płytkę odpowiednie układy scalone, oraz podłączone zasilanie – zostało ono tak połączone, że wystarczy tylko w jeden raz podłączyć 0V i 5V i każdy układ jest zasilony.
Napisanie programu na komputer oraz platformę arduino
Na samym początku ustaliłem dokładnie jak ma działać całe sterowanie. Postanowiłem, że układ będzie miał maksymalnie 8 wejść i 6 wyjść. Wejścia i wyjścia mogą być aktywowane i dezaktywowane. Jeśli na aktywnym wyjściu z układu zmieni się wartość to przez chwilę na arduino zapali się dioda kontrolna, oraz sterowanie z komputera oraz odczytywanie zmian ma wykonywać się automatycznie.
Projekt w VS
Aby utworzyć projekt należy uruchomić VS (używam wersji 2015 community), otworzyć nowy projekt i wybrać Windows Form Application:
Po wpisaniu nazwy projektu w odpowiednim polu i zatwierdzeniu powinno pojawić się okno z Form1, można oczywiście zmienić nazwę i pododawać odpowiednie przyciski (Button) oraz napisy (Label) – oczywiście nic nie stoi na przeszkodzie, żeby nie ograniczać się tylko do tych dwóch kontrolek, nie należy też zapominać o kontrolce SerialPort, która jest niezbędna podczas przesyłania danych przez USB, oraz Timerze, który będzie nam sprawdzał, czy połączenie z naszym arduino nie zostało zerwane. Mój efekt pracy wyszedł mniej więcej tak:
Mamy już cały wygląd aplikacji. Teraz najtrudniejsze – trzeba wszystko zaprogramować, każdy przycisk musi coś wykonywać, trzeba zadbać o wysyłanie danych itd. Aby było mi łatwiej zapanować nad taką ilością, przycisków i napisów postanowiłem utworzyć 2 klasy pomocnicze – Wejscie oraz Wyjscie – może teraz nie każdy to widzi, ale znacznie usprawnią one napisanie całego potrzebnego kodu.
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 |
using System.Drawing; using System.Windows.Forms; namespace Bramki_logiczne_Arduino___app { class Wejscie { /// <summary> /// zmienne /// </summary> FormApp sender; public bool value; // true - on, false - off public Label labelNumber; // napis naszego wejścia public Button buttonActive; // przycisk aktywności naszego wejścia public Button buttonOnOff; // przycisk wartości naszego wejścia public bool czyAktywny; // informacja o tym czy dana wartość jest aktywna /// <summary> /// konstruktor /// </summary> /// <param name="label"></param> /// <param name="avtiveButton"></param> /// <param name="changeValue"></param> public Wejscie(Label label, Button avtiveButton, Button changeValue, FormApp senderForm) { labelNumber = label; buttonActive = avtiveButton; buttonOnOff = changeValue; value = false; sender = senderForm; czyAktywny = false; } /// <summary> /// zamienia stan na wejściu na przeciwny /// </summary> public void zmien_on_off() { if (sender.polaczono && buttonActive.Text == "Aktywny") { if (buttonOnOff.Text == "OFF") { buttonOnOff.Text = "ON"; buttonOnOff.ForeColor = Color.Green; value = true; } else { buttonOnOff.Text = "OFF"; buttonOnOff.ForeColor = Color.Red; value = false; } } } /// <summary> /// zmienia aktywność na przeciwną /// </summary> public void zmien_aktywnosc() { if (sender.polaczono) { if (buttonActive.Text == "Blokada") { czyAktywny = true; buttonActive.Text = "Aktywny"; buttonActive.ForeColor = Color.Green; buttonOnOff.Text = "OFF"; buttonOnOff.ForeColor = Color.Red; buttonOnOff.Show(); } else { czyAktywny = false; buttonActive.Text = "Blokada"; buttonActive.ForeColor = Color.DeepSkyBlue; buttonOnOff.ForeColor = Color.Gray; value = false; buttonOnOff.Text = "OFF"; buttonOnOff.Hide(); } } } /// <summary> /// blokuje wejście /// wykonywane jak rozłączono z urządzeniem /// </summary> public void blokuj() { value = false; labelNumber.ForeColor = Color.Gray; buttonActive.Text = "Blokada"; buttonActive.ForeColor = Color.Gray; buttonOnOff.Hide(); } /// <summary> /// odblokowywuje wejście /// jak połączono z urządzeniem /// </summary> public void odblokuj() { value = false; labelNumber.ForeColor = Color.Black; buttonActive.ForeColor = Color.DeepSkyBlue; } } } |
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 |
using System.Drawing; using System.Windows.Forms; namespace Bramki_logiczne_Arduino___app { class Wyjscie { /// <summary> /// zmienne /// </summary> public Label wartosc_wyswietana; public Button nr_wyswietlany; public bool aktywny = true; public bool wartosc; // true - 1, false - 0 /// <summary> /// konstruktor /// </summary> /// <param name="w"></param> /// <param name="n"></param> public Wyjscie(Label w, Button n) { wartosc_wyswietana = w; nr_wyswietlany = n; wartosc = false; } /// <summary> /// ustawia wartość na taką jakie jest pole wartość /// </summary> public void ustaw() { if (aktywny) { if (wartosc) { wartosc_wyswietana.Text = "true"; wartosc_wyswietana.ForeColor = Color.Green; } else { wartosc_wyswietana.Text = "false"; wartosc_wyswietana.ForeColor = Color.DeepSkyBlue; } } } /// <summary> /// blokuje wyjście (jak rozłączono z urządzeniem) /// </summary> public void blokuj() { nr_wyswietlany.ForeColor = Color.Gray; wartosc_wyswietana.Text = "Nieaktywny"; wartosc_wyswietana.ForeColor = Color.Gray; aktywny = false; wartosc_wyswietana.Hide(); } /// <summary> /// odblokowywuje urządzenie (jak połączono z urządzeniem) /// </summary> public void odblokuj() { aktywny = true; zmien_aktywnosc(); } /// <summary> /// zmienia aktywność wyjścia (aktywny/nieaktywny) /// </summary> public void zmien_aktywnosc() { if (aktywny) { wartosc_wyswietana.Hide(); nr_wyswietlany.ForeColor = Color.Gray; aktywny = false; } else { wartosc_wyswietana.Show(); nr_wyswietlany.ForeColor = Color.Black; aktywny = true; } } } } |
Komentarze opisują chyba wszystkie istotne fragmenty kodu, więc nie będę go omawiał. Pozostała nam jeszcze klasa Form1 (chyba, że została zmieniona nazwa na inną). Tu kod jest już trochę bardziej obszerny:
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 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
using System; using System.Windows.Forms; using System.IO.Ports; using System.Threading; using System.Drawing; namespace Bramki_logiczne_Arduino___app { public partial class FormApp : Form { /// <summary> /// zmienne /// </summary> int wart_wejscia = 0; // pomocne przy doczycie pakietu, oznacza stany sygnałów odebranych przez arduino, jak jest takie samo to nie ma sensu liczyć bo nic się nie zmieni long licznik_czasu = 0; // liczy ms od uruchomienia - jak jest %100==0 to wysyła pakiet z danymi wejsciowymi Wejscie[] wej = new Wejscie[8]; // obiekty reprezentujące wejście do naszego układu Wyjscie[] wyj = new Wyjscie[6]; // obiekty reprezentujące wyjście od naszego układu public bool polaczono = false; // zmienna statyczne oszaczająca czy połączono z naszym arduino string odczyt_pak = ""; // zmienna wykorzystywana przy łączeniu z arduino /// <summary> /// konstruktor - inicjalizacja programu /// </summary> public FormApp() { // utworzenie okna InitializeComponent(); // ustawienie parametrów serialPort serialPort.BaudRate = 9600; serialPort.DtrEnable = true; // tworzenie obiektów wejścia wej[0] = new Wejscie(nr_zadajnika1, aktywnosc_wej1, zadajnik1, this); wej[1] = new Wejscie(nr_zadajnika2, aktywnosc_wej2, zadajnik2, this); wej[2] = new Wejscie(nr_zadajnika3, aktywnosc_wej3, zadajnik3, this); wej[3] = new Wejscie(nr_zadajnika4, aktywnosc_wej4, zadajnik4, this); wej[4] = new Wejscie(nr_zadajnika5, aktywnosc_wej5, zadajnik5, this); wej[5] = new Wejscie(nr_zadajnika6, aktywnosc_wej6, zadajnik6, this); wej[6] = new Wejscie(nr_zadajnika7, aktywnosc_wej7, zadajnik7, this); wej[7] = new Wejscie(nr_zadajnika8, aktywnosc_wej8, zadajnik8, this); // tworzenie obiektów wyjścia wyj[0] = new Wyjscie(odcz1, nr_wyj1); wyj[1] = new Wyjscie(odcz2, nr_wyj2); wyj[2] = new Wyjscie(odcz3, nr_wyj3); wyj[3] = new Wyjscie(odcz4, nr_wyj4); wyj[4] = new Wyjscie(odcz5, nr_wyj5); wyj[5] = new Wyjscie(odcz6, nr_wyj6); // blokuje wejscia do momentu jak się nie połączy z Arduino foreach (Wejscie ww in wej) ww.blokuj(); // blokuje wyjscia do momentu jak się nie połączy z Arduino foreach (Wyjscie ww in wyj) ww.blokuj(); } /// <summary> /// funkcja wykonywana w momencie odebrania danych przez serialPort /// odbierane są albo dane do utworzenia połączenia, albo układ wyjść z naszego układu /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { try // wychwytujemy wyjątek - jeśli stałoby się coś z naszym urządzeniem, rozłączamy je { // jak połączono to odbiera dane odczytu if (polaczono) { byte[] b = new byte[1]; serialPort.Read(b, 0, 1); analiza_odczytu(b[0]); } // odczytuje stringi do identyfikacji urządzenia else odczyt_pak = serialPort.ReadLine(); } catch (Exception) { rozlaczenie(); } } /// <summary> /// funkcja zamieniająca byte odczytany przez serialPort /// na ustawienia konkretnych kontrolek (napisów czy true czy false odczytanych danych) /// </summary> /// <param name="b"></param> private void analiza_odczytu(int b) { // funkcja odczytu która zamienia liczbę podaną na wejściu // na dane if (wart_wejscia != b) { wart_wejscia = b; int mnoznik = 32; for (int a=5; a>=0; a--) { if (mnoznik<=b) { b -= mnoznik; wyj[a].wartosc = true; } else wyj[a].wartosc = false; mnoznik /= 2; } } // ustawienie wyjść odbywa się synchronicznie co 1ms przez nasz timer } /// <summary> /// funkcja ustawiająca wyjścia z układu /// </summary> private void ustaw_wyjscia() { for (int a = 0; a < 6; a++) wyj[a].ustaw(); } /// <summary> /// funkcja wysyłająca wejścia do arduino (wejścia układu) /// </summary> public void wyslij_wejscia() { byte []l = new byte[2]; l[0] = 0; l[1] = 0; for (byte a = 0, m = 1; a < 8; a++, m *= 2) if (wej[a].value) l[1] += m; serialPort.Write(l, 0, 2); } public void wyslij_jakie_wyjscia_do_odczytania() { byte[] l = new byte[2]; l[0] = 1; l[1] = 0; for (byte a = 0, m = 1; a < 6; a++, m *= 2) if (wyj[a].aktywny) l[1] += m; serialPort.Write(l, 0, 2); } /// <summary> /// ustawienie kontrolki stanu połączenia na połączono /// </summary> private void ustaw_POLOCZONO() { stan_polaczenia.Text = serialPort.PortName + " połączono ✔"; stan_polaczenia.ForeColor = Color.Green; } /// <summary> /// ustawienie kontrolki stanu połączenia na nie połączono /// </summary> private void ustaw_NIE_POLOCZONO() { stan_polaczenia.Text = "nie połączono"; stan_polaczenia.ForeColor = Color.Red; } /// <summary> /// ustawienie kontrolki stanu połączenia na utracono połączenie /// </summary> private void ustaw_ROZLACZONO() { stan_polaczenia.Text = "utracono połączenie"; stan_polaczenia.ForeColor = Color.Red; } /// <summary> /// funkcja próbująca utworzyć połączenie z arduino /// - wywoływana poprzez wciśnięcie przycisku /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void przycisk_polaczenia_Click(object sender, EventArgs e) { // zablokowanie przycisku, dzięki temu nie nawiążemy 2 prób połączenia jednocześnie przycisk_polaczenia.Enabled = false; // zmienne wykorzystywane do łączenia int liczba_portow = 0; bool czy_dobry_port = false; odczyt_pak = ""; // pobranie nazw portów string[] porty = SerialPort.GetPortNames(); // odczytanie liczby portów liczba_portow = porty.Length; // sprawdzanie każdego portu - jak jakiś dobry przerywamy funkcję łączenia // i kończymy pętlę for (int a = 0; a < liczba_portow; a++) { // zamknięcie portu jak otwarty if (serialPort.IsOpen) serialPort.Close(); // nowa nazwa portu i oznaczenie go pocz. że dobry serialPort.PortName = porty[a]; bool czy_mozliwy_port = true; czy_dobry_port = false; // sprawdzenie czy można połączyć się z portem try { serialPort.Open(); } catch (Exception) // jeśli nie można (port zajęty) { czy_mozliwy_port = false; MessageBox.Show("zajety port"); } // tego MessageBox-a nie musi być if (czy_mozliwy_port == true) { // teraz jak port połączony to sprawdzenie czy to ten port try { serialPort.WriteLine("majsterkowo"); } catch (Exception) { MessageBox.Show("Err"); } // odczytanie danych tu czekamy i robimy event jak odebrane dane na serialu Thread.Sleep(2000); //MessageBox.Show(odczyt_pak); if (odczyt_pak == "Haslo poprawne" + (char)13) { czy_dobry_port = true; polaczono = true; wyslij_wejscia(); } } if (czy_dobry_port == true) break; else serialPort.Close(); } if (czy_dobry_port == true) { ustaw_POLOCZONO(); foreach (Wejscie ww in wej) ww.odblokuj(); foreach (Wyjscie ww in wyj) ww.odblokuj(); } else // jak nie połączono z niczym { serialPort.Close(); przycisk_polaczenia.Enabled = true; MessageBox.Show("Nie wykryto urządzenia\n\nSprawdź czy jest ono podłączone", "Komunikat"); ustaw_NIE_POLOCZONO(); } } /// <summary> /// funkcja rołączająca z arduino /// wywołana jeśli port był połączony a nie jest otwarty /// sprawdzane co 1ms /// </summary> private void rozlaczenie() { przycisk_polaczenia.Enabled = true; polaczono = false; ustaw_ROZLACZONO(); // blokuje wejscia do momentu jak się nie połączy z Arduino foreach (Wejscie ww in wej) ww.blokuj(); // blokuje wyjscia do momentu jak się nie połączy z Arduino foreach (Wyjscie ww in wyj) ww.blokuj(); } /// <summary> /// reakcja na przełączenie jednego przycisku odpowiadającaego za wartość na wejściu do układu /// </summary> /// <param name="sender"></param> private void obsluz_on_off_zadajnika(Object sender) { int i; for (i = 0; (Button)sender != wej[i].buttonOnOff; i++) ; // szukanie obiektu reprezentującego dany przycisk wej[i].zmien_on_off(); wyslij_wejscia(); } /// <summary> /// funkcja zmieniająca aktywność danego zadajnika, dzięki niej dezaktywujemy dane wejście do układu /// </summary> /// <param name="sender"></param> private void ustaw_aktywnosc_zadajnika(Object sender) { if (polaczono) { int i; for (i = 0; (Button)sender != wej[i].buttonActive; i++) ; // szukanie obiektu reprezentującego dany przycisk wej[i].zmien_aktywnosc(); wyslij_jakie_wyjscia_do_odczytania(); wyslij_wejscia(); } } /// <summary> /// wykonanie funkcji co 1 ms (tak mamy ustawiony timer) /// rozłączamu jak rozłączono, oraz co 100 razy wysyłamy wejścia /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void timer_Tick(object sender, EventArgs e) { ustaw_wyjscia(); if (!serialPort.IsOpen && polaczono) rozlaczenie(); if (polaczono && licznik_czasu++ % 100 == 0) { wyslij_wejscia(); wyslij_jakie_wyjscia_do_odczytania(); } } /// <summary> /// ustawia aktywność wyjścia z układu /// </summary> /// <param name="sender"></param> private void aktywnosc_wyjscia(object sender) { if (polaczono) { int a; for (a = 0; (Button)sender != wyj[a].nr_wyswietlany; a++) ; wyj[a].zmien_aktywnosc(); } } /// <summary> /// funkcje odpowiadające za wciskanie odpowiednich przycisków /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void aktywnosc_wej1_Click(object sender, EventArgs e) { ustaw_aktywnosc_zadajnika(sender); } private void aktywnosc_wej2_Click(object sender, EventArgs e) { ustaw_aktywnosc_zadajnika(sender); } private void aktywnosc_wej3_Click(object sender, EventArgs e) { ustaw_aktywnosc_zadajnika(sender); } private void aktywnosc_wej4_Click(object sender, EventArgs e) { ustaw_aktywnosc_zadajnika(sender); } private void aktywnosc_wej5_Click(object sender, EventArgs e) { ustaw_aktywnosc_zadajnika(sender); } private void aktywnosc_wej6_Click(object sender, EventArgs e) { ustaw_aktywnosc_zadajnika(sender); } private void aktywnosc_wej7_Click(object sender, EventArgs e) { ustaw_aktywnosc_zadajnika(sender); } private void aktywnosc_wej8_Click(object sender, EventArgs e) { ustaw_aktywnosc_zadajnika(sender); } private void zadajnik1_Click(object sender, EventArgs e) { obsluz_on_off_zadajnika(sender); } private void zadajnik2_Click(object sender, EventArgs e) { obsluz_on_off_zadajnika(sender); } private void zadajnik3_Click(object sender, EventArgs e) { obsluz_on_off_zadajnika(sender); } private void zadajnik4_Click(object sender, EventArgs e) { obsluz_on_off_zadajnika(sender); } private void zadajnik5_Click(object sender, EventArgs e) { obsluz_on_off_zadajnika(sender); } private void zadajnik6_Click(object sender, EventArgs e) { obsluz_on_off_zadajnika(sender); } private void zadajnik7_Click(object sender, EventArgs e) { obsluz_on_off_zadajnika(sender); } private void zadajnik8_Click(object sender, EventArgs e) { obsluz_on_off_zadajnika(sender); } private void nr_wyj1_Click(object sender, EventArgs e) { aktywnosc_wyjscia(sender); } private void nr_wyj2_Click(object sender, EventArgs e) { aktywnosc_wyjscia(sender); } private void nr_wyj3_Click(object sender, EventArgs e) { aktywnosc_wyjscia(sender); } private void nr_wyj4_Click(object sender, EventArgs e) { aktywnosc_wyjscia(sender); } private void nr_wyj5_Click(object sender, EventArgs e) { aktywnosc_wyjscia(sender); } private void nr_wyj6_Click(object sender, EventArgs e) { aktywnosc_wyjscia(sender); } } } |
Pisząc ten kod, należy zwrócić uwagę na sposób w jaki łączymy się z naszym arduino – pobieramy nazwy wszystkich portów, dla każdego próbujemy wysłać odpowiedni komunikat, następnie czekamy chwilkę na odpowiedź zwrotną, jeśli dostaniemy odpowiedni komunikat to będziemy mogli uznać, że jesteśmy połączeni z naszym urządzeniem. Inną, rzeczą wartą uwagi jest jeszcze sposób w jaki wysyłamy dane do arduino – mamy ich 2 typy, każdy z nich potrzebuje jednego bajta, będziemy trzymali się konwencji, że najpierw prześlemy bajt z informacją, jaka informacja będzie przesyłana a następnie właściwe dane.
Aby wykonać zmianę dowolnej wartości poprzez wciśnięcie przycisku posłużyłem się obiektami moich klas – szukam w tablicy reprezentanta danej kontrolki i działam. W timerze tick występuje co 1ms w każdym takim cyklu sprawdzam czy nasze urządzenie nie zostało odłączone oraz co 100ms wysyłam dane do arduino. Jeśli ktoś by nie wiedział, jak dodać akcję do danego przycisku to jeśli chodzi o kliknięcie to wystarczy go najnormalniej kliknąć 2x, a w przypadku Timera i SerialPortu należy kliknąć w daną kontrolkę, wejść w Properties, odnaleźć w górnej części przycisk Events i wybrać interesujące nas zdarzenie.
Kod do Arduino
Teraz już po napisaniu obszernego kodu nie pozostało nam nic innego jak według naszego schematu zaprogramować arduino i wreszcie zakończyć nasz projekt:
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 |
/* Name: Bramki_Logiczne_Arduino.ino Created: 2016-03-04 14:20:22 Author: Marcin */ /// zmienne bool stan[6]; // stan wyjść z układu bool aktywnoscWyjsc[6]; // jak aktywne to gdy zmiana zapalamy diodę byte stan_wejsc = 0; // stan wejść do układu int odcz[] = { A0, A1, A2, A3, A4, A5 }; // nr pinów odczytu long czas_zapalenia = 0; // czas do jakiego ma być zapalona dioda long czas_wyslania_odczytu = 0; // czas po jakim ma być wysłany odczyt bool stan_polaczenia = false; // stan połączenia z komputerem /// inicjalizacja początkowa programu void setup() { // deklaracja pinów odczytu for (int a = 0; a < 6; a++) pinMode(odcz[a], INPUT); // odczytanie początkowych wartości pól for (int a = 0; a < 6; a++) { if (digitalRead(odcz[a]) == HIGH) stan[a] = true; else stan[a] = false; } // deklaracja zadajników for (int a = 0; a < 8; a++) pinMode(a, OUTPUT); // ustawienie wszyztkoego na 0V for (int a = 0; a < 8; a++) digitalWrite(a, LOW); // ustawienie wszystkich wyjść jako nieaktyenych // ustawienie diody do migania oraz miganie na start porgramu pinMode(13, OUTPUT); szybkie_miganie(); } /// funkcja ustawia wszystkie wyjścia jako nie aktywne void dezaktywujWyjscia() { for (int i = 0; i < 6; i++) aktywnoscWyjsc[i] = false; } ///wysłanie odczytanych danych wyjściowych z układu void wyslij_odczyt() { //stan pinów odczytu // czytamy od ostatniego (numerowane są 0-5 czyli 5, 4, 3, 2, 1, 0) // jak rozlożymi liczbę binarnie to odpowiednie bity to // np liczba 32 w rozkładzie to 100000 byte wysyl[1]; byte m = 1; wysyl[0] = 0; for (int a = 0; a < 6; a++) { if (stan[a]) wysyl[0] += m; m *= 2; } Serial.write(wysyl, 1); } /// miganie normalne void miganie() { for (int i = 0; i < 4; i++) { digitalWrite(13, HIGH); delay(500); digitalWrite(13, LOW); delay(500); } } /// miganie szybkie void szybkie_miganie() { for (int a = 0; a < 8; a++) { digitalWrite(13, HIGH); delay(100); digitalWrite(13, LOW); delay(200); } } /// funkcja odbierająca dane z komputera void ustaw_odcztywane_wyjscia(byte odczytane) { for (byte i = 32, j = 5; i > 0; i /= 2, j--) { if (odczytane >= i) { aktywnoscWyjsc[j] = true; odczytane -= i; } else aktywnoscWyjsc[j] = false; } } /// odczytanie danych z komputera void odczytPakietu() { byte odczyt[2]; while (Serial.available()) Serial.readBytes(odczyt, 2); if (odczyt[0]==0) ustaw_wejscie_ukladu(odczyt[1]); else ustaw_odcztywane_wyjscia(odczyt[1]); } /// ustawienie wartości na wejście z układu void ustaw_wejscie_ukladu(int b) { stan_wejsc = b; int mnoznik = 128; for (int i = 7; i >= 0; i--) { if (b >= mnoznik) { digitalWrite(i, HIGH); b -= mnoznik; } else digitalWrite(i, LOW); mnoznik /= 2; } } /// sprawdza czy zostały zmienione wartości na wyjściu z układu bool sprawdz_zmiane() { bool wys = false; for (int a = 0; a < 6; a++) { if (aktywnoscWyjsc[a]) { if (digitalRead(odcz[a]) == HIGH) { if (!stan[a]) { stan[a] = true; wys = true; czas_zapalenia = millis() + 1000; digitalWrite(13, HIGH); } } else if (stan[a]) { stan[a] = false; wys = true; czas_zapalenia = millis() + 1000; digitalWrite(13, HIGH); } } } if (millis() > czas_zapalenia) digitalWrite(13, LOW); if (wys) wyslij_odczyt(); return wys; } /// pomocna przy tworzeniu programu void wyswietlanie_stanow_cyfrowych() { for (int a = 0; a < 6; a++) Serial.print(String(digitalRead(odcz[a])) + " "); Serial.println(); } /// pomocna przy tworzeniu programu void wyswietlanie_stanow_analogowych() { for (int a = 0; a < 6; a++) Serial.print(String(analogRead(odcz[a])) + " "); Serial.println(); } /// funkcja loop void loop() { // sprawdzanie połączenia - główny warunek co będzie się wykonywało if (!Serial) { Serial.begin(9600); dezaktywujWyjscia(); stan_polaczenia = false; } else if (stan_polaczenia) { if (Serial.available()) odczytPakietu(); if (!sprawdz_zmiane() && millis() > czas_wyslania_odczytu) { czas_wyslania_odczytu = millis() + 1500; wyslij_odczyt(); } } else { String pom = Serial.readStringUntil('\n'); if (pom == "majsterkowo") { Serial.println("Haslo poprawne"); miganie(); stan_polaczenia = true; } } } |
Mamy tu kilka zmiennych globalnych których istnienie ułatwia znacząco pisanie kodu programu. Kod jest opisany więc nie będę go jakoś szczególnie prezentował. Można zwrócić uwagę na sposób w jaki łączymy się z komputerem – analogicznie jak w Visual Studio używamy jako haseł w połączeniu tych samych stringów, co pozwoli zweryfikować nam czy łączymy się z naszym urządzeniem. Oczywiście założyłem, że pinami wejście do układu są piny od 0 do 7 na arduino, a wyjścia z układu są pinami od A0 do A5.
Prezentacja wybranego układu
Przedstawiam jeden z układów zbudowanych przeze mnie, jest to układ synchroniczny, gdzie po podaniu na wejście X prawdy, po 3 taktach zegara, zapali się dioda, po podaniu fałszu na X podczas taktu zegara dioda gaśnie i licznik który liczy przełączenia zegara zeruje się.
A czego zdjęcia z efektem mgły?
Coś się porobiło z ocenianiem. Nie można oddać głosu …
Myślałem ze to tylko u mnie coś nie tak z głosowaniem. Majsterkowo chyba trochu umiera. Artykułów coraz mniej, w większości słabe, forum tez milknie, admin zagląda raz na ruski rok…
Ja tu jestem cały czas ; Nawet na forum ostatnio zrobiliśmy porządki i zwerbowalismy nowych moderatorów (w tym moją żonę;)
A ocenianie cały czas działało, tylko było ustawione tylko dla zalogowanych użytkowników. W nocy walczyłem z jednym spacerem, który glosując przez TOR-a próbował przepchnąć na główną jakiś syf (próbował kilka razy), więc musiałem go jakoś przyblokowac. Na razie przywrocilem głosowanie dla wszystkich, ale docelowo będzie ustawione tylko dla zalogowanych (ale za to progi potrzebne do wyjścia z Poczekalni będą dużo nizsze).
Pozdrawiam!
Łukasz
Witam Panie Łukaszu. Pytanko. Dlaczego nie mogę zalogować się na stronie tym samym loginem co na forum. Trochę dziwnie to :-) Pan Podziała coś w tym kierunku :-)
W tej chwili są to dwa osobne konta, ale walczę z ich integracją :)
A i jeszcze jedno. Doda Pan stronkę z tymi artykułami co były kiedyś w poczekalni. Bo niektóre były fajne a wystarczy tylko coś zmienić (zastosować się do uwag) i może wyskoczą wyżej.
też jestem za działem “Kosz” czy coś w ten deseń, niektóre wykonania były kiepskie, za to pomysły warte uwagi i modyfikacji we własnym zakresie.
Do przemyślenia :)
Popieram ;)
Czasami tak było, że spodobał mi się jakiś projekt, chciałem do niego wrócić, ale nie mogłem, bo się nie wydostał z poczekalni. Przeszukiwanie historii przeglądania z tygodnia żeby znaleźć jeden link wcale nie należy do przyjemnych ;)
Może być ten dział kosz jakiś ukryty, gdzieś mały nierzucający się w oczy link z samą listą tematów bez nawet ikonek, ale miło by było, gdyby dało się zobaczyć jego zawartość
Dlaczego nikt nie głosuje na ten projekt, dalej się nie da, czy co? inne projekty już od dawna nie są w poczekalni.
co dalej nie działą z głosowanie na ten projekt
Możecie zobaczyć teraz?
Teraz działa.