суббота, 27 сентября 2014 г.

Включение светодиода через usb.

Для реализация управления устройствами через usb-порт потребуется намного больше действий чем для реализации управления через lpt-порт, тем не менее управление через usb имеет преимущества перед управлением через lpt. Рассмотрим схему:
Рисунок 1 - Включение светодиода через usb

Для связи с usb-портом используется микроконтроллер ATmega8A-PU но можно использовать и ATtiny2313 и любой другой AVR микроконтроллер способный работать на частоте 12МГц и имеющий как минимум 2кб flash памяти. ATtiny2313 имеет 2кб flash памяти но помимо связи с usb микроконтроллер также должен заниматься выполнением некоторых других задач поэтому для связи с usb выбран ATmega8A-PU имеющий 8кб flash памяти. Диоды VD1 и VD2 нужны для согласования уровней напряжения для "общения" с usb, эти диоды понижают напряжение питания и следовательно напряжения на выводах микроконтроллера. Есть схемы в которых для согласования уровней используются стабилитроны. Со стабилитронами могут быть проблемы из за которых устройство может не распознаваться. Стабилитроны должны быть маломощными и может понадобиться подбор резисторов. Поэтому для избежания проблем используется схема с понижением напряжения питания. Важно правильно собрать схему, при сборке не делать слишком длинных путей прохождения тока, слишком широких пересечений проводников, ничего лишнего не замкнуть и не перепутать подключение.
Для написания программы для микроконтроллера понадобится библиотека v-usb последнюю и самую актуальную версию которой можно скачать с официального сайта http://www.obdev.at/products/vusb/download.html. В скачанном v-usb архиве будет папка "examples" в ней будет пример "hid-custom-rq" который (с небольшими переделками) и будет использоваться для включения светодиода через usb. Для компиляции данного примера понадобится скачать и установить:
WinAVR (для компиляции примера для микроконтроллера),
MinGW-5.1.4.exe (для компиляции примера для микроконтроллера).
Которые для простоты дальнейших действий лучше установить туда куда предлагается по умолчанию, более подробно об установке этих программ на сайте: microsin.net. После установки MinGW-5.1.4.exe в переменную Path необходимо прописать путь c:\MinGW\bin\ на сайте microsin.net об этом написано но важно при прописывании этого пути не удалить другие, данный путь дописывается в конец после точки с запятой которую необходимо дописать если её нет. В windows7 чтобы изменить переменную Path:
1) Правой кнопкой мыши нажимается на значок "Компьютер" (или "мой компьютер"),
2) Выбирается "Свойства",
3) Выбирается "Дополнительные параметры системы",
4) Нажимается на кнопке "Переменные среды...",
5) В поле "Системные переменные" выбирается "Path" нажимается кнопка "Изменить...",
6) В поле "Значение переменной:" дописывается ";c:\MinGW\bin\" (или туда где MinGW установлена если не по умолчанию).
В распакованной папке v-usb лучше ничего не перемещать и не копировать а изменения производить в самом примере (если что можно скачать заново). в папке "hid-custom-rq" есть папка "firmware" в этой папке есть файл "Make" его надо открыть через какой нибудь текстовый редактор и найти строки:
DEVICE  = atmega168
F_CPU   = 16000000 # in Hz
и заменить на:
DEVICE  = atmega8
F_CPU   = 12000000 # in Hz
Если кварцевый резонатор на другую частоту и/или микроконтроллер другой то заменить на то что есть на самом деле. Если дополнительные действия с папками и файлами в этой скачанной v-usb папке не проводилось и записывать программу в микроконтроллер через этот Make файл не планируется то далее ничего можно не менять, этот файл сохраняется и закрывается.
В файле usbconfig
Необходимо убедится в том что есть такие записи:
#define USB_CFG_IOPORTNAME      D
#define USB_CFG_DMINUS_BIT      4
#define USB_CFG_DPLUS_BIT       2
#define USB_CFG_INTERFACE_CLASS     3
Можно изменить VENDOR_NAME и DEVICE_NAME:
#define USB_CFG_VENDOR_NAME     'e','l','e','c','t','e','.','b','l','o','g','s','p','o','t','.','c','o','m'
#define USB_CFG_VENDOR_NAME_LEN 19
#define USB_CFG_DEVICE_NAME     'm','y','u','s','b','d','e','v','i','c','e'
#define USB_CFG_DEVICE_NAME_LEN 11

В файле main находим строку:
#define LED_BIT             0
и меняем на:
#define LED_BIT             1
т.к. светодиод подключен к первому биту порта B, если сразу подключить его к биту 0 то эту строку менять не надо, можно подключить к другому биту порта B и внести соответствующие изменения в эту строку.
На всякий случай дописываем строку:
#define F_CPU 12000000UL  // 12 MHz
Сохраняем и закрываем.
Файл "requests" менять не надо.
Далее открываем cmd (командная строка) и переходим в этой командной строке в папку "firmware", если например папка v-usb находиться на диске d то сделать это можно 3мя командами: 
cd c:\
d:
cd d:\vusb-20121206\examples\hid-custom-rq\firmware\
Далее для того чтобы откомпилировать пример вводится команда:
make hex
Если компиляция прошла успешно то в папке "firmware" должен появиться файл "main.hex", его нужно прошить в микроконтроллер. Если используется программатор stk200 (5 проводков), lpt порт, микроконтроллер m8, частота кварцевого резонатора 12МГц, файл "main.hex" скопирован в корень диска C, на компьютере имеется утилита avrdude которая устанавливается вместе с WinAVR то для прошивки файла "main.hex" в микроконтроллер в командной строке достаточно выполнить две команды:
cd C:\
avrdude -c stk200 -P lpt1 -p m8 -U lfuse:w:0x9f:m -U hfuse:w:0xc9:m -U flash:w:main.hex
Обратите внимание на "-U lfuse:w:0x9f:m -U hfuse:w:0xc9:m" -это установка фьюзов если их неправильно установить то можно испортить микроконтроллер. Для правильной установки фьюзов может пригодится калькулятор фьюзов http://fusecalc.mirmk.net/. Для того чтобы команда в командной строке выполнилась необходимо вписать эту команду в чёрное текстовое поле командной строки и нажать клавишу "Enter" на клавиатуре компьютера в котором открыта эта командная строка. Для того чтобы hex-файл записался (прошился) в микроконтроллер необходимо чтобы в момент когда компьютер выполняет запись этой прошивки в микроконтроллер к этому компьютеру был подключён программатор к которому подключён микроконтроллер иначе прошить микроконтроллер не получиться. Если программатор stk200 (5 проводков) то на микроконтроллер в момент прошивки должно быть подано питание, питание следует подавать только после подключения программатора к компьютеру и отключать только перед выниманием из компьютера иначе можно испортить порт или микроконтроллер. Если прошивка прошла успешно то можно воткнуть устройство в usb порт и посмотреть в диспетчере устройств распозналось ли устройство или нет. Если в диспетчере устройств написано "неизвестное устройство" или что то вроде этого то устройство не распозналось и необходимо искать причину и устранять её, если в диспетчере устройств появилась строка где написано "HID-устройство","usb устройство ввода" или что то в этом роде то устройство распозналось.
Для организации "общения" компьютера с микроконтроллером используя скачанный пример необходимо скачать и установить библиотеку libusb (libusb-win32-releases) при установке  устройство должно быть подключено к компьютеру для того чтобы заодно установился драйвер фильтра. Подробнее про установку libusb на сайте: microsin.net. В папке "commandline" (которая находится там же где и папка "firmware") есть файл "Make" его надо открыть и найти в нём строки:
USBFLAGS = `libusb-config --cflags`
USBLIBS = `libusb-config --libs`
и закомментировать:
USBFLAGS = `libusb-config --cflags`
USBLIBS = `libusb-config --libs`
найти строки:
USBFLAGS = -I/usr/local/include
USBLIBS = -L/usr/local/lib -lusb
и заменить на:
USBFLAGS = -I"c:/Program Files/LibUSB-Win32/include"
USBLIBS = -L"c:/Program Files/LibUSB-Win32/lib/gcc" -lusb
и обязательно проверить и убедиться в том что папки "include" и "gcc" располагаются по указанным путям если нет то их туда надо переместить перед этим найдя где они установлены или скачать и установить заново. Об этом написано на сайте: microsin.net. После внесения всех необходимых изменений Make файл надо сохранить и закрыть.
Далее открываем файл "set-led.c" и меняем исходный код (в первых пяти строках надо заменить #include" " на #include< >) на:


#include "windows.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "usb.h"        /* this is libusb */
#include "opendevice.h" /* common code moved to separate module */

#include "../firmware/requests.h"   /* custom request numbers */
#include "../firmware/usbconfig.h"  /* device's VID/PID and names */

#define USB_CFG_VENDOR_NAME     'e','l','e','c','t','e','.','b','l','o','g','s','p','o','t','.','c','o','m'
#define USB_CFG_VENDOR_NAME_LEN 19

#define USB_CFG_DEVICE_NAME     'm','y','u','s','b','d','e','v','i','c','e'
#define USB_CFG_DEVICE_NAME_LEN 11

const int BUTTON_ON_OFF=1000;

usb_dev_handle      *handle = NULL;
const unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID};
char                vendor[] = {USB_CFG_VENDOR_NAME, 0}, product[] = {USB_CFG_DEVICE_NAME, 0};
char                buffer[4];
int                  vid, pid;
unsigned short key_on_off=0;

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "Windows App",       /* Title Text */
           WS_OVERLAPPEDWINDOW, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           544,                 /* The programs width */
           375,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

CreateWindow("button", "on/off", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,50, 50, 100,30, hwnd,(HMENU)BUTTON_ON_OFF,hThisInstance,NULL);

usb_init();

    vid = rawVid[1] * 256 + rawVid[0];
    pid = rawPid[1] * 256 + rawPid[0];


    if(usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) != 0){
MessageBox(hwnd, "Could not find USB device\n","error", 0);
        exit(1);
    }
else
{
MessageBox(hwnd, "Find USB device done!\n","Done!", 0);
}

    ShowWindow (hwnd, nFunsterStil);

    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
usb_close(handle);
    return messages.wParam;
}

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)                
    {
        case WM_DESTROY:
            PostQuitMessage (0);    
        break;
case WM_COMMAND:
if(LOWORD(wParam)==BUTTON_ON_OFF)
            {
if(key_on_off==1)
{
usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CUSTOM_RQ_SET_STATUS, 1, 0, buffer, 0, 5000);
key_on_off=0;
}
else
{
usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CUSTOM_RQ_SET_STATUS, 0, 0, buffer, 0, 5000);
key_on_off=1;
}
            }
break;
        default:                    
            return DefWindowProc (hwnd, message, wParam, lParam);
    }
    return 0;
}



поля:
#define USB_CFG_VENDOR_NAME     'e','l','e','c','t','e','.','b','l','o','g','s','p','o','t','.','c','o','m'
#define USB_CFG_VENDOR_NAME_LEN 19

#define USB_CFG_DEVICE_NAME     'm','y','u','s','b','d','e','v','i','c','e'
#define USB_CFG_DEVICE_NAME_LEN 11
меняем на те что прописаны в файле "usbconfig.h"
Сохраняем и закрываем файл. Файлы "opendevice" (с расширением c и h) менять не надо. Файл "opendevice" с расширением c очень полезный в нём функция для более удобного "открытия" устройства. В папке где установлен libusb должна быть папка "include" в папке "include" должен быть файл "lusb0_usb.h" или что то в этом роде с расширением h этот файл надо скопировать в папку "include" где установлен MinGW и потом переименовать в "usb" расширение должно остаться h.
Открываем cmd (командную строку) и переходим в этой командной строке в папку "commandline"если папка v-usb находиться на диске d то сделать это можно 3мя командами:
cd c:\
d:
cd d:\vusb-20121206\examples\hid-custom-rq\commandline\
Далее для того чтобы откомпилировать пример вводится команда:
make
Если компиляция прошла успешно то в папке "commandline" должен появиться файл
"set-led.exe" -это и есть программа которая включает светодиод при нажатии кнопки.
Изменённый (немного криво но работающий) проект можно скачать с Яндекс диска.
Если всё сделано правильно то при запуске "set-led.exe" появится окно с кнопкой нажатие на которую приводит к включению светодиода, если устройство подключено к usb.
 Как видите реализация управления устройством через usb процесс довольно трудоёмкий и времязатратный но возможно результат всё таки стоит потраченного времени. 
КАРТА БЛОГА (содержание)

1 комментарий: