<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="pl-pl">
<link rel="self" type="application/atom+xml" href="https://forum.atnel.pl/feed.php?f=57&amp;t=6137&amp;mode" />

<title>ATNEL tech-forum</title>
<link href="https://forum.atnel.pl/index.php" />
<updated>2014-08-20T09:17:52+01:00</updated>

<author><name><![CDATA[ATNEL tech-forum]]></name></author>
<id>https://forum.atnel.pl/feed.php?f=57&amp;t=6137&amp;mode</id>
<entry>
<author><name><![CDATA[WoodPaker]]></name></author>
<updated>2014-08-20T09:17:52+01:00</updated>
<published>2014-08-20T09:17:52+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=92126#p92126</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=92126#p92126"/>
<title type="html"><![CDATA[Re: V-USB na Atmega]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=92126#p92126"><![CDATA[
<strong><span style="font-size: 150%; line-height: normal">usbFunctionWrite()</span></strong><br /><br />Tak jak pisałem wyżej funkcja ta służy do odbierania danych wysyłanych do urządzenia. Np. w programatorze <em>USBasp</em> wysyłamy ciąg danych z PC do programatora, które mają zostać zapisane w programowanym procesorze. Odbiór danych z PC odbywa się właśnie poprzez funkcję <em>usbFunctionWrite()</em><br />Składnia funkcji jest następująca (odrazu z małym przykładem wykorzystania)<br />[syntax=c]static uchar buffer&#91;64&#93;;<br />static uchar currentPosition, bytesRemaining;<br /><br />uchar usbFunctionWrite(uchar *data, uchar len)<br />{<br />    uchar i;<br />    if(len &gt; bytesRemaining)                <br />        len = bytesRemaining;               <br />    bytesRemaining -= len;<br />    for(i = 0; i &lt; len; i++)<br />        buffer&#91;currentPosition++&#93; = data&#91;i&#93;;<br />    return bytesRemaining == 0;             <br />}[/syntax]<br /><br />Jak widać składnia i działanie jest bardzo podobne do <em>usbFunctionRead()</em>.  Powyższy przykład pokazuje jak zapisać dane do bufora w pamięci RAM.<br /><br />To przyszedł czas na<br /><br /><strong><span style="font-size: 150%; line-height: normal">USB &lt;--&gt; PC</span></strong><br /><br />W tej części kursu postaram się pokazać na prostym przykładzie jak przy pomocy programu napisanego w <strong>C </strong>(np. <strong>VISUAL C++</strong>) pod Windows porozumiewać się z naszym urządzeniem. Takie hello world przy pomocy V-USB. Na początek program zapalający i gaszący diodę po naciśnięciu przycisku <strong>zapal/zgaś</strong> na ekranie naszego komputera. Ale zanim to nastąpi omówię w jaki sposób podłączać i wyszukiwać nasze urządzenie z poziomu programu PC.<br /><br /> <br /><br />Po pierwsze trzeba dołączyć plik nagłówkowy pozwalający na komunikacje z USB. Plik ten uzyskamy zmieniając nazwę<em> lusb0_usb.h</em> na <em>usb.h</em> z katalogu sterowników libusb, które musimy zainstaloać (te same, które instaluje się żeby móc korzystać z USBasp)<br /><br />[syntax=c]#include &quot;usb.h&quot; // plik nagłówkowy z funkcjami do sterowania mikrokontrolerem[/syntax]<br /><br />Od tej chwili możemy korzystać z połączenia AVR&lt;-&gt;PC poprzez USB. Oczywiście wcześniej należy użyć odpowiednich funkcji.<br /><br />Na początek stwórzmy przycisk, którym będziemy sprawdzać czy nasze urządzenie jest włożone do gniazda i jeśli jest to połączymy je z programem.<br /><br />Do tego celu służą instrukcje<br /><br /> usb_find_busses(); //**************************  szukamy portów USB<br /> usb_find_devices(); //************************** szukamy urządzeń<br /><br />Nastepnie musimy przeszukać uzyskaną w ten sposób bazę podłączonych rządzeń w celu znalezienia naszego. Nasze urządzenie rozpoznajemy poprzez<strong> VendorID</strong> oraz <strong>ProductID</strong>, które ustaliliśmy wcześniej w naszym programie <br /><br /> <br />[syntax=c]structusb_bus      *bus;<br />structusb_device   *dev;<br /> <br />usb_init();             // initialize libusbusb_find_busses();<br />usb_find_devices();<br />for(bus=usb_get_busses(); bus; bus=bus-&gt;next){for(dev=bus-&gt;devices; dev; dev=dev-&gt;next){// use dev-&gt;descriptor to identify device here}}[/syntax]<br />W ten sposób podłączamy nasze urządzenie pod nasz program. Flaga is_connected jest ustawiana w chwili gdy w zmiennej <em>usb_handle</em> znajdzie się hak do naszego urządzenia.<br /><br />OK, mamy podłączone urządzenie do programu. Można wysłać pierwszą wiadomość. Informacje wysyła się przy użyciu funkcji <em>usb_control_msg()</em>, która ma następującą składnie<br /><br />[syntax=c]int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);[/syntax]<br /><br />A w wyniku zwraca liczbę otrzymanych bajtów lub (-1) w przypadku błędu. (<a href="http://libusb.sourceforge.net/doc/function.usbcontrolmsg.html"  class="postlink">http://libusb.sourceforge.net/doc/function.usbcontrolmsg.html</a>)<br /><br /> <br /><br />[syntax=c]nBytes = usb_control_msg(usb_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USB_NASZA_KOMENDA, WARTOSC, 0, (char *)buffer, sizeof(buffer), 5000);//wysyłamy komendę ID: 2,  USB_NASZA_KOMENDA[/syntax]<br /><br />Zapewne wielu z was zastanawia się czym jest ten zestaw komend/poleceń USB_TYPE_VENDOR | USB_RECIP_DEVICE |USB_ENDPOINT_IN<br /><br />Otóż jeżeli wykorzystujemy metodę <em>usbFunctionWrite()</em>, która służy do odczytywania danych wysyłanych z PC (lub innego urządzenia) powinniśmy użyć tej składni<br /><br />[syntax=c]int realNumBytes = usb_control_msg(<br />        handle,             // handle obtained with usb_open()<br />        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, // bRequestType<br />        MY_REQUEST_ID,      // bRequest<br />        value,              // wValue<br />        index,              // wIndex<br />        buffer,             // pointer to buffer containing data<br />        numBytesInBuffer,   // wLength<br />        timeoutInMilliseconds<br />    );[/syntax]<br /><br />Jeżeli natomiast dane odczytujemy z naszego urządzenia to korzystamy z takiego zestawu<br /><br />[syntax=c]int realNumBytes = usb_control_msg(<br />        handle,             // handle obtained with usb_open()<br />        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, // bRequestType<br />        MY_REQUEST_ID,      // bRequest<br />        value,              // wValue<br />        index,              // wIndex<br />        buffer,             // pointer to destination buffer<br />        numBytesRequested,  // wLength<br />        timeoutInMilliseconds<br />    );[/syntax]<br />Więcej informacji na <a href="http://vusb.wikidot.com/host-software"  class="postlink">http://vusb.wikidot.com/host-software</a>, a ja za chwilę wytłumaczę znaczenie poszczególnych poleceń<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=1425">WoodPaker</a> — 20 sie 2014, o 09:17</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[WoodPaker]]></name></author>
<updated>2014-02-27T20:31:38+01:00</updated>
<published>2014-02-27T20:31:38+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=72320#p72320</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=72320#p72320"/>
<title type="html"><![CDATA[Re: V-USB na Atmega]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=72320#p72320"><![CDATA[
<strong><span style="font-size: 150%; line-height: normal">usbFunctionRead();</span></strong><br /><br />Przyszedł czas na wytłumaczenie w jaki sposób przesyłać większe ilości danych odczytywanych w locie. Do tego celu służy procedura <em>usbFunctionRead()</em>. Jednakże żeby jej użyć należy najpierw w pliku usbconfig.h zmienić<br /><br />[syntax=c]#define USB_CFG_IMPLEMENT_FN_READ       0 //funkcja usbFunctionread()<br />#define USB_CFG_IMPLEMENT_FN_WRITE      0// funkcja usbFunctionWrite()[/syntax]<br /><br /> <br /><br /> na<br />[syntax=c]#define USB_CFG_IMPLEMENT_FN_READ       1<br />#define USB_CFG_IMPLEMENT_FN_WRITE      1[/syntax]<br /><br />To umożliwi wykorzystanie tej funkcji w naszym programie. Dobrze, zatem czas napisać do czego właściwie służy ta funkcja. Otóż jest ona wywoływana w chwili gdy sterownik żąda wysłania jakichś danych z naszego urządzenia. Na początku wywoływana jest zawsze funkcja <em>usbFunctionConfig()</em>, a następnie wywoływana jest jedna z funkcji <em>usbFunctionRead()</em> lub <em>usbFunctionWrite()</em>. W rzeczywistości jest tak, że funkcja <em>Read</em> służy do wysyłania danych z urządzenia, a funkcja <em>Write</em> do odczytywania danych przychodzących. Żeby jednak nastąpiło wywołanie jednej z tych funkcji to funkcja Setup musi zwrócić wartość<strong> USB_NO_MSG</strong> tak jak w  przykładzie poniżej. <br />[syntax=c]USB_PUBLIC uchar usbFunctionSetup(uchar data&#91;8&#93;)<br />{<br />    usbRequest_t *rq = (void *)data; // cast data to correct type<br />    switch(rq-&gt;bRequest)<br />    {<br />        case USB_READ: //Wywołujemy funkcje nazwaną przez nas USB_READ<br />        {<br />            //mignijmy diodą (w tym miejscu możemy skonfigurować co i jak zostanie przekazane funkcji read/write)<br />            LED_PORT&amp;=~(1&lt;&lt;LED_P);<br />            _delay_ms(250);<br />            LED_PORT|=(1&lt;&lt;LED_P);    <br />            return USB_NO_MSG; //sterowanie zostanie przekazane do funkcji read lub write w zależności od wywołania z zewnątrz<br />        }<br /><br />}[/syntax]<br />Funkcję <em>usbFunctionRead() </em>można wykorzystać np do odczytu większej ilości danych z pamięci EEPROM. Mozliwości jest wiele to tylko jeden z przykładów ale warto pamiętać jedną aczkolwiek bardzo ważną rzecz. Mianowicie to, że funkcja ta zwraca max 254 bajtów. Jakby jednak ktoś chciał to da się zwiększyć ilość danych przesyłanych przez nasz program do komputera. Aby to zrobić należy:<br /><br />ustawić zmienną<strong> USB_CFG_LONG_TRANSFERS</strong> na 1 w pliku<em> usbconfig.h.</em><br />[syntax=c]#define USB_CFG_LONG_TRANSFERS          1[/syntax]<br /><br />to pozwoli nam na przesyłanie danych powyżej 254 bajtów. Oczywiście powoduje to także zwiększenie ilości zajętej pamięci naszego procesora przez sterownik.<br /><br />Teraz możemy wysyłać do hosta więcej niż 254 bajty.<br /><br />[syntax=c]USB_PUBLIC uchar usbFunctionRead(uchar *data, uchar len){<br />    uchar i;<br /><br />    for(i =0; dSent &lt;1024&amp;&amp; i &lt; len; i++, dSent++)<br />        data&#91;i&#93;='0'+i;<br />    <br />    // zakończ przesył gdy został wysłany ostatni bajt<br />    if(i &amp;&amp; dSent ==1024) <br />        data&#91;i-1&#93;=0;// NULL<br />                <br />    return i;// zwróć dokładną ilość wysłanych danych[/syntax]<br /> Jak widać w powyższym przykładzie funkcja usbFunctionRead() wysyła dane poprzez wskaźnik uchar *data. Dane trafiaja wprost do naszego hosta. Pamiętać należy, że funkcja MUSI zwrócić dokładną liczbę wysłanych danych. Jeżeli funkcja zwróci mniejszą liczbę program na komputerze nie będzie w stanie odczytać wszystkich bajtów wysłanych przez urządzenie, jeżeli zwróci większą liczbę niż liczba wysłanych danych  to program się wysypie próbując odczytać nieistniejące dane.<br /><br />Jeśli z jakichś powodów wewnątrz funkcji wystąpi błąd (np odczytując dane z EEPROM okaże się, że jest błąd odczytu) można poinformować sterownik o błędzie wysyłając jako wynik działania funkcji wartość (-1) 0xff.<br /><br />[syntax=c]return 0xff;[/syntax]<br /><br />To poinformuje sterownik i nasz program o tym, że wystąpił błąd.<br /><br />Bardziej wnikliwi użytkownicy mogą spróbować przeanalizować działanie funkcji <em>usbReadWrite() </em>czytając źródła USBasp dostępne pod adresem <a href="https://github.com/whitequark/usbasp/blob/master/main.c"  class="postlink">https://github.com/whitequark/usbasp/blob/master/main.c</a><br /><br /><span style="color: #FF0000">Dyskusja na temat</span> <a href="http://forum.atnel.pl/post71949.html#p71949"  class="postlink">http://forum.atnel.pl/post71949.html#p71949</a><br /><span style="color: #FF0000">Różowo-zielony (czyli s...[śliczny] - cenzura mirekk36 <img src="https://forum.atnel.pl/images/smilies/icon_e_wink.gif" alt=";)" title="Puszcza oko" /> ) J.</span><p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=1425">WoodPaker</a> — 27 lut 2014, o 20:31</p><hr />
]]></content>
</entry>
<entry>
<author><name><![CDATA[WoodPaker]]></name></author>
<updated>2014-02-25T01:11:59+01:00</updated>
<published>2014-02-25T01:11:59+01:00</published>
<id>https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=71920#p71920</id>
<link href="https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=71920#p71920"/>
<title type="html"><![CDATA[V-USB na Atmega]]></title>

<content type="html" xml:base="https://forum.atnel.pl/viewtopic.php?t=6137&amp;p=71920#p71920"><![CDATA[
<strong><span style="font-size: 150%; line-height: normal">Czym jest V-USB?</span></strong><br /><br />V-USB jest to biblioteka napisana z myślą o procesorach ATMEL umożliwiająca oprogramowanie komunikacji poprzez interfejs USB. Wprawny programista może spróbować przerobić bibliotekę pod inne procesory. Bibliotekę można ściągnąć ze strony projektu <!-- m --><a class="postlink" href="http://www.obdev.at/products/vusb/index.html" >http://www.obdev.at/products/vusb/index.html</a><!-- m -->. W tym miejscu dowiesz się jak obsługiwać USB od strony projektu opartego na procesorze ATMEL oraz od strony środowiska systemu operacyjnego Twojego PC.<br />Schematy podłączeń<br /><br />Zgodnie z zaleceniami końcówki D+ i D- powinny być podłączone do nóżek odpowiedzialnych za przerwania procesora (INT0, INT1) aczkolwiek łącze D+ interfejsu podłączone być powinno zawsze do nóżki INT0 natomiast D- może być podłączone gdzie chcemy. Dodatkowo ważnym jest aby napięcie wychodzące z łączy D+ i D- było na poziomie 3.6V co można uzyskać na kilka sposobów (patrz schematy poniżej). Zaleca się też podłączenie rezystora pull-up 1.5k do D- oraz pull-up lub pull-down 1M do D+ żeby uniknąć interferencji kiedy USB nie jest podłączone.<br />Jako, że USB zasilane jest napięciem 5V do jego obniżenia można użyć diody Zenera<br /><br /><a href="http://forum.atnel.pl/_obrazki/o/1425/278f9286fd83795dbdd0095b346771e2.jpg"  class="postlink"><img src="http://forum.atnel.pl/_obrazki/o/1425/278f9286fd83795dbdd0095b346771e2.jpg" alt="Obrazek" /></a><br /><em><strong>Podłączenie 1</strong></em><br /><br /><a href="http://forum.atnel.pl/_obrazki/o/1425/ea4376300fc81a1bb8e9943a2daf42a6.jpg"  class="postlink"><img src="http://forum.atnel.pl/_obrazki/o/1425/ea4376300fc81a1bb8e9943a2daf42a6.jpg" alt="Obrazek" /></a><br /><strong><em>Podłączenie 2</em></strong><br /><br /><a href="http://forum.atnel.pl/_obrazki/o/1425/3b5ca9a7836bd431a23e2c421a66ad5d.jpg"  class="postlink"><img src="http://forum.atnel.pl/_obrazki/o/1425/3b5ca9a7836bd431a23e2c421a66ad5d.jpg" alt="Obrazek" /></a><br /><strong><em>Podłączenie 3</em></strong><br /><br />Rys 1. Sposoby obniżenia napięcia na wyjściu USB<br /><br /><br /><a href="http://forum.atnel.pl/_obrazki/o/1425/b2f31e09453205d115840b5f08f64769.jpg"  class="postlink"><img src="http://forum.atnel.pl/_obrazki/o/thumb/1425/b2f31e09453205d115840b5f08f64769.jpg" alt="Obrazek" /></a><br />Rys 2. Schemat wtyczki<br /><br />  <br /><strong><span style="font-size: 150%; line-height: normal">Przygotowanie do pracy</span></strong><br /><br />Zanim zaczniemy należy przygotować stanowisko pracy. Nie piszę już o samym układzie ale bardziej mam na myśli przygotowanie środowiska programistycznego tj. ściągnięcie biblioteki i przygotowanie jej do pracy z naszym programem.<br /><br />Po ściągnięciu biblioteki rozpakowujemy ją do wybranego katalogu. Należy też ściągnąć sterowniki USB dla ©MS WINDOWS, dzięki którym będziemy mogli &quot;rozmawiać&quot; z naszym układem. Można to zrobić ze strony projektu libusb-win32. Moduł ten umożliwi nam skompilowanie sterowników dedykowanych dla naszego układu. Ale o tym później.<br /><br />Kopiujemy folder usbdrv do naszego katalogu projektu. Wchodzimy do katalogu i tworzymy kopię pliku usbconfig_prototype.h jako usbconfig.h. Lokalizujemy linie definiującą porty IO oraz taktowanie zegara i jeśli to potrzebne uaktualniamy je do odpowiednich danych. W tym miejscu chciałbym zaznaczyć, że nasz procesor <strong>MUSI</strong> byś taktowany jedną z wartości: 12 MHz, 15 MHz, 16 MHz oraz 20 MHz lub 12.8 MHz w ostateczności 16.5 MHz +/- 1%. Inne wartości taktowania spowodują, że nie będzie możliwości używania naszego urządzenia.<br /> Dlatego należy używać zewnętrznych kwarców i oczywiście odpowiednio obliczyć i ustawić FUSE BITy. (ja ustawiam low = <strong>AF</strong> high = <strong>DF</strong> ext. = <strong>01</strong>)<br /><br /> <br />[syntax=c]#ifndef __usbconfig_h_included__<br />#define __usbconfig_h_included__[/syntax]<br /><br />Wstawiamy:<br />[syntax=c]#define F_CPU 12000000<br />#define USB_CFG_IOPORTNAME      D<br />#define USB_CFG_DMINUS_BIT      3<br />#define USB_CFG_DPLUS_BIT       2<br />#define USB_CFG_CLOCK_KHZ       12000[/syntax] <br />Powinniśmy też skonfigurować nazwę naszego urządzenia oraz numer, przez który będzie nas rozpoznawać nasz sterownik WINDOWS.<br />[syntax=c]#define USB_CFG_DEVICE_ID 0x66, 0x0E /* ustawiamy ID urządzenia */ <br />#define USB_CFG_VENDOR_NAME 'e', '-', 'w', 'o', 'o', 'd', 'y', '.', 'i', 'n', 'f', 'o' /* Nazwa producenta */ <br />#define USB_CFG_VENDOR_NAME_LEN 12 /* Długość nazwy producenta */ <br />#define USB_CFG_DEVICE_NAME     'W', 'O', 'O', 'D', 'U', 'S', 'B' /* Nazwa urządzenia */<br />#define USB_CFG_DEVICE_NAME_LEN 7 /* Długość nazwy urządzenia *//[/syntax]<br /><br />Przydaje się także informacja o tym czy nasze urządzenie korzysta z zasilania USB czy nie<br /><br />[syntax=c]#define USB_CFG_IS_SELF_POWERED         0<br />#define USB_CFG_MAX_BUS_POWER           50[/syntax]<br /><br />Tak naprawdę plik usbconfig.h jest na tyle dobrze opisany, że można samemu zaglądnąć do środka i zorientować się co jeszcze można ustawić. Zapraszam do lektury.<br /><br /><strong><span style="font-size: 150%; line-height: normal">Czas na main.c</span></strong><br /><br /><br />Poniżej mamy podstawowy szkielet programu dla μprocesora obsługującego protokół i łącze USB<br /><br />[syntax=c]#include&lt;avr/io.h&gt;<br />#include&lt;avr/interrupt.h&gt;<br />#include&lt;avr/wdt.h&gt;<br /><br />#include&quot;usbdrv.h&quot;<br /><br />#define F_CPU 12000000L<br />#include&lt;util/delay.h&gt;<br /><br />USB_PUBLIC uchar usbFunctionSetup(uchar data&#91;8&#93;){<br />        return0;// Narazie nic nie rób<br />}<br /><br />int main(){<br />        uchar i;<br /><br />    wdt_enable(WDTO_1S);// uaktywnij jednosekundowy watchdog <br /><br />    usbInit();<br />        <br />    usbDeviceDisconnect();// Wymuś przenumerowanie<br />    for(i =0; i&lt;250; i++){// Odczekaj około 500 ms<br />        wdt_reset();// Poinformuj watchdog, ze procesor działa<br />        _delay_ms(2);<br />    }<br />    usbDeviceConnect();<br />        <br />    sei();// Aktywuj przerwania po renumeracji<br />        <br />    while(1){<br />        wdt_reset();// wiadomo, jak wyżej<br />        usbPoll();<br />    }<br />        <br />    return0;<br />}[/syntax] <br />Co tu mamy? Jak to działa? Małe wytłumaczenie<br /><br />    Zaimplementujmy funkcję<em> usbFunctionSetup()</em> obsługującą wywołania USB (co i jak opiszę później)<br />    W częsci głównej programu ustawiamy watchdog na 1 s, która zresetuje procesor jeśli coś pójdzie nie tak i nie zostanie wywołana funkcja <em>wdt_reset()</em> w czasie 1000 ms. To zabezpiecza program przed jakimiś nietypowymi zachowaniami i pozwala uniknąć użytkownikowi odłączania i ponownego przyłączania urządzenia jeśli stanie się coś dziwnego.<br />    Wywołajmy<em> usbInit()</em> - funkcję inicjującą działąnie biblioteki V-USB.<br />    Wymuśmy przenumerowanie USB poprzez użycie <em>usbDeviceDisconnect()</em>, a następnie po 500ms <em>usbDeviceConnect()</em>. Na wypadek resetu Watchdog.<br />    Włączamy przerwania<br />    Na sam koniec nieskończona pętla resetująca watchdog i wywołująca funkcję obsługi USB <em>usbPool()</em>.<br /><br />Jak dotąd wszystko wygląda chyba prosto. Zatem wypadałoby napisać jak urządzenie ma odpowiadać na zewnętrzne wywołanie.<br />Aby lepiej zrozumieć w jaki sposób procesor odpowiada na zewnętrzne wywołania USB należy przybliżyć działanie trzech podstawowych funkcji. Ale to w następnej części<br /><br /><strong><span style="color: #808000">------------------------ [ Dodano po: 16 minutach ]</span></strong><br /><br /><strong><span style="font-size: 150%; line-height: normal">Dwie funkcje</span></strong><br /><br />Jak wspominałem w części poprzedniej aby zacząć pisanie programów do komunikacji USB należy poznać dwie, no może trzy podstawowe funkcje służące do komunikacji <strong>URZĄDZENIE-KOMPUTER.</strong><br /><br />Pierwszą funkcją, która musi być zawsze zdefiniowana jest <em>usbFunctionSetup(uchar dane[8])</em>. Wywołując wezwanie USB z poziomu komputera uruchamiana jest zawsze ta funkcja. Jej wywołanie z poziomu procesora jest następujące:<br /><br /> <br /><br />[syntax=c]USB_PUBLIC uchar usbFunctionSetup(uchar data&#91;8&#93;)<br />{<br />    usbRequest_t *rq = (void *)data; // zamiana data na właściwy typ<br />    switch(rq-&gt;bRequest)<br />    {[/syntax]<br /><br />usbRequest jest zdefiniowany następująco<br /><br />[syntax=c]typedef struct usbRequest{<br /><br />uchar bmRequestType;<br /><br />uchar bRequest;<br /><br />usbWord_ twValue;  <br /><br />usbWord_ twIndex;<br /><br />usbWord_ twLength;<br />}usbRequest_t;[/syntax]<br /><br /><br /><br />Wszystkie dane są przekazywane od strony komputera poprzez funkcje wywołującą działanie programu poprzez USB ale co i jak napiszę w kolejnej części. W tej chwili zajmiemy się tylko funkcjami usbFunctionSetup, usbFunctionRead oraz usbFunctionWrite.<br /><br /><strong>bmRequestType</strong> - informuje sterownik o tym czy chcemy dane przesyłać z czy do urządzenia<br /><br /><strong>bRequest </strong>- rodzaj wywołania (zazwyczaj ustalane przez programiste)<br /><br /><strong>twValue</strong> - wartość przesyłana do urządzenia<br /><br /><strong>twIndex</strong> - index (w rzeczywistości kolejna wartość wysyłana przez programistę)<br /><br /><strong>twLength</strong> - ilość danych<br /><br /><br />Funckie <em>usbFunctionSetup</em> możemy wykorzystać do wysyłania danych statycznych. Jeśli chcemy przesyłać dane odczytywane &quot;w locie&quot; winnismy użyć funkcji <em>usbFunctionRead.</em><br /><br />Przyszedł zatem czas na napisanie przykładowego programu służącego do zapalenia i gaszenia diody i przy okazji przesłania jakiegoś krótkiego tekstu np nazwy urządzenia. Ponieważ już wiadomo jak skonfigurować sterownik (patrz USB - AVR - biblioteka VUSB - część I) więc ten etap pominę.<br />[syntax=c]/*<br /> * USBmain.c<br /> *<br /> * Created: 2014-02-13 00:22:21<br /> *  Author: Dr inż. W.K.<br /> */ <br /><br />#define F_CPU 12000000L<br /><br />#include&lt;avr/io.h&gt;<br />#include&lt;avr/interrupt.h&gt;<br />#include&lt;avr/wdt.h&gt;<br /><br /><br />#include&lt;util/delay.h&gt;<br />#include&quot;usbdrv.h&quot;<br /><br /><br />/definiujemy stałe opisujące konkretne wywołania<br />#define USB_TEST 0     //test USB, który w odpowiedzi zwraca np nazwę urządzenia<br />#define USB_LED_OFF 1 //Zgaś diodę<br />#define USB_LED_ON 2 //zapal diodę<br /><br />#define LED_DDR DDRC<br /><br />#define LED_PORT PORTC<br /><br />#define LED_PIN (1&lt;&lt;PC0)<br /><br /><br /><br /><br />USB_PUBLIC uchar usbFunctionSetup(uchar data&#91;8&#93;)<br />{<br /><br />    usbRequest_t *rq = (void *)data; // cast data to correct type<br />    switch(rq-&gt;bRequest)<br />    { <br />        case USB_TEST:<br />        {<br />            usbMsgPtr=&quot;USBTest&quot;; //usbMsgPtr słuzy do przekazywania łańcucha znaków do programu wywołującego<br />        <br />             return 7; //return zawsze powinno zwracać liczbę znaków jaką przekazujemy na zewnątrz (w tym wypadku 7)<br />        <br />        }<br />        case USB_LED_ON:<br />        {<br />            LED_PORT|= LED_PIN; // turn LED on<br />            usbMsgPtr=&quot;ON&quot;; //Przekaż ciąg znaków o treści ON<br /><br />            return 2;//Zwracamy dwa znaki (ON)<br />        }<br />        case USB_LED_OFF:<br />        {    <br />            LED_PORT&amp;=~LED_PIN               <br />            usbMsgPtr = &quot;OFF&quot; //Przekaż ciąg znaków o treści OFF<br />            <br />            return 3; //zwracamy trzy znaki (OFF)<br />        }        <br />    }    <br />    return 0;//Na wszelki wypadek zwróćmy zero (jakby została wywołana jakaś nieobsługiwana funkcja)<br />}<br /><br />int main(){<br />    LED_DDR=LED_PIN;<br />    <br />    wdt_enable(WDTO_2S);// uaktywnij dwusekundowy watchdog<br /><br />    usbInit();<br />    <br />    usbDeviceDisconnect();// Wymuś przenumerowanie<br />    for(i =0; i&lt;250; i++)// Odczekaj około 500 ms<br />    {<br />        wdt_reset();// Poinformuj watchdog, ze procesor działa<br />        _delay_ms(2);<br />    }<br />usbDeviceConnect();<br /><br />sei();// Aktywuj przerwania po renumeracji<br /><br />while(1)<br />{<br />    wdt_reset();// wiadomo, jak wyżej<br />    usbPoll();<br />}<br /><br />return;<br />}[/syntax]<br /><br />Mam nadzieję, że choć trochę rozjaśniłem sposoby komunikacji URZĄDZENIE&lt;--&gt;KOMPUTER poprzez USB. W następnej części wytłumaczę jak można przekazywać większą ilość danych niż 8 znaków (w dwie strony) oraz jak porozumiewać się z naszym procesorem z poziomu komputera (WIN/LINUX). Napiszę też trochę informacji na temat numerowania VENDOR/DEVICE aby pozostać legalnym.<p>Statystyki: Napisane przez <a href="https://forum.atnel.pl/memberlist.php?mode=viewprofile&amp;u=1425">WoodPaker</a> — 25 lut 2014, o 01:11</p><hr />
]]></content>
</entry>
</feed>