Inicjalizacja biblioteki:
Po przygotowaniu projektu dla wybranego mikrokontrolera. Bibliotekę wgrywa się poprzez asf (atmel software framework). Po wgraniu jest ona prawie w pełni gotowa do używania. Zostało już tylko odpowiednio włączyć zegary:
Włączenie zegarów:
Następnym elementem jest włączenie zegarów dla systemu oraz dla USB. Odnośnie zegara USB wspomniałem w poprzednim poście dla rodziny tych mikrokontrolerów.
- void USB_WLACZ_ZEGAR()
- {
- //Wylaczenie przerwan
- cli();
- //Konfiguracja DFLL z zegarem 48MHz
- OSC.DFLLCTRL = OSC_RC32MCREF_USBSOF_gc;
- NVM.CMD = NVM_CMD_READ_CALIB_ROW_gc;
- DFLLRC32M.CALB = pgm_read_byte(offsetof(NVM_PROD_SIGNATURES_t, USBRCOSC));
- DFLLRC32M.COMP1 = 0x1B;
- DFLLRC32M.COMP2 = 0xB7;
- DFLLRC32M.CTRL = DFLL_ENABLE_bm;
- //Modyfikacja zegarow
- CPU_CCP = CCP_IOREG_gc; //Security Signature to modify clock
- //Wlaczenie zegara 32MHz oraz 2MHz
- OSC.CTRL = OSC_RC32MEN_bm | OSC_RC2MEN_bm; // enable internal 32MHz oscillator
- //Odczekanie na wlaczenie zegara 32MHz
- while(!(OSC.STATUS & OSC_RC32MRDY_bm));
- //Ustawienie PLL'a z zegara 2MHz (2MHz * 16)
- OSC.PLLCTRL = OSC_PLLSRC_RC2M_gc | 16;
- //Zezwolenie na modyfikacje zegarow
- CPU_CCP = CCP_IOREG_gc;
- //Wlaczenie petli PLL
- OSC.CTRL = OSC_RC32MEN_bm | OSC_PLLEN_bm | OSC_RC2MEN_bm;
- //Odczekanie na gotowosc
- while(!(OSC.STATUS & OSC_PLLRDY_bm));
- //Wlaczenie DFLL
- DFLLRC2M.CTRL = DFLL_ENABLE_bm;
- //Wlaczenie przerwan
- PMIC_CTRL = PMIC_HILVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm;
- //Zezwolenie na modyfikacje
- CPU_CCP = CCP_IOREG_gc;
- //Wybranie PLL
- CLK.CTRL = CLK_SCLKSEL_PLL_gc;
- //Prescaler na 0
- CLK.PSCTRL = 0x00;
- //Wlaczenie watchdoga 4kCycles, 4s przy 3.3V
- //Dodatkowe ustawienia nie potrzebne dla USB
- ccp_write_io((uint8_t *)&WDT.CTRL, (WDT_PER_4KCLK_gc | WDT_ENABLE_bm | WDT_CEN_bm));
- //Zezwolenie na mapowanie EEPROMU
- NVM_CTRLB = NVM_EEMAPEN_bm;
- //Ustawienie timera
- TCC1.PER = 1*0xFF + 10;
- TCC1.CTRLA = TC_CLKSEL_DIV64_gc;
- TCD1.PER = 1*0xFF + 78;
- TCD1.CTRLA = TC_CLKSEL_DIV1024_gc;
- //Wlaczenie przerwan
- sei();
- }
Przesyłanie danych:
W celu uruchomienia transmisji po USB należy włączyć przerwania irq oraz cpu. Następnie zegar dla układ USB oraz samą bibliotekę.
Główna pętla programu w minimalnym stopniu wygląda następująco:
- int main(void)
- {
- //Wlaczenie
- irq_initialize_vectors();
- cpu_irq_enable();
- //Wlaczenie zegarow
- USB_WLACZ_ZEGAR();
- //Wlaczenie biblioteki
- udc_start();
- while(1)
- {
- }
- }
- void Send_Data_USB()
- {
- udi_hid_kbd_down(HID_L);
- udi_hid_kbd_up(HID_L);
- _delay_ms(100);
- udi_hid_kbd_down(HID_P);
- udi_hid_kbd_up(HID_P);
- _delay_ms(100);
- udi_hid_kbd_down(HID_W);
- udi_hid_kbd_up(HID_W);
- _delay_ms(100);
- udi_hid_kbd_down(HID_2);
- udi_hid_kbd_up(HID_2);
- _delay_ms(100);
- }
Klawisze należy przesyłać poprzez włączenie oraz jego wyłączenie stąd funkcje udi_hid_kbd_down() oraz udi_hid_kbd_up().
Po każdym wysłaniu przycisku należy odczekać pewien okres czasu tak aby kolejne wciśnięcie zostało przez program zapamiętane.
Następnym elementem jest przechodzenie i rozdzielanie danych w celu ich poprawnego przesłania. Jeśli będą one podawane do funkcji to muszą zostać zdefiniowane jako zmienne globalne bądź statyczne w funkcji. Przechodzenie np. po cyfrach czy liczbach w HEX-ie można wykonać poprzez instrukcje if else if czy switch.
Po każdym wysłaniu przycisku należy odczekać pewien okres czasu tak aby kolejne wciśnięcie zostało przez program zapamiętane.
Następnym elementem jest przechodzenie i rozdzielanie danych w celu ich poprawnego przesłania. Jeśli będą one podawane do funkcji to muszą zostać zdefiniowane jako zmienne globalne bądź statyczne w funkcji. Przechodzenie np. po cyfrach czy liczbach w HEX-ie można wykonać poprzez instrukcje if else if czy switch.