Project showcase
Simple Wireless Keyboard for PC

Simple Wireless Keyboard for PC © GPL3+

Keyboard designed specifically for YouTube and Netflix on a PC. Works great with music players as well.

  • 11,579 views
  • 8 comments
  • 69 respects

Components and supplies

Apps and online services

About this project

I have my desktop PC meter away from my bed so naturally I like to watch YouTube and movies from the comfort of my bed. Every time I lay down, however, I find myself needing to adjust volume, pause video for some reason, or simply skip video entirely. I could just lean forward and hit a button on the keyboard but I'm too lazy to do that so instead I decided to spend dozens of hours designing and building this remote control for my PC. It's really just wireless keyboard.

I have actually had wireless keyboard already but it's a keyboard. When the lights are off it's basically impossible to find the key I'm looking for. On top of that with it's tiny size I'm more likely to press three buttons at once than the one I want even with my tiny fingers. But really it's just an excuse to build something cool.

It's using Arduino Micro which has ATmega32u4 capable of acting as HID to a computer. Since it works like regular keyboard I even managed to control my android phone with it. For the wireless communication I'm using nRF24L01 and the rotary encoder for volume is custom made with mechanical microswitches. Build instructions can be found here.

Code

Receiver.inoArduino
Code for the receiver
#include <SPI.h>
#include <NRFLite.h>
#include "HID-Project.h"


const static uint8_t RADIO_ID = 7;       // Our radio's id.  The transmitter will send to this id.
const static uint8_t PIN_RADIO_CE = 9;
const static uint8_t PIN_RADIO_CSN = 10;

struct RadioPacket // Any packet up to 32 bytes can be sent.
{
    uint8_t FromRadioId;
    uint32_t OnTimeMillis;
    uint32_t FailedTxCount;
};

NRFLite _radio;
RadioPacket _radioData;

void setup()
{
    if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN))  //Checks if radio is connected
    {
        while (1); // Wait here forever.
    }
    Consumer.begin();       //initialization of keyboard. Arduino will act as HID
    pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
    while (_radio.hasData())          //when data is received over radio
    {
        digitalWrite(LED_BUILTIN,HIGH);
        _radio.readData(&_radioData);
        int msg = _radioData.OnTimeMillis;    //saves received data in msg
        bool YTflag = true;                   //Determines youtube or media mode
        if (msg > 100) {                      //checks if the remote is in youtube or media mode
          YTflag = false;
          msg -= 100;
        }
        switch(msg){                        //Outputs appropriate key presses as keyboard
          case 4:
          Consumer.write(MEDIA_VOLUME_DOWN);
          break;
          case 5:
          Consumer.write(MEDIA_VOLUME_UP);
          break;
          case 6:
          if (YTflag){
            Keyboard.print("f");
          }
          else Consumer.write(MEDIA_PREVIOUS);
          break;
          case 7:
          if (YTflag ){
            Keyboard.press(KEY_LEFT_SHIFT);
            Keyboard.press('n');
            delay(50);
            Keyboard.releaseAll();
          }
          else Consumer.write(MEDIA_NEXT);
          break;
          case 8:
          if (YTflag) Keyboard.print("k");
          else {
                //Consumer.write(MEDIA_PLAY_PAUSE);
                Keyboard.print(" ");
          }
          break;
          case 14:
          if (YTflag) Keyboard.print("j");
          else Consumer.write(MEDIA_REWIND);
          break;
          case 15:
          if (YTflag) Keyboard.print("l");
          else Consumer.write(MEDIA_FAST_FORWARD);
          break;
        }
        digitalWrite(LED_BUILTIN,LOW);
    }
}
Remote.inoArduino
Code for the transmitter
#include <SPI.h>
#include <NRFLite.h>
#include "Arduino.h"
#include <avr/sleep.h>
#include <avr/power.h>
#include "RF24.h"

volatile bool input = true;
bool YTmode = true;
long startTime;
int lowBattery = 740;     //Low battery level (740 = 3.65V)

const static uint8_t RADIO_ID = 21;             // Our radio's id.
const static uint8_t DESTINATION_RADIO_ID = 7; // Id of the radio we will transmit to.
const static uint8_t PIN_RADIO_CE = 9;
const static uint8_t PIN_RADIO_CSN = 10;

struct RadioPacket // Any packet up to 32 bytes can be sent.
{
    uint8_t FromRadioId;
    uint32_t OnTimeMillis;
    uint32_t FailedTxCount;
};

RF24 radio(9,10);
NRFLite _radio;
RadioPacket _radioData;

void setup()
{
    //Serial.begin(115200);

    pinMode(2, INPUT);            //interrupt
    pinMode(3, INPUT);     //mode Button
    pinMode(4, INPUT);     //volume down button
    pinMode(5, INPUT);     //volume up button
    pinMode(6, INPUT);     //previous button
    pinMode(7, INPUT);     //next button
    pinMode(8, INPUT);     //play button
/*
Radio    Arduino
CE    -> 9
CSN   -> 10 (Hardware SPI SS)
MOSI  -> 11 (Hardware SPI MOSI)
MISO  -> 12 (Hardware SPI MISO)
SCK   -> 13 (Hardware SPI SCK)
IRQ   -> No connection
VCC   -> No more than 3.6 volts
GND   -> GND
*/
    pinMode(14, INPUT);    //rewind button
    pinMode(15, INPUT);    //skip button
    pinMode(16,OUTPUT);           //backlight LED
    pinMode(17,OUTPUT);           //blue LED
    pinMode(18,OUTPUT);           //red LED

    checkBattery();                                               //checks battery status
    initRadio();                                                  //initialization of radio
    _radioData.FromRadioId = RADIO_ID;
    sendButton(0);
    modeStatus();
    attachInterrupt(digitalPinToInterrupt(2), isr, FALLING);      //Interrupt setup
}

void loop() {
  if(input){          //only occurs during isr method which is interrupt
    checkButtons(); 
    delay(10);  
  }
  enterSleep();       //puts arduino to sleep to save power
}


void checkButtons(){        //Scans which button is pressed and sends message
  startTime = millis();
  digitalWrite(16,HIGH);    //backlight on
  checkBattery();           //makes sure battery isn't low
  modeStatus();             //Lights up the mode LEDs(youtube / media)
  radio.powerUp();          //wakes up radio from sleep
  int message = 0;          //message will be send at the of the method
  
  while(millis()-startTime < 3000){  //runs for 3 seconds
    message = 0;
    if(digitalRead(4)) {
      delay(3);                   //debouncing
      while(digitalRead(4)){}     //debouncing
      delay(3);                   //debouncing
      message = 4;                //sets message that is going to be send
      startTime = millis();       //resets timer
    } else if
    (digitalRead(5)) {
      delay(3);
      while(digitalRead(5)){}
      delay(3);
      message = 5;
      startTime = millis();
    }else if (digitalRead(6)) {
      delay(10);
      while(digitalRead(6)){}
      delay(10);
      message = 6;
      startTime = millis();
    }else if (digitalRead(7)) {
      delay(10);
      while(digitalRead(7)){}
      delay(10);
      message = 7;
      startTime = millis();
    }
    else if (digitalRead(8)) {
      delay(10);
      while(digitalRead(8)){}
      delay(10);
      message = 8;
      startTime = millis();
    }else if (digitalRead(14)) {
      delay(10);
      while(digitalRead(14)){}
      delay(10);
      message = 14;
      startTime = millis();
    }else if (digitalRead(15)) {
      delay(10);
      while(digitalRead(15)){}
      delay(10);
      message = 15;
      startTime = millis();
    }else if (digitalRead(3)) {
      delay(10);
      while(digitalRead(3)){}
      delay(10);
      changeMode();             //changes between youtube and media mode
      startTime = millis();
    }

    if(message == 0){}                  //checks if there is any message
    else if(YTmode)sendButton(message); //in youtube mode message gets send normally
    else sendButton(message + 100);     //in media mode message is incremented by 100
    delay(10);
  }
  digitalWrite(16,LOW);                 //turns off backlight
  radio.powerDown();                    //Puts radio to sleep
  input =false;                         //prevents from looping
}

void sendButton(int buttonIndex){     //send data over radio

    _radioData.OnTimeMillis = buttonIndex;

    if (_radio.send(DESTINATION_RADIO_ID, &_radioData, sizeof(_radioData))) // Note how '&' must be placed in front of the variable name.
    {
       // Serial.println("...Success");
    }
    else
    {
       // Serial.println("...Failed");
        _radioData.FailedTxCount++;
    }
}

void isr(){                       //called when interrupt happens which wakes up arduino from sleep
  input = true;
}

void enterSleep(){              //Puts arduino to sleep to save power
  digitalWrite(16,LOW);   //Turns off all LEDs
  digitalWrite(17,LOW);
  digitalWrite(18,LOW);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  //waits until woken up
  sleep_disable();
  power_all_enable();
}

void changeMode(){            //Changes between youtube and media mode
  delay(10);
  while (digitalRead(3)){}
  delay(10);
  YTmode = !YTmode;
  if(YTmode) {
    digitalWrite(17,LOW);
    digitalWrite(18,HIGH);
  }else{
    digitalWrite(17,HIGH);
    digitalWrite(18,LOW);
  }
}

void initRadio(){     //initialization of radio
   if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN)) //if radio can't be found turn on all LEDs and do nothing.
    {
        digitalWrite(16,HIGH);
        digitalWrite(17,HIGH);
        digitalWrite(18,HIGH); 
        while (1); // Wait here forever.
    }
}

void modeStatus(){
  if(YTmode) {                        //setting the mode LED
      digitalWrite(17,LOW);
      digitalWrite(18,HIGH);
    }else{
      digitalWrite(17,HIGH);
      digitalWrite(18,LOW);
    }
}

void checkBattery(){                  //makes sure battery isn't too low
  if (analogRead(A5) < lowBattery){   //if battery is too low blink couple of times
    for(int i=0; i<=4; i++){
      digitalWrite(16,LOW);
      delay(200);
      digitalWrite(16,HIGH);
      delay(200);
    }
    detachInterrupt(0);           // detach interrupt and go to sleep. Arduino cannot be woken after this point. only reset will make it work
    enterSleep();
  }
}

Custom parts and enclosures

3D models
STL files of all parts
3dmodels_BUHKItFjXO.zip

Schematics

Recevier
Schematic for the receiver. Fritzing file
schem_media_receiver_8QK331p3wB.fzz
Transmitter
Schematic for the transmitter. Fritzing file
schem_media_remote_lzZ89yJWqP.fzz

Comments

Similar projects you might like

Arduino Bluetooth Basic Tutorial

by Mayoogh Girish

  • 457,804 views
  • 44 comments
  • 246 respects

Home Automation Using Raspberry Pi 2 And Windows 10 IoT

Project tutorial by Anurag S. Vasanwala

  • 287,476 views
  • 95 comments
  • 674 respects

Security Access Using RFID Reader

by Aritro Mukherjee

  • 231,298 views
  • 40 comments
  • 241 respects

OpenCat

Project in progress by Team Petoi

  • 197,246 views
  • 154 comments
  • 1,372 respects
Add projectSign up / Login