Zatem do rzeczy. Założenie było takie. Mam aplikacje na komputerze za pomocą której mogę ustawiać 6 świecących LEDów. Do budowy wykorzystuje tylko to co mam w domu.
Także zabrałem się za robotę i w szybkim czasie powstał schemat poniżej
Schemat został podzielony na trzy pola robocze. Wyprowadzenia połączeń z USB, zasilanie i LED podłączone do procesora. Przynajmniej na początku miały być to LEDy ale w ostateczności uznałem, że będzie to wyjście do płytki, na której znajdują się przekaźniki. VUSB dopuszcza tylko niektóre częstotliwości taktowania procesora. Więcej informacji można znaleźć na stronie projektu. https://www.obdev.at/products/vusb/index.html
A oto i płytka. Wielu z was może zdziwić brak wyprowadzeń do programowania. Potrzeba matką wynalazku. Kiedyś dawno dawno temu zrobiłem sobie urządzenie do programowania procesorów ATMEGA w obudowie TQFP.
I przyszedł czas na program. Jako, że miało to być tylko testowe to uznałem, że nie będę sobie utrudniać roboty i zrobię coś co będzie działać. Optymalizacja kodu jest nieważna. Program po skompilowaniu ma 1.5KB
Na początku trzeba zmienić linie w usbconfig.h na takie, których używamy w programie jako połączenie z USB.
Kod: Zaznacz cały
#define USB_CFG_IOPORTNAME D
/* This is the port where the USB bus is connected. When you configure it to
* "B", the registers PORTB, PINB and DDRB will be used.
*/
#define USB_CFG_DMINUS_BIT 3
/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
* This may be any bit in the port.
*/
#define USB_CFG_DPLUS_BIT 2
/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
* This may be any bit in the port. Please note that D+ must also be connected
* to interrupt pin INT0! [You can also use other interrupts, see section
* "Optional MCU Description" below, or you can connect D- to the interrupt, as
* it is required if you use the USB_COUNT_SOF feature. If you use D- for the
* interrupt, the USB interrupt will also be triggered at Start-Of-Frame
* markers every millisecond.]
*/
#define USB_CFG_CLOCK_KHZ (F_CPU/1000)
/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000,
* 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code
* require no crystal, they tolerate +/- 1% deviation from the nominal
* frequency. All other rates require a precision of 2000 ppm and thus a
* crystal!
* Since F_CPU should be defined to your actual clock rate anyway, you should
* not need to modify this setting.
*/
A następnie można zabrać się za tekst programu. Jako, że korzystam z całego portu (a raczej z jego części ale cały jest dla mnie) pozwolić sobie mogłem na to żeby dane, który przekaźnik włączyć, a który wyłączyć przekazywać w jednej zmiennej.
Zawsze jak wywoływane jest zdarzenie przychodzące z USB to wykonywana jest funkcja usbFunctionSetup(uchar data[8]). Mogłem wysyłać z komputera bajt danych, który ustawiałbym na porcie B ale chciałem też trochę pracy przerzucić na procesor. Także wymyśliłem sobie, że będą 4 predefiniowane stany ustawienia przekaźnika: Wszystkie wyłączone, wszystkie włączone, 101010 oraz 010101. Oczywiście nie zapomniałem też o stanie wybranym przez użytkownika oprogramowania na komputerze.
Zatem komputer wysyła dwie zmienne. Jedna zmienna to oznaczenie jednego ze stanów predefiniowanych lub własny, a druga zmienna odczytywana jest wtedy i tylko wtedy gdy wybierzemy własne ustawienia stanu przekaźnika.
Cały program wygląda tak.
Kod: Zaznacz cały
/*
* V-USB-LED.c
*
* Created: 4/28/2014 14:36:43
* Author : WoodPaker
*/
#define F_CPU 16000000L //to wyrażenie zostało tutaj wpisane w celach edukacyjnych. Wszyscy wiemy, że nie należy
//wpisywać tej zmiennej bezpośrednio do kodu programu!
#include<avr/io.h>
#include<avr/interrupt.h>
#include<avr/wdt.h>
#include<util/delay.h>
#include"V-USB/usbdrv.h"
#define LED_PORT DDRB
#define LED1_PIN (1<<PB0)
#define LED2_PIN (1<<PB1)
#define LED3_PIN (1<<PB2)
#define LED4_PIN (1<<PB3)
#define LED5_PIN (1<<PB4)
#define LED6_PIN (1<<PB5)
#define USB_F_ALL_OFF 0 //Funkcja która wyłącza wszystkie LEDy
#define USB_F_ALL_ON 1//Funkcja, która włącza wszystkie LEDy
#define USB_F_EVEN 2//Funkcja włączająca LEDy 101010
#define USB_F_ODD 3//Funkcja włączająca LEDy 010101
#define USB_F_USER_CUSTOM 4//dowolne ustawienie wysyłąne z komputera
#define F_ALL_OFF 0b00000000
#define F_ALL_ON 0b00111111
#define F_EVEN 0b00010101 //Od tej strony zaczynamy bo PB0 to LED1 (od prawa do lewej)
#define F_ODD 0b00101010
//Główna funkcja, w której odbywa się komunikacja urządzenie-komputer
USB_PUBLIC uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data; // zamiana data na właściwy typ
uint8_t custom=(uint8_t)(rq->wValue.word); //przypisuje wartość stałej zawierającej informacje, które LEDy włączyć,
//przesłanej z komputera do zmiennej custom
switch(rq->bRequest)// Przełączanie funkcji w zależności od zdażenia z komputera
{
case USB_F_ALL_OFF:
{
LED_PORT = F_ALL_OFF;
usbMsgPtr="All Off";
return 7;
}
case USB_F_ALL_ON:
{
LED_PORT = F_ALL_ON;
usbMsgPtr="All On";
return 6;
}
case USB_F_EVEN:
{
LED_PORT = F_EVEN;
usbMsgPtr="LED Even";
return 8;
}
case USB_F_ODD:
{
LED_PORT = F_ODD;
usbMsgPtr="LED Odd";
return 7;
}
case USB_F_USER_CUSTOM:
{
LED_PORT = custom;
usbMsgPtr="Custom";
return 6;
}
}
return 0; //na wszelki wypadek zwróćmy zero
}
int main(void)
{
//Aktywacja USB, ustawienia zmiennych programu
DDRD = 0b00111111;
wdt_enable(WDTO_2S);// uaktywnij dwusekundowy watchdog
usbInit();//inicjacja USB
usbDeviceDisconnect();// Wymuś przenumerowanie
for(uint8_t i=0; i<250; i++)// Odczekaj około 500 ms
{
wdt_reset();// Poinformuj watchdog, ze procesor działa
_delay_ms(2);
}
usbDeviceConnect();//Podłącz USB
sei();// Aktywuj przerwania po renumeracji
//Tu zaczyna się właściwy program
while(1)
{
wdt_reset();//
usbPoll();
}
return 0;
}
A poniżej wysylam pliki EAGLA oraz kod programu