{"id":920,"date":"2017-11-28T18:07:43","date_gmt":"2017-11-28T18:07:43","guid":{"rendered":"http:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/?p=920"},"modified":"2017-12-06T07:52:05","modified_gmt":"2017-12-06T07:52:05","slug":"sterowanie-ledami-za-pomoca-klawiatury","status":"publish","type":"post","link":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/?p=920","title":{"rendered":"Sterowanie ledami za pomoc\u0105 klawiatury &#8211; ASCII i (znowu) tablice"},"content":{"rendered":"<p>Na ostatnich zaj\u0119ciach kontynuowali\u015bmy nauk\u0119 obs\u0142ugi led\u00f3w przez monitor szeregowy. Tym razem nie ograniczali\u015bmy si\u0119 do sterowania wszystkimi ledami jednocze\u015bnie, a d\u0105\u017cyli\u015bmy do mo\u017cliwo\u015bci dowolnego w\u0142\u0105czania i wy\u0142\u0105czania pojedynczych lampek. Podczas tych zaj\u0119\u0107 uczyli\u015bmy si\u0119 sprytnego (zaawansowanego?) wykorzystania tablic.<\/p>\n<h1>Switch &#8230; case<\/h1>\n<p>Na zaj\u0119ciach wykorzystali\u015bmy uk\u0142ady przygotowane tydzie\u0144 temu. Pod\u0142\u0105czyli\u015bmy je w taki sam spos\u00f3b. Do naszego pierwszego programu wykorzystali\u015bmy warunek wielokrotnego wyboru, czyli sk\u0142adni\u0119 switch &#8230; case.<\/p>\n<p>Na pocz\u0105tku kodu standardowo&nbsp; pod\u0142\u0105czamy ka\u017cdy z led\u00f3w do pinu cyfrowego. Nast\u0119pnie tworzymy <strong>p\u0119tl\u0119 if<\/strong>, kt\u00f3ra sprawdza, czy s\u0105 dane (bajty) na porcie szeregowym do odczytania przez Arduino &#8211; linia #11. W 12 linii&nbsp;wczytujemy jeden bajt i przypisujemy go do zmiennej znakowej c (omawiali\u015bmy to tydzie\u0144 temu). W celu umo\u017cliwienia sterowania pojedynczymi lampkami za pomoc\u0105 konkretnych liter w&nbsp;<strong>13 linii&nbsp;<\/strong>tworzymy prze\u0142\u0105cznik <strong>switch<\/strong> zale\u017cny w\u0142a\u015bnie od zmiennej c. W<strong>&nbsp;liniach&nbsp;14-23&nbsp;<\/strong>tworzymy warunki, czyli przypisujemy do wybranych znak\u00f3w (u nas: a b c d e A B C D i E)&nbsp; w\u0142\u0105czanie lub wy\u0142\u0105czanie danego LED-a. Fajne jest to, \u017ce do bufora mo\u017cemy od razu wpisa\u0107 <strong>ca\u0142e &#8222;zdanie&#8221; <\/strong>a nie tylko pojedynczy znak. Arduino b\u0119dzie odczytywa\u0107 znak-po-znaku (linia 12), a my zobaczymy dan\u0105 sekwencj\u0119 w\u0142\u0105czania\/wy\u0142\u0105czania LED-\u00f3w na p\u0142ytce. Aby uatrakcyjni\u0107 ten fragment etap zabawy z Arduino i LED-ami dodali\u015bmy specjalny <strong>case<\/strong>&nbsp;z warto\u015b\u0107i\u0105&nbsp;<strong>#<\/strong>, kt\u00f3ry tworzy przerw\u0119 &#8211; pauz\u0119 (linia 24).<\/p>\n<pre class=\"lang:arduino decode:true\" title=\"Proste sterowanie LED-ami z klawiatury\">#define MAX 5\r\nint piny[5]={2,3,4,5,6};\r\nint i;\r\nchar c;\r\nvoid setup(){\r\n  for(i=0;i&lt;MAX;i++)\r\n  pinMode(piny[i],OUTPUT);\r\n  Serial.begin(9600);\r\n}\r\nvoid loop(){\r\n  if(Serial.available()&gt;0){\r\n  c=Serial.read();  \r\n   switch(c){\r\n      case 'a': digitalWrite(piny[0],HIGH);break;\r\n      case 'A': digitalWrite(piny[0],LOW);break;\r\n      case 'b': digitalWrite(piny[1],HIGH);break;\r\n      case 'B': digitalWrite(piny[1],LOW);break;\r\n      case 'c': digitalWrite(piny[2],HIGH);break;\r\n      case 'C': digitalWrite(piny[2],LOW);break;\r\n      case 'd': digitalWrite(piny[3],HIGH);break;\r\n      case 'D': digitalWrite(piny[3],LOW);break;\r\n      case 'e': digitalWrite(piny[4],HIGH);break;\r\n      case 'E': digitalWrite(piny[4],LOW);break;\r\n      case '#': delay(200);break; \r\n}}}\r\n<\/pre>\n<p>W\u0142a\u015bnie dzi\u0119ki nowemu symbolowi # (pauza) by\u0142o mo\u017cliwe wpisywanie sekwencji (=&#8221;zda\u0144&#8221;) typu&nbsp;<strong>abcde#####A#B#C#D#E<\/strong> (jednoczesne w\u0142\u0105czenie wszystkich 5-ciu LED\u00f3w, odczekanie sekundy a nast\u0119pnie wy\u0142\u0105czenie, z kr\u00f3tkimi przerwami, po kolei LED-\u00f3w). Inne sekwencje to, np. abcde##E##D##C##B##A##abcde###ABCDE###abcde###ABCDE (w\u0142\u0105czenie wszystkich, wy\u0142\u0105czenie po kolei wszystkich w odwrotnej kolejno\u015bci a na koniec dwukrotne &#8222;mrygni\u0119cie&#8221; wszystkimi na raz LED-ami).<\/p>\n<h1>Obserwacje\/uwagi<\/h1>\n<p>Powy\u017cszy program jest prosty ale ci\u0105gle efektowny &#8211; dzi\u0119ki <strong>wprowadzeniu pauzy (#)<\/strong>. Jednak z informatycznego punktu widzenia cierpi na nast\u0119puj\u0105ce problemy:<\/p>\n<ul>\n<li>chc\u0105c doda\u0107 wi\u0119cej LED-\u00f3w musimy jak &#8222;ma\u0142pa&#8221; skopiowa\u0107 linie 14-15 dodaj\u0105c nowe literki do sterowania. Zauwa\u017camy jednak pewn\u0105 regularno\u015b\u0107 w oprogramowaniu ka\u017cdej literki (linie 14-23 niewiele r\u00f3\u017cni\u0105 si\u0119 od siebie). Mo\u017ce nie ma w tym nic z\u0142ego, ale czy nie da si\u0119 tego jako\u015b lepiej zaprogramowa\u0107?&nbsp;<\/li>\n<li>jak rozbudowa\u0107 program o mo\u017cliwo\u015b\u0107 sterowania literkami w ten spos\u00f3b, \u017ce dana literka w\u0142\u0105cza LED-a gdy by\u0142 on wy\u0142\u0105czony, a wy\u0142\u0105cza gdy by\u0142 on w\u0142\u0105czony? Jak na razie do w\u0142\u0105czania u\u017cywamy ma\u0142ych liter a do wy\u0142\u0105czania du\u017cych &#8211; to chyba zbyteczna rozrzutno\u015b\u0107.<\/li>\n<\/ul>\n<p>Zaczynamy od rozwi\u0105zania pierwszego problemu i przechodzimy do wykorzystania <strong>tablic.<\/strong>&nbsp;Tablice pojawiaj\u0105 si\u0119 tu w spos\u00f3b naturalny &#8211; przygl\u0105daj\u0105c si\u0119 liniom 14-23 zauwa\u017camy, \u017ce w\u0142\u0105czamy\/wy\u0142aczamy LED-y podpi\u0119te do port\u00f3w cyfrowych Arduino zapisanych w tablicy <strong>piny[0,1,2,3,4]<\/strong>. Przy czym pierwszy LED pod\u0142\u0105czony jest do portu <strong>piny[0]<\/strong>, drugi do portu <strong>piny[1]<\/strong> i tak dalej. Jak wi\u0119c dobra\u0107 odpowiedni indeks tablicy do konkretnego LED-a?<\/p>\n<h1>ASCII<\/h1>\n<p>Dobranie indeksu tablicy <strong>piny[]<\/strong> b\u0119dzie bazowa\u0107 na kodowaniu znak\u00f3w <a href=\"https:\/\/pl.wikipedia.org\/wiki\/ASCII\">ASCII<\/a>. Dane wczytywane przez Serial.read() to w rzeczywisto\u015bci bajty, kt\u00f3re mo\u017cemy interpretowa\u0107 jako literki (typ char) lub jako liczby (typ int). Mo\u017cemy wi\u0119c patrze\u0107 na literk\u0119&nbsp;<strong>d<\/strong> jak znak 'd&#8217; (typ char) lub jak na kod ASCII wynosz\u0105cy <strong>100<\/strong> (liczba ca\u0142kowita, typ int). Dlaczego liczba 100? Przypatrz si\u0119 uwa\u017cnie tablicy kod\u00f3w ASCII z poprzedniego linku (kolumna DEC) lub <a href=\"https:\/\/www.rapidtables.com\/code\/text\/ascii-table.html\">tutaj<\/a>. Kolejna literka po <strong>d<\/strong> to <strong>e<\/strong> &#8211; czyli kod ASCII 101 i tak dalej. Co wi\u0119cej, mo\u017cemy <strong>odejmowa\u0107 literki<\/strong> od siebie, bo to b\u0119dzie zrozumia\u0142e jako&#8230; odejmowanie liczb ca\u0142kowitych! Tak wi\u0119c <strong>d-a<\/strong> oznacza 100-97, czyli 3. Jesli wi\u0119c um\u00f3wimy si\u0119, \u017ce pod literk\u0105 <strong>a<\/strong> mamy sterowanie pierwszego LEDa, pod&nbsp;<strong>b<\/strong> drugiego i tak dalej &#8211; to w\u0142a\u015bnie r\u00f3\u017cnica wczytanej literki i znaku <strong>a<\/strong> da nam&nbsp;dobrze okre\u015blenie indeksu tablicy dla konkretnego LED-a! Zapisane jest to w linii #6 poni\u017cszego kodu:<\/p>\n<pre class=\"lang:arduino decode:true\" title=\"Wyliczenie indeksu tablicy piny\">void loop(){\r\n  if(Serial.available()&gt;0){\r\n    c=Serial.read();\r\n    Serial.print(\"Wczyta\u0142em znak = \");\r\n    Serial.println(c);\r\n    int idx=c-'a';\r\n    Serial.print(\"indeks =\");\r\n    Serial.print(idx);\r\n    if(idx&gt;=0&amp;&amp;idx&lt;5){ \/\/gdy mamy 5 LEDow\r\n      Serial.print(\"W\u0142\u0105czam \/ wy\u0142\u0105czam LED-a nr\");\r\n      Serial.print(idx);\r\n      \/\/dalsza cz\u0119\u015b\u0107 kodu\r\n    }\r\n}<\/pre>\n<p>Na ma\u0142\u0105 uwag\u0119 zas\u0142uguje jeszcze linia #9 &#8211; sprawdzenie, czy indeks nie jest wi\u0119kszy ni\u017c liczba pod\u0142\u0105czonych LED-\u00f3w (oczywiste) oraz czy indeks jest wi\u0119kszy od zera. To drugie mo\u017ce nast\u0105pi\u0107&nbsp; gdy, np. omy\u0142kowo wpiszem z klawiatury znak <strong>[<\/strong> (o numerze ASCII 91), wi\u0119c w wyniku odejmowania mamy <strong>nieistnie\u0105cy<\/strong> element tablicy o indeksie 91-97=-6.<\/p>\n<h1>Tablica &#8211; zapami\u0119tanie stan\u00f3w pin\u00f3w<\/h1>\n<p>Drugi problem na naszej li\u015bcie to zapami\u0119tanie stan\u00f3w port\u00f3w cyfrowych Arduino. Chodzi o to, aby po odczytaniu danej literki w\u0142\u0105czy\u0107 LED-a gdy by\u0142 on w stanie wy\u0142\u0105czonym, i wy\u0142\u0105czy\u0107 &#8211; gdy&nbsp; by\u0142 on w\u0142\u0105czony. Arduino nie ma jakiej\u015b specjalnej funkcji do &#8222;zapytania si\u0119&#8221; o aktualny stan portu, dlatego wi\u0119c musimy zrobi\u0107 do samodzielnie. Wykorzystamy pami\u0119\u0107 operacyjn\u0105 p\u0142ytki Arduino, czyli stany port\u00f3w b\u0119dziemy zapisywa\u0107 w zmiennych. Mo\u017ce do tego s\u0142u\u017cy\u0107 zmienna typu logicznego <strong>bool<\/strong>. Przechowuje ona tylko dwie warto\u015bci: 0, czyli fa\u0142sz (<strong>false<\/strong>), oraz liczb\u0119 r\u00f3\u017cn\u0105 od zera, czyli prawd\u0119 (<strong>true<\/strong>). Pewnie nie ma nic z\u0142ego w utworzeniu pi\u0119ciu takich zmiennych dla naszych pi\u0119ciu LED-\u00f3w, ale gdy pod\u0142\u0105czymy ich 20? 30? Dlatego ponownie u\u017cywamy tablice:<\/p>\n<pre class=\"lang:arduino decode:true\" title=\"Sterowanie LED-ami z zapami\u0119tanymi stanami\">bool stan[]={false,false,false,false,false};\r\nvoid loop(){\r\n  if(Serial.available()&gt;0){\r\n  c=Serial.read();\r\n  int idx=c-'a';\r\n  if(idx&gt;=0&amp;&amp;idx&lt;5)\/\/gdy mamy 5 LEDow\r\n    if(stan[idx]==true){\r\n      digitalWrite(piny[idx],HIGH);\r\n      stan[idx]=false;\r\n    }\r\n    else{\r\n      digitalWrite(piny[idx],LOW);\r\n      stan[idx]=true;\r\n    }\r\n  else\/\/jesli idx rozny od zera to moze... nasza pauza?\r\n  if(c=='#') delay(200);<\/pre>\n<p>Na pocz\u0105tku (linia #1) wprowadzamy zmienn\u0105 tablicow\u0105&nbsp;<strong>stan<\/strong> z informacj\u0105 o wy\u0142\u0105czeniu wszystkich LED-\u00f3w (pi\u0119\u0107&nbsp;<strong>false<\/strong>-\u00f3w). Kluczowe s\u0105 linie #7-14, gdzie sprawdzamy stan portu i je\u015bli jest on w\u0142\u0105czony (warto\u015b\u0107 true) to wy\u0142\u0105czamy LED-a i zmieniamy stan na false (linia #9), a gdy jest wy\u0142\u0105czony (warto\u015b\u0107 false &#8211; u nas &#8222;w przeciwnym przypadku&#8221; linia #11) to w\u0142\u0105czamy LED-a i tak\u017ce zmieniamy stan portu &#8211; tym razem na true (linia #13).&nbsp;<\/p>\n<p>Program ponownie akceptuje ca\u0142e sekwencje rozkaz\u00f3w (&#8222;zdania&#8221;) a dodatkowo nie potrzebuje ju\u017c oddzielnej literki dla w\u0142\u0105czenia (poprzednio ma\u0142a literka) i wy\u0142\u0105czenia (poprzednio du\u017ca literka) LED-a. Piszemy wi\u0119c zdania typu &nbsp; abcde######edcba##a##a##b##b##c##c##b##b&nbsp; i obserwujemy p\u0142ytk\u0119 stykow\u0105.<\/p>\n<h1>Podsumowanie<\/h1>\n<p>Wszystko da\u0142o si\u0119 tak prosto zapisa\u0107 dzi\u0119ki <strong>tablicom<\/strong> oraz sprytnie wyliczonemu indeksowi tablicy (<strong>kodowanie ASCII<\/strong>). Jak wida\u0107 indeks wykorzystali\u015bmy dwukrotnie &#8211; raz w odniesieniu do w\u0142\u0105czania\/wy\u0142\u0105czania LED-a (funkcja digitalWrite i LEDy pod\u0142\u0105czone do port\u00f3w zapisanych w tablicy <strong>piny<\/strong>) a drugi raz do zapisu stanu portu cyffrowego Arduino (tablica <strong>stan<\/strong>). Si\u0142\u0119 tego programy docenimy w\u00f3wczas, gdy pod\u0142\u0105czymy du\u017co LED\u00f3w (np. 20) i jedyne rozbudowanie tego kodu polega\u0107 b\u0119dzie na&#8230; zmienie sta\u0142ej MAX w pierwszej linii programu &#8211; a nie dopisywaniu prawie identycznych linii kodu dla ka\u017cdego nowego LED-a (i jego stanu!).<\/p>\n<p>Prosz\u0119 przemy\u015ble\u0107 dzisiejsz\u0105 lekcj\u0119, bo za tydzie\u0144 ponownie spotykamy si\u0119 z tablicami (no i z wy\u015bwietlaczem siedmiosegmentowym).<\/p>\n<p style=\"text-align: right;\"><em>(c) Ewelina &amp; KG<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Na ostatnich zaj\u0119ciach kontynuowali\u015bmy nauk\u0119 obs\u0142ugi led\u00f3w przez monitor szeregowy. Tym razem nie ograniczali\u015bmy si\u0119 do sterowania wszystkimi ledami jednocze\u015bnie, a d\u0105\u017cyli\u015bmy do mo\u017cliwo\u015bci dowolnego w\u0142\u0105czania i wy\u0142\u0105czania pojedynczych lampek. Podczas tych zaj\u0119\u0107 uczyli\u015bmy si\u0119 sprytnego (zaawansowanego?) wykorzystania tablic. Switch &#8230; case Na zaj\u0119ciach wykorzystali\u015bmy uk\u0142ady przygotowane tydzie\u0144 temu. Pod\u0142\u0105czyli\u015bmy je w taki sam spos\u00f3b. [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":890,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[52],"tags":[183,187,189,99,185,186,188],"class_list":{"0":"post-920","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","6":"hentry","7":"category-fibot","8":"tag-ascii","9":"tag-bool","10":"tag-false","11":"tag-led","12":"tag-monitor-szeregowy","13":"tag-switch","14":"tag-true","16":"post-with-thumbnail","17":"post-with-thumbnail-large"},"_links":{"self":[{"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=\/wp\/v2\/posts\/920","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=920"}],"version-history":[{"count":21,"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=\/wp\/v2\/posts\/920\/revisions"}],"predecessor-version":[{"id":945,"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=\/wp\/v2\/posts\/920\/revisions\/945"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=\/wp\/v2\/media\/890"}],"wp:attachment":[{"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=920"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=920"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/physics.uwb.edu.pl\/wf\/fi-bot\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=920"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}