This is the schematic:

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;
}
/* ------------------------------------------------------------------------- */