Budowa modułu kontrolnego na USB przy pomocy mikrokontrolera AVR
bordeux
1 Słowa wstępu
2 Co nam potrzebne
3 Budujemy układ
3.1 Schemat
4 Kofigurujemy Środowisko
4.2 Co nam potrzebne
5 Programujemy mikrokontroler
5.3 Szybka teoria
5.3.1 Wyjście
5.3.2 Wejście
5.3.3 Prosty program
5.3.4 Konfiguracja VUSB
5.3.5 Tworzymy sterowniki
6 Piszemy aplikację sterującą dla Windows
6.4 Budujemy formę
6.5 Programujemy
Słowa wstępu
Artykuł został stworzony dla początkujących, dlatego czasami przesadnie opisuje niektóre czynności. Brakuje też fachowej terminologii, 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.
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.
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>
Wyjście
Aby ustawić cały port B na stan wyjścia, należy w programie wywołać: ```c DDRB = 0xFF; // binarnie 0b1111111 - DDR[LiterkaPortu] ``` Jeśli chcesz ustawić nóżki w stan wysoki : ```c 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: ```c 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: ```c DDRB = 0x00; // binarnie 0b0000000 - DDR[LiterkaPortu] ``` Jeśli chcesz odczytać dane z portu: ```c 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 : ```c #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 <a href="http://www.youtube.com/watch?feature=player_detailpage&v=S7VVBDy_zIA#t=1320s" target="_blank">00:22:00</a> <br />
<h2>Piszemy program dla mikrokontrolera</h2>
Zanim wszystko zaczniemy, musisz mieć skonfigurowane środowisko: Jak to zrobić jest pokazane na filmie od momentu: <a href="http://www.youtube.com/watch?feature=player_detailpage&v=S7VVBDy_zIA#t=1316s" target="_blank">00:20:00</a> (zakładając, że Eclipse i JDK już ściągłeś i zainstalowałeś).
<h3>Tworzymy projekt</h3>
<a href="http://www.youtube.com/watch?feature=player_detailpage&v=S7VVBDy_zIA#t=1368s">Uruchamiamy</a> <b>Eclipse</b>, następnie <b>File->New->Project</b>. Wybieramy <b>C/C++</b> -> <b>C Project</b>. Klikamy <b>Dalej</b>, w następnym formularzy uzupełniamy <b>Nazwę projektu</b>. Znów klikamy <b>Dalej</b> i odznaczamy "<b>Debug</b>", i znów <b>Dalej</b>. W kolejnym oknie wybieramy nasz mikrokontroler, i teraz <b>WAŻNE</b>: taktowanie procesora ustaw na 12mhz czyli na <b>12000000</b> hz
<h3>Kod</h3>
<p>Utworzyliśmy projekt. Teraz musisz <a href="http://www.youtube.com/watch?feature=player_detailpage&v=S7VVBDy_zIA#t=1509s">skopiować folder</a> "<b>usbdrv</b>" do katalogu projektu. </p>
Następnie w projekcie <a href="http://www.youtube.com/watch?feature=player_detailpage&v=S7VVBDy_zIA#t=1491s">utwórz plik main.c</a>, i uzupełnij go kodem:
```c
/*
* 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.hMusimy 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@@HHHHPADHH@Z)
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@@HHHHPADHH@Z)
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 ```cpp #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łaczonenamespace 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;
}
}
};
}
<h1>Efekt końcowy</h1>
<div style="text-align:center;">
<a href="http://www.youtube.com/watch?feature=player_detailpage&v=S7VVBDy_zIA#t=3186s"><img src="//static.4programmers.net/uploads/attachment/21075597354f352f863b10d.png" /></a>
</div>
<hr />
Autorzy:
Programowanie: <a href="http://bednarczyk.bordeux.net">Krzysztof "Bordeux" Bednarczyk</a>
Elektronik: Łukasz Domański
<a href="https://mega.co.nz/#!WIZnTIKI!Ae_NzSVqyHOOKL3f06nddzZ3LL15ibdjxLZqvJ4mE4Q">Gotowiec.zip</a>
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ć?
@koloco_cnc: go to options -> General i w Common Language Runtime support and set Common Language Runtime Support (/clr) :)
warning LNK4248: unresolved typeref token (01000026) for 'usb_dev_handle'; image may not run
what should I do next ?
"Jeśli chcesz ustawić nóżki w stan wysoki (płynie napięcie)"
"Płynie napięcie" -- buuuahahaha :D
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
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;
...
itd.
Brakuje więc linijki:
usbMsgPtr = replyBuf;
Pozdrawiam
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.blogspot.com/2011/04/zasilanie-mikrokontrolera.html
taka mała uwaga - płynie prąd, a nie napięcie ;) Napięcie jest/się odkłada.