This is the schematic:
![Image](http://www.mikrocontroller.net/attachment/226803/AC-PG-USBASP_03_LRG_1_.jpg)
Can I use this device as V-USB device?
Can you help me to Implement a 4 Button HID Keyboard?
Ripper121
Code: Select all
------
MOSI PB3 | 1 2 | +5V
N/C | 3 4 | PD1 TXD (via 1K resistor)
/RES PB2 5 6 | PD0 RXD
SCK PB5 | 7 8 | GND
MISO PB4 | 9 10 | GND
------
Male end on programmer
Can you help me to Implement a 4 Button HID Keyboard?
But it should work with 8 keys.
Code: Select all
/* Name: main.c
* Project: HID-Test
* Author: Christian Starkjohann
* Creation Date: 2006-02-02
* Tabsize: 4
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
* This Revision: $Id$
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include "usbdrv.h"
#include "oddebug.h"
/* ----------------------- hardware I/O abstraction ------------------------ */
/* pin assignments:
PB0 Key 1
PB1 Key 2
PB2 Key 3
PB3 Key 4
PB4 Key 5
PB5 Key 6
PC0 Key 7
PC1 Key 8
PC2 Key 9
PC3 Key 10
PC4 Key 11
PC5 Key 12
PD0 USB-
PD1 debug tx
PD2 USB+ (int0)
PD3 Key 13
PD4 Key 14
PD5 Key 15
PD6 Key 16
PD7 Key 17
*/
uint8_t keyscan( void )
{
DDRB &= ~( (1<<PB4) ); // PB4 als Eingaenge
PORTB |= ( (1<<PB4) ); // PB4 Pull-Up einschalten
DDRB |= (1 << PB5); // Ausgang
PORTB &= ~(1 << PB5); //Low
if (!(PIND & (1<<PIND1))){
if (!(PINB & (1<<PINB4))) {
return 1;
}
}
if (!(PIND & (1<<PIND0))) {
if (!(PINB & (1<<PINB4))) {
return 2;
}
}
if (!(PINB & (1<<PINB2))) {
if (!(PINB & (1<<PINB4))) {
return 3;
}
}
if (!(PINB & (1<<PINB3))) {
if (!(PINB & (1<<PINB4))) {
return 4;
}
}
DDRB &= ~( (1<<PB5) ); // PB5 als Eingaenge
PORTB |= ( (1<<PB5) ); // PB5 Pull-Up einschalten
DDRB |= (1 << PB4); // Ausgang
PORTB &= ~(1 << PB4); //Low
if (!(PIND & (1<<PIND1))) {
if (!(PINB & (1<<PINB5))) {
return 5;
}
}
if (!(PIND & (1<<PIND0))) {
if (!(PINB & (1<<PINB5))) {
return 6;
}
}
if (!(PINB & (1<<PINB2))) {
if (!(PINB & (1<<PINB5))) {
return 7;
}
}
if (!(PINB & (1<<PINB3))) {
if (!(PINB & (1<<PINB5))) {
return 8;
}
}
return 0;
}
static void hardwareInit(void)
{
DDRC |= (1 << PC0); // Ausgang
PORTC &= ~(1 << PC0); //PB1 High
DDRC |= (1 << PC1); // Ausgang
PORTC &= ~(1 << PC1); //PB1 High
DDRB &= ~( (1<<PB2) ); // PB2 als Eingaenge
PORTB |= ( (1<<PB2) ); // PB2 Pull-Up einschalten
DDRB &= ~( (1<<PB3) ); // PB3 als Eingaenge
PORTB |= ( (1<<PB3) ); // PB3 Pull-Up einschalten
DDRD &= ~( (1<<PD0) ); // PD0 als Eingaenge
PORTD |= ( (1<<PD0) ); // PD0 Pull-Up einschalten
DDRD &= ~( (1<<PD1) ); // PD1 als Eingaenge
PORTD |= ( (1<<PD1) ); // PD1 Pull-Up einschalten
/* configure timer 0 for a rate of 12M/(1024 * 256) = 45.78 Hz (~22ms) */
TCCR0 = 5; /* timer 0 prescaler: 1024 */
}
/* ------------------------------------------------------------------------- */
#define NUM_KEYS 8
/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */
static uchar reportBuffer[2]; /* buffer for HID reports */
static uchar idleRate; /* in 4 ms units */
const PROGMEM char usbHidReportDescriptor[35] = { /* USB report descriptor */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
};
/* We use a simplifed keyboard report descriptor which does not support the
* boot protocol. We don't allow setting status LEDs and we only allow one
* simultaneous key press (except modifiers). We can therefore use short
* 2 byte input reports.
* The report descriptor has been created with usb.org's "HID Descriptor Tool"
* which can be downloaded from http://www.usb.org/developers/hidpage/.
* Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
* for the second INPUT item.
*/
/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
* 10 Keyboard/Keypad Page for more codes.
*/
#define MOD_CONTROL_LEFT (1<<0)
#define MOD_SHIFT_LEFT (1<<1)
#define MOD_ALT_LEFT (1<<2)
#define MOD_GUI_LEFT (1<<3)
#define MOD_CONTROL_RIGHT (1<<4)
#define MOD_SHIFT_RIGHT (1<<5)
#define MOD_ALT_RIGHT (1<<6)
#define MOD_GUI_RIGHT (1<<7)
#define KEY_A 4
#define KEY_B 5
#define KEY_C 6
#define KEY_D 7
#define KEY_E 8
#define KEY_F 9
#define KEY_G 10
#define KEY_H 11
#define KEY_I 12
#define KEY_J 13
#define KEY_K 14
#define KEY_L 15
#define KEY_M 16
#define KEY_N 17
#define KEY_O 18
#define KEY_P 19
#define KEY_Q 20
#define KEY_R 21
#define KEY_S 22
#define KEY_T 23
#define KEY_U 24
#define KEY_V 25
#define KEY_W 26
#define KEY_X 27
#define KEY_Y 28
#define KEY_Z 29
#define KEY_1 30
#define KEY_2 31
#define KEY_3 32
#define KEY_4 33
#define KEY_5 34
#define KEY_6 35
#define KEY_7 36
#define KEY_8 37
#define KEY_9 38
#define KEY_0 39
#define KEY_F1 58
#define KEY_F2 59
#define KEY_F3 60
#define KEY_F4 61
#define KEY_F5 62
#define KEY_F6 63
#define KEY_F7 64
#define KEY_F8 65
#define KEY_F9 66
#define KEY_F10 67
#define KEY_F11 68
#define KEY_F12 69
static const uchar keyReport[NUM_KEYS + 1][2] PROGMEM = {
/* none */ {0, 0}, /* no key pressed */
/* 1 */ {MOD_SHIFT_LEFT, KEY_A},
/* 2 */ {MOD_SHIFT_LEFT, KEY_B},
/* 3 */ {MOD_SHIFT_LEFT, KEY_C},
/* 4 */ {MOD_SHIFT_LEFT, KEY_D},
/* 5 */ {MOD_SHIFT_LEFT, KEY_E},
/* 6 */ {MOD_SHIFT_LEFT, KEY_F},
/* 7 */ {MOD_SHIFT_LEFT, KEY_G},
/* 8 */ {MOD_SHIFT_LEFT, KEY_H},
};
static void buildReport(uchar key)
{
/* This (not so elegant) cast saves us 10 bytes of program memory */
*(int *)reportBuffer = pgm_read_word(keyReport[key]);
}
uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
usbMsgPtr = reportBuffer;
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */
if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */
/* we only have one report type, so don't look at wValue */
buildReport(keyscan());
return sizeof(reportBuffer);
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){
usbMsgPtr = &idleRate;
return 1;
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){
idleRate = rq->wValue.bytes[1];
}
}else{
/* no vendor specific requests implemented */
}
return 0;
}
/* ------------------------------------------------------------------------- */
int main(void)
{
uchar key, lastKey = 0, keyDidChange = 0;
uchar idleCounter = 0;
wdt_enable(WDTO_2S);
hardwareInit();
odDebugInit();
usbInit();
sei();
DBG1(0x00, 0, 0);
for(;;){ /* main event loop */
wdt_reset();
usbPoll();
key = keyscan();
if(lastKey != key){
lastKey = key;
keyDidChange = 1;
}
if(TIFR & (1<<TOV0)){ /* 22 ms timer */
TIFR = 1<<TOV0;
if(idleRate != 0){
if(idleCounter > 4){
idleCounter -= 5; /* 22 ms in units of 4 ms */
}else{
idleCounter = idleRate;
keyDidChange = 1;
}
}
}
if(keyDidChange && usbInterruptIsReady()){
keyDidChange = 0;
/* use last key and not current key status in order to avoid lost
changes in key status. */
buildReport(lastKey);
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
}
return 0;
}
/* ------------------------------------------------------------------------- */
Code: Select all
if (!(PIND & (1<<PIND0))) { // error
if (!(PIND & (1<<PD0))) { // correct
if (!(PIND & (1<<0))) { // what I use
Code: Select all
uint8_t keyscan( void )
{
PORTB |= ( (1<<PB4) ); // PB4 Pull-Up einschalten
[...]
PORTB &= ~(1 << PB5); //Low
if (!(PIND & (1<<PD1))){
if (!(PINB & (1<<PB4))) {
return 1;
}
}
Code: Select all
uint8_t keyscan( void )
{
PORTB |= ( (1<<PB4) ); // PB4 Pull-Up einschalten
[...]
PORTB &= ~(1 << PB5); //Low
_delay_us( 200 ); // added
if (!(PIND & (1<<PD1))){
if ((PINB & (1<<PB4))) {
return 1;
}
}
Code: Select all
for(;;){ /* main event loop */
wdt_reset();
usbPoll();
if(TIFR & (1<<TOV0)){ /* 22 ms timer */
TIFR = 1<<TOV0;
if(idleRate != 0){
if(idleCounter > 4){
idleCounter -= 5; /* 22 ms in units of 4 ms */
}else{
idleCounter = idleRate;
keyDidChange = 1;
}
}
}
if(usbInterruptIsReady()){ // only scan if USB is ready
key = keyscan();
if(lastKey != key){
lastKey = key;
keyDidChange = 1;
}
if(keyDidChange){
keyDidChange = 0;
/* use last key and not current key status in order to avoid lost
changes in key status. */
buildReport(lastKey);
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
}
}
Code: Select all
/* Name: main.c
* Project: HID-Test
* Author: Christian Starkjohann
* Creation Date: 2006-02-02
* Tabsize: 4
* Copyright: (c) 2006 by OBJECTIVE DEVELOPMENT Software GmbH
* License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
* This Revision: $Id$
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include "usbdrv.h"
#include "oddebug.h"
/* ----------------------- hardware I/O abstraction ------------------------ */
/* pin assignments:
PB0 Key 1
PB1 Key 2
PB2 Key 3
PB3 Key 4
PB4 Key 5
PB5 Key 6
PC0 Key 7
PC1 Key 8
PC2 Key 9
PC3 Key 10
PC4 Key 11
PC5 Key 12
PD0 USB-
PD1 debug tx
PD2 USB+ (int0)
PD3 Key 13
PD4 Key 14
PD5 Key 15
PD6 Key 16
PD7 Key 17
*/
uint8_t keyscan( void )
{
DDRB &= ~( (1<<PB4) ); // PB4 als Eingaenge
PORTB |= ( (1<<PB4) ); // PB4 Pull-Up einschalten
DDRB |= (1 << PB5); // Ausgang
PORTB &= ~(1 << PB5); //Low
_delay_us( 200 );
if (!(PIND & (1<<PD1))){
if ((PINB & (1<<PB4))) {
return 1;
}
}
if (!(PIND & (1<<PD0))) {
if ((PINB & (1<<PB4))) {
return 2;
}
}
if (!(PINB & (1<<PB2))) {
if ((PINB & (1<<PB4))) {
return 3;
}
}
if (!(PINB & (1<<PB3))) {
if ((PINB & (1<<PB4))) {
return 4;
}
}
DDRB &= ~( (1<<PB5) ); // PB5 als Eingaenge
PORTB |= ( (1<<PB5) ); // PB5 Pull-Up einschalten
DDRB |= (1 << PB4); // Ausgang
PORTB &= ~(1 << PB4); //Low
_delay_us( 200 );
if (!(PIND & (1<<PD1))) {
if ((PINB & (1<<PB5))) {
return 5;
}
}
if (!(PIND & (1<<PD0))) {
if ((PINB & (1<<PB5))) {
return 6;
}
}
if (!(PINB & (1<<PB2))) {
if ((PINB & (1<<PB5))) {
return 7;
}
}
if (!(PINB & (1<<PB3))) {
if ((PINB & (1<<PB5))) {
return 8;
}
}
return 0;
}
static void hardwareInit(void)
{
DDRC |= (1 << PC0); // Ausgang
PORTC &= ~(1 << PC0); //PB1 High
DDRC |= (1 << PC1); // Ausgang
PORTC &= ~(1 << PC1); //PB1 High
DDRB &= ~( (1<<PB2) ); // PB2 als Eingaenge
PORTB |= ( (1<<PB2) ); // PB2 Pull-Up einschalten
DDRB &= ~( (1<<PB3) ); // PB3 als Eingaenge
PORTB |= ( (1<<PB3) ); // PB3 Pull-Up einschalten
DDRD &= ~( (1<<PD0) ); // PD0 als Eingaenge
PORTD |= ( (1<<PD0) ); // PD0 Pull-Up einschalten
DDRD &= ~( (1<<PD1) ); // PD1 als Eingaenge
PORTD |= ( (1<<PD1) ); // PD1 Pull-Up einschalten
/* configure timer 0 for a rate of 12M/(1024 * 256) = 45.78 Hz (~22ms) */
TCCR0 = 5; /* timer 0 prescaler: 1024 */
}
/* ------------------------------------------------------------------------- */
#define NUM_KEYS 8
/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */
static uchar reportBuffer[2]; /* buffer for HID reports */
static uchar idleRate; /* in 4 ms units */
const PROGMEM char usbHidReportDescriptor[35] = { /* USB report descriptor */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
};
/* We use a simplifed keyboard report descriptor which does not support the
* boot protocol. We don't allow setting status LEDs and we only allow one
* simultaneous key press (except modifiers). We can therefore use short
* 2 byte input reports.
* The report descriptor has been created with usb.org's "HID Descriptor Tool"
* which can be downloaded from http://www.usb.org/developers/hidpage/.
* Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
* for the second INPUT item.
*/
/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
* 10 Keyboard/Keypad Page for more codes.
*/
#define MOD_CONTROL_LEFT (1<<0)
#define MOD_SHIFT_LEFT (1<<1)
#define MOD_ALT_LEFT (1<<2)
#define MOD_GUI_LEFT (1<<3)
#define MOD_CONTROL_RIGHT (1<<4)
#define MOD_SHIFT_RIGHT (1<<5)
#define MOD_ALT_RIGHT (1<<6)
#define MOD_GUI_RIGHT (1<<7)
#define KEY_A 4
#define KEY_B 5
#define KEY_C 6
#define KEY_D 7
#define KEY_E 8
#define KEY_F 9
#define KEY_G 10
#define KEY_H 11
#define KEY_I 12
#define KEY_J 13
#define KEY_K 14
#define KEY_L 15
#define KEY_M 16
#define KEY_N 17
#define KEY_O 18
#define KEY_P 19
#define KEY_Q 20
#define KEY_R 21
#define KEY_S 22
#define KEY_T 23
#define KEY_U 24
#define KEY_V 25
#define KEY_W 26
#define KEY_X 27
#define KEY_Y 28
#define KEY_Z 29
#define KEY_1 30
#define KEY_2 31
#define KEY_3 32
#define KEY_4 33
#define KEY_5 34
#define KEY_6 35
#define KEY_7 36
#define KEY_8 37
#define KEY_9 38
#define KEY_0 39
#define KEY_F1 58
#define KEY_F2 59
#define KEY_F3 60
#define KEY_F4 61
#define KEY_F5 62
#define KEY_F6 63
#define KEY_F7 64
#define KEY_F8 65
#define KEY_F9 66
#define KEY_F10 67
#define KEY_F11 68
#define KEY_F12 69
static const uchar keyReport[NUM_KEYS + 1][2] PROGMEM = {
/* none */ {0, 0}, /* no key pressed */
/* 1 */ {MOD_SHIFT_LEFT, KEY_A},
/* 2 */ {MOD_SHIFT_LEFT, KEY_B},
/* 3 */ {MOD_SHIFT_LEFT, KEY_C},
/* 4 */ {MOD_SHIFT_LEFT, KEY_D},
/* 5 */ {MOD_SHIFT_LEFT, KEY_E},
/* 6 */ {MOD_SHIFT_LEFT, KEY_F},
/* 7 */ {MOD_SHIFT_LEFT, KEY_G},
/* 8 */ {MOD_SHIFT_LEFT, KEY_H},
};
static void buildReport(uchar key)
{
/* This (not so elegant) cast saves us 10 bytes of program memory */
*(int *)reportBuffer = pgm_read_word(keyReport[key]);
}
uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
usbMsgPtr = reportBuffer;
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */
if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */
/* we only have one report type, so don't look at wValue */
buildReport(keyscan());
return sizeof(reportBuffer);
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){
usbMsgPtr = &idleRate;
return 1;
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){
idleRate = rq->wValue.bytes[1];
}
}else{
/* no vendor specific requests implemented */
}
return 0;
}
/* ------------------------------------------------------------------------- */
int main(void)
{
uchar key, lastKey = 0, keyDidChange = 0;
uchar idleCounter = 0;
wdt_enable(WDTO_2S);
hardwareInit();
odDebugInit();
usbInit();
sei();
DBG1(0x00, 0, 0);
for(;;){ /* main event loop */
wdt_reset();
usbPoll();
if(TIFR & (1<<TOV0)){ /* 22 ms timer */
TIFR = 1<<TOV0;
if(idleRate != 0){
if(idleCounter > 4){
idleCounter -= 5; /* 22 ms in units of 4 ms */
}else{
idleCounter = idleRate;
keyDidChange = 1;
}
}
}
if(usbInterruptIsReady()){
key = keyscan();
if(lastKey != key){
lastKey = key;
keyDidChange = 1;
}
if(keyDidChange){
keyDidChange = 0;
/* use last key and not current key status in order to avoid lost
changes in key status. */
buildReport(lastKey);
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
}
}
return 0;
}
/* ------------------------------------------------------------------------- */