Z pogranicza

Budowa modułu kontrolnego na USB przy pomocy mikrokontrolera AVR

  • 2013-12-19 18:03
  • 8 komentarzy
  • 12117 odsłon
  • Oceń ten tekst jako pierwszy
Spis treści

     1 Słowa wstępu
     2 Co nam potrzebne
     3 Budujemy układ
          3.1 Schemat
     4 Kofigurujemy Środowisko
          4.1 Co nam potrzebne
     5 Programujemy mikrokontroler
          5.1 Szybka teoria
               5.1.1 Wyjście
               5.1.2 Wejście
               5.1.3 Prosty program
          5.2 Piszemy program dla mikrokontrolera
               5.2.1 Tworzymy projekt
               5.2.2 Kod
               5.2.3 Konfiguracja VUSB
               5.2.4 Tworzymy sterowniki
     6 Piszemy aplikację sterującą dla Windows
          6.1 Budujemy formę
          6.2 Programujemy
     7 Efekt końcowy


Słowa wstępu


Artykuł został stworzony dla początkujących, dlatego czasami przesadnie opisuje niektóre czynności. Brakuje też fachowej terminologi, gdyż znam tylko praktykę, przez co starałem się w logiczny sposób wytłumaczyć niektóre kwestie. Chcę tutaj pokazać jak stworzyć komunikację pomiędzy komputer <--> mikrokontroler - jest to według mnie najużyteczniejsza rzecz, dzięki czemu zbudujemy podstawy do: np. nadajnika, odbiornika.

Co nam potrzebne




Nazwa Zdjęcie Opis Sugerowana cena (allegro.pl)
Programator AVR ISP Bez tego się nie obejdzie. Służy do programowania mikrokontrolera. Ten na obrazku to "Programator USBasp ATMEGA ATMEL AVR ISP" 21zł
Gniazdo ISP Do podłączania programatora do naszego układu 1zł
Atmega168A-PU Można kupić inny, ale wtedy musisz się zaznajomić się z PORTBmi. Ważną sprawą jest pamięć i taktowanie. Procesor musi taktować min. w 12mhz. Pamięć na program min. 5kb (tyle waży ten przykład) 15zł
Kwarc 12mHz W prawie każdym dobrym sklepie elektronicznym. Zawsze możesz wylutować z układów scalonych (ja wylutowałem z starego modemu) 2zł
Diody LED x6 W każdym sklepie elektronicznym kupisz. 0.30zł/szt
Dioda Zenera x2 3V3 W każdym sklepie elektronicznym kupisz. 0.15zł/szt
Rezystory x10 W każdym sklepie elektronicznym kupisz. 2x75R , 1x15R, 1x10kR, 6x1kR (do diód) 0.15zł/szt
Kondensator x3 W każdym sklepie elektronicznym kupisz. 2x27pF (ceramiczny), 1x220uF(elektrolitowy) 0.15zł/szt
Kabel USB Masz pewnie zepsutą myszkę lub inny sprzęt na USB. Coś znajdziesz. 0zł
Razem ok. 40zł


Budujemy układ


To już od ciebie i twojego doświadczenia zależy jak to będzie wyglądało. Amatorsko - na pająka. Możesz zbudować płytkę- lecz to są dodatkowe koszta - wiertła, laminat( plytka pcb) i b327 do wytrawiania miedzi. Jeśli na to się jednak zdecydujesz, to tutaj ściągniesz projekt schematu do programu DipTrace, dzięki któremu będziesz mógł wydrukować sobie płytkę.

Lecz jeśli naprawdę jesteś zielony w temacie elektroniki, podskocz z częściami i 4pakiem do sąsiada elektryka. Pewnie ci pomoże.

Plytka Plytka

Schemat



   


Kofigurujemy Środowisko


W tym celu przygotowałem 54 minutowy materiał video. Pokazałem w nim od zera dalsze czynności (od zainstalowania Windowsa po efekt końcowy). W tym artykule zajmę się samym kodem.


    Film

   

Co nam potrzebne


Nazwa Opis Download Moment w filmie
Eclipse Classic Środowisko programistyczne dla programowania mikrokontrolerów. Alternatywa dla środowiska WinAVR Download 00:00:02
WinAVR Kompilatory & biblioteki, narzędzia Download 00:00:38
MS Visual C++ Środowisko do programowania okienkowego w Windows. Wystarczy wersja Express.
Nie polecam MS Visual C++ 2010 - nie posiada funkcji IntelliSense, dzięki czemu programowanie stanie się praktycznie niemożliwe
Download 00:01:15
Java JDK Potrzebne do uruchomienia Eclipse Download 00:10:42
Eclipse AVR Plugin Plugin do Eclipse który umożliwia programowanie dla mikrokontrolerów Download 00:20:00
libusb-win32 Biblioteka dla C++, dzięki czemu nasz program na Windowsie będzie mógł porozumieć się z mikrokontrolerem. Wraz z biblioteką, jest generator sterowników. Download 00:05:15
vusb Biblioteka dla mikrokontrolera, dzięki czemu będziemy mogli obsłużyć protokół USB Download 00:05:05


Programujemy mikrokontroler


Zanim zaczniemy, musisz zaznajomić się z portami mikrokontrolera:



Szybka teoria


Jak widać na powyższym rysunku, procesor składa się 3 portów. Porty są oznaczone P[Litera portu][Bit/nóżka portu], czyli u nas:
  • PB</a>
  • PC</a>
  • PD</a>
Każdy port ma 8 nóżek (0-7), prócz PC (0-6), i każdy z nich może przyjąć stan wejścia/wyjścia.

Wyjście


Aby ustawić cały port B na stan wyjścia, należy w programie wywołać:
    DDRB = 0xFF; // binarnie 0b1111111 - DDR[LiterkaPortu]

Jeśli chcesz ustawić nóżki w stan wysoki :
    DDRB = 0xFF; // binarnie 0b1111111 
    PORTB = 0xFF; // binarnie 0b1111111 PORT[LiterkaPortu]

Oczywiście nie musi być cały port w stanie wysokim. Jeśli chcesz by nóżka 0, 1, 2 była w trybie wyjścia z stanem wysokim, wykonaj:
    DDRB = 0x07; // binarnie 0b00000111
    PORTB = 0x07; // binarnie 0b00000111

Czyli jak już zauważyłeś, ustawiamy porty poprzez 8bitowe dane, gdzie każdy bit odpowiada za nóżkę procesora.

Wejście


Oprócz wyjścia, możesz odczytywać dane z nóżek (wejście). Aby ustawić port  w stan wejścia:
    DDRB = 0x00; // binarnie 0b0000000 - DDR[LiterkaPortu]

Jeśli chcesz odczytać dane z portu:
    DDRB = 0x00; // binarnie 0b0000000 - DDR[LiterkaPortu]
    twojazmienna = PINB; // PIN[LiterkaPortu]


To tyle z skróconej teori. Jeśli chcesz poszerzyć wiedzę, to skorzystaj z tej strony.

Prosty program


Prosty program to :
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <avr/pgmspace.h>
    #include <avr/wdt.h>
    int main(void){
            DDRB=0xFF; // Ustawiamy port B w stan Wyjścia
            PORTB=0xFF; // Ustawaimy cały port B w stan Wysoki
             for(;;){ // to co programistów przeraża, w mikrokontrolerach jest normalną rzeczą - oznacza nieprzerwanie pracy mikrokontrolera
 
             }
    }

Jak to skompilować? Zobacz film od momentu 00:22:00


Piszemy program dla mikrokontrolera


Zanim wszystko zaczniemy, musisz mieć skonfigurowane środowisko: Jak to zrobić jest pokazane na filmie od momentu: 00:20:00 (zakładając, że Eclipse i JDK już ściągłeś i zainstalowałeś).

Tworzymy projekt


Uruchamiamy Eclipse, następnie File->New->Project. Wybieramy C/C++ -> C Project. Klikamy Dalej, w następnym formularzy uzupełniamy Nazwę projektu. Znów klilamy Dalej i odznaczamy "Debug", i znów Dalej. W kolejnym oknie wybieramy nasz mikrokontroler, i teraz WAŻNE: taktowanie procesora ustaw na 12mhz czyli na 12000000 hz

Kod


Utworzyliśmy projekt. Teraz musisz skopiować folder "usbdrv" do katalogu projektu.
Następnie w projekcie utwórz plik main.c, i uzupełnij go kodem:

/*
 * main.c
 *
 *  Created on: 09-02-2012
 *      Author: Bordeux
 */
#include <avr/io.h> // biblioteki do obsługi µKontrolera
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
 
#include "usbdrv/usbdrv.h" // biblioteka do obsługi USB
#include "usbdrv/oddebug.h" // biblioteka do debugowania
 
USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len){ // 
    return 1;
}
 
USB_PUBLIC uchar usbFunctionSetup(uchar data[8]){ // funkcja wykonywana, gdy µKontroler dostanie polecenie poprzez USB od komputera
usbRequest_t *rq = (void *)data;
static uchar    replyBuf[255]; // bufer danych wyjściowych - odpowiedź µKontrolera na żądanie
 
    if(rq->bRequest == 0){               // rq->bRequest to ID żądania 
        replyBuf[0] = 0x48; //h
        replyBuf[1] = 0x65; //e
        replyBuf[2] = 0x6c; //l
        replyBuf[3] = 0x6c; //l
        replyBuf[4] = 0x6f;   //o
        replyBuf[5] = 0x20;   //space
        replyBuf[6] = 0x77;   //w
        replyBuf[7] = 0x6f;   //o
        replyBuf[8] = 0x72;   //r
        replyBuf[9] = 0x6c;   //l
        replyBuf[10] = 0x64;   //d
        replyBuf[11] = 0x21;   //!
        //Wysyłamy odpowiedź: Hello world!
        return 12; //w wyniku funkcji podajemy długość buffora
    }
    if(rq->bRequest == 1){               // gdy numer żądania to 1, odpowiedz...
        DDRC=data[2]; //odczytaj dane wysłane z programu data[0], data[1] są zarezerwowane do komunikacji
                      //Od data[2] zaczynają się nasze dane wysłane z aplikacji
                      //W programie wysyłamy dane 1 bajtowe, ustawiając port C w stan wejścia/wyjścia
        PORTC=data[2]; // Ustawiamy wybrane porty w programie w stan Wysoki/niski
 
        replyBuf[0] = 0x64; //d 
        replyBuf[1] = 0x6f; //o
        replyBuf[2] = 0x6e; //n
        replyBuf[3] = 0x65; //e
        replyBuf[4] = 0x21; //!
        //Odpowiedź naszego programu: Done!
        return 5; // rozmiar tablicy
    }
    if(rq->bRequest == 2){ // tutaj będziemy zczytywać aktualny stan portu wyjścia C
        replyBuf[0] = PORTC; //odczytanie stanu (nie wejścia - PINC)
        return 1;
    }
    replyBuf[0] = 0xff;                    // gdy komenda jest nieobsługiwana, odpowiedź: 0xFF;
    return 1;                            
}
 
int main(void){
    wdt_enable(WDTO_1S);    //Watchdog Timer - zegar pakietu kontrolnego 
                            //(mechanizm wykorzystywany do przełączenia zdarzenia czy 
                            //zaniechania procesu w momencie zerowania zegara) 
    odDebugInit(); // włącz debugowanie
    usbInit(); // załaduj bibliotekę USB
    sei(); // Włączenie przerwań
    for(;;){    // pętla w nieskończoność, co oznacza że µKontroler nigdy nie zakończy pracy
        wdt_reset(); //resetuj Watch Dog
        usbPoll(); // Tutaj działa biblioteka VUSB
    }
    return 0;
}


Konfiguracja VUSB


Przed kompilacją, musimy skonfigurować bibliotekę VUSB. W tym celu przechodzimy do katalogu vusb, który jest w naszym projekcie. Tworzymy kopię pliku usbconfig-prototype.h, nazywając nowy plik "usbconfig.h". Następnie go edytujemy.
Po
#ifndef __usbconfig_h_included__
#define __usbconfig_h_included__

Wstawiamy:
    #define  F_CPU   12000000 //taktowanie procesora w hz


Po tym odszukujemy:
/* ---------------------------- Hardware Config ---------------------------- */

Zmieniamy dane na :
#define USB_CFG_IOPORTNAME      D
#define USB_CFG_DMINUS_BIT      3
#define USB_CFG_DPLUS_BIT       2


Następnie szukamy:
/* -------------------------- Device Description --------------------------- */

Ustawiamy:
#define USB_CFG_VENDOR_ID       0x18, 0x19 /* = 0x1918 = 6424  - ustawiamy ID producenta   */
#define USB_CFG_DEVICE_ID       0x66, 0x0E /* = 0x0E66 = 3686 - ustawiamy ID urządzenia */
#define USB_CFG_VENDOR_NAME     'B', 'o', 'r', 'd', 'e', 'u', 'x', '.', 'N', 'E', 'T' /* Nazwa producenta */
#define USB_CFG_VENDOR_NAME_LEN 11 /* Długość nazwy producenta */
#define USB_CFG_DEVICE_NAME     'B', 'O', 'R', 'D', 'E', 'U', 'X', '-', 'D', 'X' /* Nazwa urządzenia */
#define USB_CFG_DEVICE_NAME_LEN 10 /* Długość nazwy urządzenia */



Teraz możemy skompilować i wrzucić do µKontrolera, nie zapominając ustawić FuseBity na:
low        = AF
hight    = DF
ext.    = 01


Tworzymy sterowniki


Na szczęście nie musimy ich pisać od podstaw. Użyjemy biblioteki libusb-32. W katalogu tego projektu "libusb-win32-bin-1.2.6.0\bin" jest program "inf-wizard.exe", dzięki któremu wygenerujesz sterowniki.

Piszemy aplikację sterującą dla Windows


Nagrywając i pisząc ten tutorial, założyłem że port C ma 8 nóżek, lecz ma tylko 7 (0-6), z czego 6 do użytku (7 nóżka to reset). Jest to błąd, który nie przerywa programu, więc można go pominąć
Uruchamiamy MS Visual C++, tworzymy nowy projekt. Kopiujemy libusb.lib z folderu "libusb-win32-bin-1.2.6.0\lib\msvc" oraz lusb0_usb.h z "libusb-win32-bin-1.2.6.0\include". Zmieniamy nazwę lusb0_usb.h na usb.h


Musimy teraz ustawić linker. Klikamy prawym przyciskiem na nasz projekt, następnie properties->Linker->Input . W additional dependencies dodajemy bibliotekę libusb.lib.

Skompiluj teraz projekt. Jeśli wyskoczy błąd:
Example_avr_usb.obj : error LNK2031: unable to generate p/invoke for "extern "C" void __clrcall usb_init(void)" (?usb_init@@$$J0YMXXZ); calling convention missing in metadata
Example_avr_usb.obj : warning LNK4248: unresolved typeref token (0100002E) for 'usb_dev_handle'; image may not run
Example_avr_usb.obj : error LNK2020: unresolved token (0A00001C) "extern "C" int __clrcall usb_control_msg(struct usb_dev_handle *,int,int,int,int,char *,int,int)" (?usb_control_msg@@$$J0YMHPAUusb_dev_handle@@[email protected])
Example_avr_usb.obj : error LNK2020: unresolved token (0A00001E) "extern "C" struct usb_dev_handle * __clrcall usb_open(struct usb_device *)" (?usb_open@@$$J0YMPAUusb_dev_handle@@PAUusb_device@@@Z)
Example_avr_usb.obj : error LNK2020: unresolved token (0A00001F) "extern "C" int __clrcall usb_close(struct usb_dev_handle *)" (?usb_close@@$$J0YMHPAUusb_dev_handle@@@Z)
Example_avr_usb.obj : error LNK2020: unresolved token (0A000022) "extern "C" struct usb_bus * __clrcall usb_get_busses(void)" (?usb_get_busses@@$$J0YMPAUusb_bus@@XZ)
Example_avr_usb.obj : error LNK2020: unresolved token (0A000023) "extern "C" int __clrcall usb_find_devices(void)" (?usb_find_devices@@$$J0YMHXZ)
Example_avr_usb.obj : error LNK2020: unresolved token (0A000024) "extern "C" int __clrcall usb_find_busses(void)" (?usb_find_busses@@$$J0YMHXZ)
Example_avr_usb.obj : error LNK2020: unresolved token (0A000055) "extern "C" void __clrcall usb_init(void)" (?usb_init@@$$J0YMXXZ)
Example_avr_usb.obj : error LNK2001: unresolved external symbol "extern "C" void __clrcall usb_init(void)" (?usb_init@@$$J0YMXXZ)
Example_avr_usb.obj : error LNK2001: unresolved external symbol "extern "C" struct usb_dev_handle * __clrcall usb_open(struct usb_device *)" (?usb_open@@$$J0YMPAUusb_dev_handle@@PAUusb_device@@@Z)
Example_avr_usb.obj : error LNK2001: unresolved external symbol "extern "C" int __clrcall usb_close(struct usb_dev_handle *)" (?usb_close@@$$J0YMHPAUusb_dev_handle@@@Z)
Example_avr_usb.obj : error LNK2001: unresolved external symbol "extern "C" int __clrcall usb_find_busses(void)" (?usb_find_busses@@$$J0YMHXZ)
Example_avr_usb.obj : error LNK2001: unresolved external symbol "extern "C" int __clrcall usb_find_devices(void)" (?usb_find_devices@@$$J0YMHXZ)
Example_avr_usb.obj : error LNK2001: unresolved external symbol "extern "C" struct usb_bus * __clrcall usb_get_busses(void)" (?usb_get_busses@@$$J0YMPAUusb_bus@@XZ)
Example_avr_usb.obj : error LNK2001: unresolved external symbol "extern "C" int __clrcall usb_control_msg(struct usb_dev_handle *,int,int,int,int,char *,int,int)" (?usb_control_msg@@$$J0YMHPAUusb_dev_handle@@[email protected])
C:\Users\Tester\Desktop\Programowanie AVR\Example_avr_usb\Release\Example_avr_usb.exe : fatal error LNK1120: 14 unresolved externals

To powtórz dwie pierwsze czynności, wejdź w General i w Common Language Runtime support ustaw Common Language Runtime Support (/clr)

Budujemy formę


Zbuduj formę, tak jak pokazałem Tutaj

   

Komponent Opis Nazwa
TabControl Posłuży do blokowania elementów wewnątrz tabControl1
Label Label do pokazywania informacji Podłączony/Niepodłączony label1
Checbox Do ustawiania bitów dla portu/ odczytywania portc[od 0 do 7]
Button Przycisk wyślij, do wysłania bitów button2
Button Przycisk odczytaj, do odczytywania stanu mikrokontrolera button3
ListBox Logi z pracy programu log_box

Programujemy


Nie będę pisać co i gdzie wkleić, bo jest to pokazane w filmie. Dlatego wkleję gotowy kod z obszernymi komentarzami co do poszczególnych elementów.
form1.h
#pragma once
#include "usb.h" // plik nagłówkowy z funkcjami do sterowania mikrokontrolerem
#include <string> // potrzebne do konwersji hex->string
#define VENDOR_ID 6424 // nasz VENDOR ID w systemie dziesiątkowym. Ten co ustawialiśmy w kodzie programu dla mikrokontrolera
#define PRODUCT_ID 3686 // nasz PRODUCT ID. Tak samo jak u góry
#define USB_COMMAND_SETBIT_C 1 //ID komendy, która służy do ustawienia portu - ustawione w kodzie programu dla mikrokont.....
#define USB_COMMAND_READBIT_C 2 // ID komendy do odczytu
#define USB_COMMAND_HELLO 0 // ID komendy dla Hello World!
usb_dev_handle *usb_handle; // zmienna do przechowywania uchywtu podłączonego urządzenia
bool is_connected = false; //zmienna informuje nas czy urządzenie jest podłaczone
 
namespace Example_avr_usb {
 
    using namespace System;
    using namespace System::ComponentModel;
    using namespace System::Collections;
    using namespace System::Windows::Forms;
    using namespace System::Data;
    using namespace System::Drawing;
 
    /// <summary>
    /// Summary for Form1
    ///
    /// WARNING: If you change the name of this class, you will need to change the
    ///          'Resource File Name' property for the managed resource compiler tool
    ///          associated with all .resx files this class depends on.  Otherwise,
    ///          the designers will not be able to interact properly with localized
    ///          resources associated with this form.
    /// </summary>
    public ref class Form1 : public System::Windows::Forms::Form
    {
    public:
        Form1(void)
        {
            InitializeComponent();
            //
            //TODO: Add the constructor code here
            //
            usb_init(); //************************** Ładujemy bibliotekę libusb
        }
 
    protected:
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        ~Form1()
        {
            if (components)
            {
                delete components;
            }
        }
    private: System::Windows::Forms::Button^  button1;
    protected: 
    private: System::Windows::Forms::Label^  label1;
    private: System::Windows::Forms::ListBox^  log_box;
 
    private: System::Windows::Forms::Label^  label2;
    private: System::Windows::Forms::TabControl^  tabControl1;
    private: System::Windows::Forms::TabPage^  tabPage1;
    private: System::Windows::Forms::CheckBox^  portc7;
 
    private: System::Windows::Forms::CheckBox^  portc6;
 
    private: System::Windows::Forms::CheckBox^  portc5;
    private: System::Windows::Forms::CheckBox^  portc4;
    private: System::Windows::Forms::CheckBox^  portc3;
    private: System::Windows::Forms::CheckBox^  portc2;
    private: System::Windows::Forms::CheckBox^  portc1;
    private: System::Windows::Forms::CheckBox^  portc0;
    private: System::Windows::Forms::TabPage^  tabPage2;
    private: System::Windows::Forms::Button^  button3;
    private: System::Windows::Forms::Button^  button2;
    private: System::Windows::Forms::Timer^  timer1;
    private: System::ComponentModel::IContainer^  components;
 
    private:
        /// <summary>
        /// Required designer variable.
        /// </summary>
    public: 
        void log_op(System::Object ^to_add){ //************************** Metoda posłuży do zapisywania komunikatów do Listboxa
            log_box->Items->Add(to_add);
        }
    public: 
        int get_bit_val( int n, int bitPosition ) { //************************** metoda, dzięki której będziemy mogli pobierać x bit n liczby
           return ((n >> bitPosition) & 1);
        }
 
 
#pragma region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        void InitializeComponent(void)
        {
            this->components = (gcnew System::ComponentModel::Container());
            this->button1 = (gcnew System::Windows::Forms::Button());
            this->label1 = (gcnew System::Windows::Forms::Label());
            this->log_box = (gcnew System::Windows::Forms::ListBox());
            this->label2 = (gcnew System::Windows::Forms::Label());
            this->tabControl1 = (gcnew System::Windows::Forms::TabControl());
            this->tabPage1 = (gcnew System::Windows::Forms::TabPage());
            this->button3 = (gcnew System::Windows::Forms::Button());
            this->button2 = (gcnew System::Windows::Forms::Button());
            this->portc7 = (gcnew System::Windows::Forms::CheckBox());
            this->portc6 = (gcnew System::Windows::Forms::CheckBox());
            this->portc5 = (gcnew System::Windows::Forms::CheckBox());
            this->portc4 = (gcnew System::Windows::Forms::CheckBox());
            this->portc3 = (gcnew System::Windows::Forms::CheckBox());
            this->portc2 = (gcnew System::Windows::Forms::CheckBox());
            this->portc1 = (gcnew System::Windows::Forms::CheckBox());
            this->portc0 = (gcnew System::Windows::Forms::CheckBox());
            this->tabPage2 = (gcnew System::Windows::Forms::TabPage());
            this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
            this->tabControl1->SuspendLayout();
            this->tabPage1->SuspendLayout();
            this->SuspendLayout();
            // 
            // button1
            // 
            this->button1->Location = System::Drawing::Point(12, 22);
            this->button1->Name = L"button1";
            this->button1->Size = System::Drawing::Size(152, 29);
            this->button1->TabIndex = 0;
            this->button1->Text = L"Podłącz!";
            this->button1->UseVisualStyleBackColor = true;
            this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
            // 
            // label1
            // 
            this->label1->AutoSize = true;
            this->label1->ForeColor = System::Drawing::Color::Red;
            this->label1->Location = System::Drawing::Point(48, 6);
            this->label1->Name = L"label1";
            this->label1->Size = System::Drawing::Size(85, 13);
            this->label1->TabIndex = 1;
            this->label1->Text = L"Nie podłączony!";
            // 
            // log_box
            // 
            this->log_box->FormattingEnabled = true;
            this->log_box->Location = System::Drawing::Point(260, 19);
            this->log_box->Name = L"log_box";
            this->log_box->Size = System::Drawing::Size(371, 212);
            this->log_box->TabIndex = 2;
            // 
            // label2
            // 
            this->label2->AutoSize = true;
            this->label2->Location = System::Drawing::Point(257, 6);
            this->label2->Name = L"label2";
            this->label2->Size = System::Drawing::Size(27, 13);
            this->label2->TabIndex = 3;
            this->label2->Text = L"Logi";
            // 
            // tabControl1
            // 
            this->tabControl1->Controls->Add(this->tabPage1);
            this->tabControl1->Controls->Add(this->tabPage2);
            this->tabControl1->Location = System::Drawing::Point(12, 57);
            this->tabControl1->Name = L"tabControl1";
            this->tabControl1->SelectedIndex = 0;
            this->tabControl1->Size = System::Drawing::Size(242, 180);
            this->tabControl1->TabIndex = 4;
            // 
            // tabPage1
            // 
            this->tabPage1->Controls->Add(this->button3);
            this->tabPage1->Controls->Add(this->button2);
            this->tabPage1->Controls->Add(this->portc7);
            this->tabPage1->Controls->Add(this->portc6);
            this->tabPage1->Controls->Add(this->portc5);
            this->tabPage1->Controls->Add(this->portc4);
            this->tabPage1->Controls->Add(this->portc3);
            this->tabPage1->Controls->Add(this->portc2);
            this->tabPage1->Controls->Add(this->portc1);
            this->tabPage1->Controls->Add(this->portc0);
            this->tabPage1->Location = System::Drawing::Point(4, 22);
            this->tabPage1->Name = L"tabPage1";
            this->tabPage1->Padding = System::Windows::Forms::Padding(3);
            this->tabPage1->Size = System::Drawing::Size(234, 154);
            this->tabPage1->TabIndex = 0;
            this->tabPage1->Text = L"Port C";
            this->tabPage1->UseVisualStyleBackColor = true;
            // 
            // button3
            // 
            this->button3->Location = System::Drawing::Point(101, 98);
            this->button3->Name = L"button3";
            this->button3->Size = System::Drawing::Size(114, 29);
            this->button3->TabIndex = 9;
            this->button3->Text = L"Odczytaj";
            this->button3->UseVisualStyleBackColor = true;
            this->button3->Click += gcnew System::EventHandler(this, &Form1::button3_Click);
            // 
            // button2
            // 
            this->button2->Location = System::Drawing::Point(101, 62);
            this->button2->Name = L"button2";
            this->button2->Size = System::Drawing::Size(114, 30);
            this->button2->TabIndex = 8;
            this->button2->Text = L"Wyślij";
            this->button2->UseVisualStyleBackColor = true;
            this->button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);
            // 
            // portc7
            // 
            this->portc7->AutoSize = true;
            this->portc7->Location = System::Drawing::Point(101, 29);
            this->portc7->Name = L"portc7";
            this->portc7->Size = System::Drawing::Size(61, 17);
            this->portc7->TabIndex = 7;
            this->portc7->Text = L"Port C7";
            this->portc7->UseVisualStyleBackColor = true;
            // 
            // portc6
            // 
            this->portc6->AutoSize = true;
            this->portc6->Location = System::Drawing::Point(101, 6);
            this->portc6->Name = L"portc6";
            this->portc6->Size = System::Drawing::Size(61, 17);
            this->portc6->TabIndex = 6;
            this->portc6->Text = L"Port C6";
            this->portc6->UseVisualStyleBackColor = true;
            // 
            // portc5
            // 
            this->portc5->AutoSize = true;
            this->portc5->Location = System::Drawing::Point(6, 121);
            this->portc5->Name = L"portc5";
            this->portc5->Size = System::Drawing::Size(61, 17);
            this->portc5->TabIndex = 5;
            this->portc5->Text = L"Port C5";
            this->portc5->UseVisualStyleBackColor = true;
            // 
            // portc4
            // 
            this->portc4->AutoSize = true;
            this->portc4->Location = System::Drawing::Point(6, 98);
            this->portc4->Name = L"portc4";
            this->portc4->Size = System::Drawing::Size(61, 17);
            this->portc4->TabIndex = 4;
            this->portc4->Text = L"Port C4";
            this->portc4->UseVisualStyleBackColor = true;
            // 
            // portc3
            // 
            this->portc3->AutoSize = true;
            this->portc3->Location = System::Drawing::Point(6, 75);
            this->portc3->Name = L"portc3";
            this->portc3->Size = System::Drawing::Size(61, 17);
            this->portc3->TabIndex = 3;
            this->portc3->Text = L"Port C3";
            this->portc3->UseVisualStyleBackColor = true;
            // 
            // portc2
            // 
            this->portc2->AutoSize = true;
            this->portc2->Location = System::Drawing::Point(6, 52);
            this->portc2->Name = L"portc2";
            this->portc2->Size = System::Drawing::Size(61, 17);
            this->portc2->TabIndex = 2;
            this->portc2->Text = L"Port C2";
            this->portc2->UseVisualStyleBackColor = true;
            // 
            // portc1
            // 
            this->portc1->AutoSize = true;
            this->portc1->Location = System::Drawing::Point(6, 29);
            this->portc1->Name = L"portc1";
            this->portc1->Size = System::Drawing::Size(61, 17);
            this->portc1->TabIndex = 1;
            this->portc1->Text = L"Port C1";
            this->portc1->UseVisualStyleBackColor = true;
            // 
            // portc0
            // 
            this->portc0->AutoSize = true;
            this->portc0->Location = System::Drawing::Point(6, 6);
            this->portc0->Name = L"portc0";
            this->portc0->Size = System::Drawing::Size(61, 17);
            this->portc0->TabIndex = 0;
            this->portc0->Text = L"Port C0";
            this->portc0->UseVisualStyleBackColor = true;
            // 
            // tabPage2
            // 
            this->tabPage2->Location = System::Drawing::Point(4, 22);
            this->tabPage2->Name = L"tabPage2";
            this->tabPage2->Padding = System::Windows::Forms::Padding(3);
            this->tabPage2->Size = System::Drawing::Size(234, 154);
            this->tabPage2->TabIndex = 1;
            this->tabPage2->Text = L"Port B";
            this->tabPage2->UseVisualStyleBackColor = true;
            // 
            // timer1
            // 
            this->timer1->Enabled = true;
            this->timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
            // 
            // Form1
            // 
            this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
            this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
            this->ClientSize = System::Drawing::Size(643, 241);
            this->Controls->Add(this->tabControl1);
            this->Controls->Add(this->label2);
            this->Controls->Add(this->log_box);
            this->Controls->Add(this->label1);
            this->Controls->Add(this->button1);
            this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog;
            this->Name = L"Form1";
            this->Text = L"Sternik :)";
            this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load);
            this->tabControl1->ResumeLayout(false);
            this->tabPage1->ResumeLayout(false);
            this->tabPage1->PerformLayout();
            this->ResumeLayout(false);
            this->PerformLayout();
 
        }
#pragma endregion
    private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) {
             }
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
                this->log_op("------------------------------");
                this->log_op("Search devices");
                 struct usb_bus      *bus;  //************************** zmienna przechowywająca porty USB
                struct usb_device   *dev; //************************** zmienna przechowyująca Port USB z urządzeniem
                usb_find_busses(); //**************************  szukamy portów USB
                usb_find_devices(); //************************** szukamy urządzeń
                for(bus=usb_get_busses(); bus; bus=bus->next){ //************************** Przeszukujemy wszystkie porty
                    for(dev=bus->devices; dev; dev=dev->next){ //************************** i wszystkie urządzenia
                        this->log_op("Found: idVendor: "+dev->descriptor.idVendor.ToString() +" Product ID"+dev->descriptor.idProduct.ToString()); 
                        //************************** Zapisujemy do logów że coś znaleziono
                        if(dev->descriptor.idVendor == VENDOR_ID && dev->descriptor.idProduct == PRODUCT_ID){
                                //************************** Sprawdzamy czy to nasze urządzenie po idVendor i idProduct
                            this->log_op("Selected device: idVendor: "+dev->descriptor.idVendor.ToString() +" Product ID"+dev->descriptor.idProduct.ToString());
                            ////************************** Powiadamiamy o tym
 
                        if(is_connected){ //************************** Sprawdzamy czy jest połaczony z programem
                                this->log_op("Disconnected"); //************************** Jak tak, to rozłączamy
                                usb_close(usb_handle); //************************** Zamykamy połączenie
                                usb_handle = NULL; //************************** Czyścimy uchwyt
                            }else{
                                usb_handle = usb_open(dev); //************************** Jeśli nie, otwieramy połączenie z urządzeniem
                            }
                        }
                    }
                }
                if(usb_handle){ //************************** sprawdzamy czy udało się połączyć
                            is_connected = true;
                            int nBytes;  //************************** liczba bajtów, które przyjdą do nas z urządzenia
                            char    buffer[12]; //************************** buffer danych, które przyjdą do nas z urządzenia
                            this->log_op("Start send command ID "+ USB_COMMAND_HELLO+"; Value: 0xFF; Mode char buffer");
        nBytes = usb_control_msg(usb_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USB_COMMAND_HELLO, 0xFF, 0, (char *)buffer, sizeof(buffer), 5000);
        //************************** wysyłamy do naszego urządzenia komendę USB_COMMAND_HELLO , czyli ID : 0 , z danymi 0xFF. W rezultacie otrzymamy liczbe bajtów odpowiedzi
        this->log_op("Response is: ");
        this->log_op("Num of bytes:"+nBytes.ToString());
        String^ response_string = gcnew String(buffer); //************************** zmieniamy buffer na string
        this->log_op("ASCI response: "+response_string->Substring(0, nBytes)); //************************** wyswietmy wynik
        }else{
            is_connected = false;
                }
             }
private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) { 
            //************************** timer ustaw na 100ms, odrazu ustaw na enabled
                 if(is_connected){
                            this->label1->ForeColor = System::Drawing::Color::Green;
                            this->label1->Text = L"Podłączony!";
                            this->tabControl1->Enabled = true;
                            this->button1->Text = "Odłącz!";
                }else{
                            this->label1->ForeColor = System::Drawing::Color::Red;
                            this->label1->Text = L"Nie podłączony";
                            this->tabControl1->Enabled = false;
                            this->button1->Text = "Podłącz!";
                }
         }
private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) { //************************** przycisk do wysyłania danych o ustawieniu portu
             int to_send = 0x00; // dane do wysłania
             if(this->portc0->Checked){
                to_send |= 0x01; //ustawiamy bit 0 na 1
             }
             if(this->portc1->Checked){
                to_send |= 0x02; //ustawiamy bit 1 na 1
             }
             if(this->portc2->Checked){
                to_send |= 0x04; //ustawiamy bit 1 na 1 ... i tak dalej
             }
             if(this->portc3->Checked){
                to_send |= 0x08;
             }    
             if(this->portc4->Checked){
                to_send |= 0x10;
             }
             if(this->portc5->Checked){
                to_send |= 0x20;
             }
             if(this->portc6->Checked){
                to_send |= 0x40;
             }
             if(this->portc7->Checked){
                to_send |= 0x80; //ustawiamy bit 7 na 1
             }
 
        int nBytes;
        char  buffer[32]; // buffer
        this->log_op("----- START SEND BITS -----");
        this->log_op("Start send command ID "+ USB_COMMAND_SETBIT_C +"; Value: 0x"+to_send.ToString("X2")+"; Mode char buffer");
        nBytes = usb_control_msg(usb_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USB_COMMAND_SETBIT_C, to_send, 0, (char *)buffer, sizeof(buffer), 5000); //wysyłamy komendę o ID 1, czyli USB_COMMAND_SETBIT_C, z danymi z zmiennej to_send
        this->log_op("Response is: ");
        this->log_op("Num of bytes:"+nBytes.ToString());
        String^ response_string = gcnew String(buffer); //odpowiedź zmieniamy na ASCII
        this->log_op("ASCI response: "+response_string->Substring(0, nBytes));
 
         }
private: System::Void button3_Click(System::Object^  sender, System::EventArgs^  e) { // odczytujemy aktualny stan portu C
             int to_send = 0xFF;
            int nBytes;
            char  buffer[32];
            this->log_op("----- START READ PORTC -----");
            this->log_op("Start send command ID "+ USB_COMMAND_READBIT_C +"; Value: 0x"+to_send.ToString("X2")+"; Mode char buffer");
            nBytes = usb_control_msg(usb_handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, USB_COMMAND_READBIT_C, to_send, 0, (char *)buffer, sizeof(buffer), 5000);//wysyłamy komendę ID: 2,  USB_COMMAND_READBIT_C
            this->log_op("Response is: ");
            this->log_op("Num of bytes:"+nBytes.ToString());
            int response_int = buffer[0]; 
            this->log_op("HEX response: 0x"+response_int.ToString("X2")); //otrzymany wynik pokazujemy w formacie HEX
            this->portc0->Checked = false;
            this->portc1->Checked = false;
            this->portc2->Checked = false;
            this->portc3->Checked = false;
            this->portc4->Checked = false;
            this->portc5->Checked = false;
            this->portc6->Checked = false;
            this->portc7->Checked = false;
 
            if(this->get_bit_val(response_int, 0)){ // i sprawdzamy czy bit 0 jest w stanie wysokim
                this->portc0->Checked = true;
            }
            if(this->get_bit_val(response_int, 1)){ //czy jest 1 bit w stanie wysokim... i tak dalej.
                this->portc1->Checked = true;
            }
            if(this->get_bit_val(response_int, 2)){
                this->portc2->Checked = true;
            }
            if(this->get_bit_val(response_int, 3)){
                this->portc3->Checked = true;
            }
            if(this->get_bit_val(response_int, 4)){
                this->portc4->Checked = true;
            }
            if(this->get_bit_val(response_int, 5)){
                this->portc5->Checked = true;
            }
            if(this->get_bit_val(response_int, 6)){
                this->portc6->Checked = true;
            }
            if(this->get_bit_val(response_int, 7)){
                this->portc7->Checked = true;
            }
         }
};
}


Efekt końcowy



    21075597354f352f863b10d.png




Autorzy:
Programowanie: Krzysztof "Bordeux" Bednarczyk
Elektronik: Łukasz Domański
Gotowiec.zip

8 komentarzy

Brak avatara
Paweł 2013-11-14 11:52

Witam
Link do pliku Gotowiec.zip nie działa...

Simi91 2013-03-06 07:54

Witam. Mam problem ze skompilowaniem programu dla mikrokontrolera, a mianowicie dostaje błąd
make:***[flash.elf] Error 1
(projekt nazwałem flash)
Jak sobie z tym poradzić? Makefile jest generowany przez eclipse, a wydaje mi się, że tam tkwi problem.
Druga sprawa. Patrzyłem na stronę domowa biblioteki V USB i natknąłem się tam na hardware, który wygląda inaczej jeśli chodzi o PINy D+ oraz D-
http://www.obdev.at/Images/vusb/circuit-zoomed.gif
PINy są zamienione. Co z tym zrobić?

bordeux 2013-02-10 21:38

@koloco_cnc: go to options ->  General i w Common Language Runtime support and set Common Language Runtime Support (/clr) :)

kolco_cnc 2012-12-14 11:31

warning LNK4248: unresolved typeref token (01000026) for 'usb_dev_handle'; image may not run

what should I do next ?

marogo 2012-08-20 10:01

"Jeśli chcesz ustawić nóżki w stan wysoki (płynie napięcie)"

"Płynie napięcie" -- buuuahahaha :D

genezus 2012-08-09 20:34

Miałem problem z powyższym kursem. Otóż zawiera on pewien mały błąd który niestety uniemożliwia prawidłową pracę mikrokontrolera.
W programie na ukontroler jest:

USB_PUBLIC uchar usbFunctionSetup(uchar data[8]){ // funkcja wykonywana, gdy µKontroler dostanie polecenie poprzez USB od komputera
usbRequest_t *rq = (void *)data;
static uchar    replyBuf[255]; // bufer danych wyjściowych - odpowiedź µKontrolera na żądanie
 
        if(rq->bRequest == 0){                       // rq->bRequest to ID żądania
      ...

itd.
A powinno być:

USB_PUBLIC uchar usbFunctionSetup(uchar data[8]){ // funkcja wykonywana, gdy µKontroler dostanie polecenie poprzez USB od komputera
usbRequest_t *rq = (void *)data;
static uchar    replyBuf[255]; // bufer danych wyjściowych - odpowiedź µKontrolera na żądanie
usbMsgPtr = replyBuf;


        if(rq->bRequest == 0){                       // rq->bRequest to ID żądania
        replyBuf[0] = 0x48; //h

...

itd.

Brakuje więc linijki:
usbMsgPtr = replyBuf;

Pozdrawiam

dondu 2012-05-16 16:58

Drobna uwaga - zgodnie z datasheet warto dodać filtrowanie zasilania pinów mikrokontrolera, by nie narażać się na zbędne ryzyko nieprawidłowej pracy: http://mikrokontrolery.blogspo[...]zasilanie-mikrokontrolera.html

Coldpeer 2012-05-02 15:52

taka mała uwaga - płynie prąd, a nie napięcie ;) Napięcie jest/się odkłada.