Amazon Store

Tuesday 24 March 2015

How to Transmit Mouse Data Using Xbee with Arduino

The PS2 mouse is an input device which can communicate with a host device using the PS2 protocol. It can be connected to a host device using the 6 pin mini DIN connector. The mouse will continuously give output which can be decoded to get the movement in the X-Y plane and also the status of the buttons on the mouse.

The data read from the mouse can be decoded and processed to get the amount of change in position of the mouse with respect to the position at the previous read. This data is normally used in PCs to move a pointer in the screen. The PS2 protocol is a simple two wire synchronous protocol which makes it possible for the simple microcontroller board to interface the standard PS2 mouse or keyboard with it.

This particular project demonstrates how to transmit the data read from a standard PS2 mouse from a microcontroller board to a distant PC. The microcontroller board used in this project is the easy prototyping hardware platform Arduino and the wireless transmission system is implemented using Xbee transceiver modules.

The Xbee is the brand name wireless transceiver device which works on the ZigBee protocol. The ZigBee is the name of a wireless protocol maintained by the IEEE 802.15 standard. This protocol is specified for wireless Personal Area Network (PAN) using low powered wireless transceivers. They can be used for simple point to point communication systems also.

How to Transmit Mouse Data Using Xbee with Arduino

Circuit Diagram:

In this project the Arduino pro-mini board is used which is pre-programmed with the Arduino boot-loader.The programming IDE used for this project isArduino IDE version 1.0.3 on windows operating system. The image of the Arduino pro-mini board and the Arduino IDE is shown in the following:

 

Arduino Pro Mini

 

Arduino Programming

 

 

Another hardware which can perform the USB to TTL conversion is used to upload the program into the arduino board. This board can be also when it is required to perform serial communication between the PC and the Arduino board.

USB to TTL converter

 

It is assumed that the reader has gone through the project how to get started with the arduino and done all the things discussed in it.

The PS2 mouse uses a synchronous communication with the PC which is very much similar to the Two Wire Interface protocol. The PS2 connector has a pin for Data and another pin for Clock and using only these two pins the mouse communicate with the host device. The mouse always has 6 pin mini-DIN male connector for PS2 interface and the host device always has the corresponding female pin. The images and the pin-outs of the PS2 male and female connectors are shown in the following image:

The image of the PS2 male pin

Male PS2 Connector

The image of the PS2 female pin

Female PS2 Connector

The pin-out of the PS2 male and female connectors

PS2 Connector Output

When it comes to connecting the female connector with the circuit board one should be able to identify the pins at the bottom of the PS2 connector and the following image will be helpful.

PS2 Connector Pinout

 

The code written for this project uses the custom PS2 library file called "PS2Mouse.h" which has all the necessary routines for accessing a PS2 mouse. There are two functions which the user can directly make use in their code and are namely "mouse.initialize()" and "mouse.report(data)". The details of the functions are discussed in the following.

mouse.initialize()

The function mouse.initialize() is used to perform all the necessary things to initialize data reporting from a mouse. Once the initialization is done properly the mouse starts sending the data regarding its X-Y movement and the status of the buttons on the mouse. The function takes no parameter and returns nothing but will exist only when the initialization is properly done.

mouse.report(data)

The function mouse.report(data) can be used to read the current data from the mouse. The function should be provided with an integer array of three elements and the function will fill the elements with the required values. The first element is written with the status value, the second element with the X movement value and the third element will be written with the Y movement value.

The method of reading the data from the PS2 mouse using the above functions and decoding them to get the X-Y coordinates are explained in a previous project on how to interface a PS2 mouse with the Arduino.

Two Xbee S1 series transceivers modules are used in this project and the image of the same module shown in the following figure. Since the pitch of the pins of the modules are not breadboard compatible one can use the Xbee based design boards which comes with breadboard compatible pins.

 

Zigbee

 

The Xbee modules have several digital and analog I/O pins apart from these pins and the pin out of an Xbee module is shown in the following table:

 

PIN

DESCRIPTION

1

Power Supply

2

UART Data Out

3

UART Data In

4

Digital Output 8 (not supported as of 2/28/09)

5

Module Reset (reset pulse must be at least 200 ns)

6

PWM Output 0 / RX Signal Strength Indicator

7

PWM Output 1

8

Do not connect

9

DTR / Pin Sleep Control Line or Digital Input 8

10

Ground

11

Analog Input 4 or Digital I/O 4

12

Clear-to-Send Flow Control or Digital I/O 7

13

Module Status Indicator

14

Voltage Reference for A/D Inputs

15

Associated Indicator, Analog Input 5 or Digital I/O 5

16

Request-to-Send Flow Control, Analog Input 6 or Digital I/O 6

17

Analog Input 3 or Digital I/O 3

18

Analog Input 2 or Digital I/O 2

19

Analog Input 1 or Digital I/O 1

20

Analog Input 0 or Digital I/O 0

 

Since the Xbee modules communicate using serial communication protocol with the interfacing devices they can be connected to a microcontroller using a minimum of four pins, Power supply, and Ground, UART Data Out, and UART Data In pins. The pin number 2, UART Data Out is connected to the RX1 pin of the Arduino pro mini board and pin number 3 UART Data In is connected to the TX0 pin.

The implementation of the project which can receive the data from PS2 mouse and transmit the X-Y coordinate extracted from the mouse data through Xbee is represented using the following block diagram:

 

Mouse Interfacing With Arduino

The code written for this project on Arduino reads the PS2 mouse data continuously and writes the same data to the Xbee for transmission with the help of serial communication functions provided by the Arduino IDE. The functions like Serial.begin() which helps to initialize the serial port with a given baud rate, Serial.write() to send a data to the serial port, Serial.available() and Serial.read() functions to read data from the serial port are used in this project and they are already discussed in previous projects on how to do serial communication with the Arduino,how to send and receive serial data using arduino and how to do serial debugging with the Arduino. The method of getting the required X-Y data from the PS2 mouse is explained in the previous project on how to interface a PS2 mouse with the Arduino. The method of interfacing an Xbee module and transmission of data using it is discussed in as previous project on how to interface Xbee module with Arduino{C}{C}{C}{C}{C}{C}[H1]{C}{C}{C}{C}{C}{C} {C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}.

When the coding is finished one can verify and upload the code to the Arduino board as explained in the project how to get started with the Arduino. As soon as the board is powered up the Xbee in the Arduino board automatically establishes communication with another Xbee which is connected to the serial port of a PC. The second Xbee board can be connected to the PC using the same USB to TTL converter board which has been used to program the Arduino board. The X-Y position can be then be read using any serial monitoring software or using the Arduino IDE's serial monitoring software itself as explained in the project how to do serial debugging with the Arduino.

Code1:
/*============================ EG LABS ===================================//
 Demonstration on how to wirelessly send mouse data using Xbee
 
 The circuit:
 LCD:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 7
 * LCD D5 pin to digital pin 6
 * LCD D6 pin to digital pin 5
 * LCD D7 pin to digital pin 4
 * LCD R/W pin to ground
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD pin 3
 * LED anode attached to digital output 9
 * LED cathode attached to ground through a 1K resistor
 
 MOUSE:
 DATA PIN TO PIN NUMBER 8
 CLOCK PIN TO PIN NUMBER 3
 
 XBEE:
 RX PIN OF XBEE TO TX0 PIN OF ARDUINO
 SHORT THE GROUND PINS OF ARDUINO AND XBEE
============================== EG LABS ===================================*/
 
#include "PS2Mouse.h"
#define MOUSE_DATA 8                                                              
#define MOUSE_CLOCK 3
// include the library code:
#include <LiquidCrystal.h>
 
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
 
PS2Mouse mouse(MOUSE_CLOCK, MOUSE_DATA, STREAM);                              // initializing the PS2 library
 
int data[2];
int led = 9;
 
void setup()
{
  pinMode(led, OUTPUT);     
  lcd.begin(16, 2);
  lcd.print("ENGINEERS GARAGE");
  lcd.setCursor(0, 1);
  lcd.print("    PS2 MOUSE   ");
  delay(2000);
  lcd.clear();
  Serial.begin(9600);
  
  mouse.initialize();                                                        // initializing the PS2 mouse connected with the Arduino
  digitalWrite(led, HIGH);  
}
 
void loop()
{
  mouse.report(data);                                                       // get data from the mouse
 
  if((data[1] != 0) || (data[2] != 0) || (data[0] != 8))
  {
      lcd.clear();
      Serial.print("X = ");
      lcd.print("X=");
      Serial.print(data[1]);                                                 // X Movement Data
      lcd.print(data[1]);
      lcd.setCursor(0, 1);
      
      Serial.print(", Y = ");
      lcd.print("Y=");
      Serial.print(data[2]);                                                 // Y Movement Data
      lcd.print(data[2]);  
      
      if(data[0] == 9)
            Serial.print(", LEFT BUTTON");                                  // Status Byte
      else if (data[0] == 10)
            Serial.print(", RIGHT BUTTON");                                 // Status Byte
      else if (data[0] == 12)
            Serial.print(", CENTRE BUTTON");                                // Status Byte
      else;
      
      Serial.println();
  }else;
 

Code2: 

//#include "WConstants.h"
#include "HardwareSerial.h"
#include "PS2Mouse.h"
#include "Arduino.h"
 
PS2Mouse::PS2Mouse(int clock_pin, int data_pin, int mode) {
  _clock_pin = clock_pin;
  _data_pin = data_pin;
  _mode = mode;
  _initialized = false;  
  _disabled = true;
  _enabled = false;
}
 
int PS2Mouse::clock_pin() {
  return _clock_pin;
}
 
int PS2Mouse::data_pin() {
  return _data_pin;
}
 
void PS2Mouse::initialize() {
  pull_high(_clock_pin);
  pull_high(_data_pin);
  delay(20);
  write(0xff); // Send Reset to the mouse
  read_byte();  // Read ack byte 
  delay(20); // Not sure why this needs the delay
  read_byte();  // blank 
  read_byte();  // blank
  delay(20); // Not sure why this needs the delay
  if (_mode == REMOTE) {
    set_remote_mode();
  } else {
    enable_data_reporting(); // Tell the mouse to start sending data again
  }
  delayMicroseconds(100);
  _initialized = 1;
}
 
void PS2Mouse::set_mode(int data) {
  if (_mode == STREAM) {
    disable_data_reporting(); // Tell the mouse to stop sending data.
  }
  write(data);  // Send Set Mode
  read_byte();  // Read Ack byte
  if (_mode == STREAM) {
    enable_data_reporting(); // Tell the mouse to start sending data again
  }
  if (_initialized) {
    delayMicroseconds(100);    
  }
}
 
void PS2Mouse::set_remote_mode() {
  set_mode(0xf0);
  _mode = REMOTE;
}
  
void PS2Mouse::set_stream_mode() {
  set_mode(0xea);
  _mode = STREAM;
}
 
void PS2Mouse::set_sample_rate(int rate) {
  if (_mode == STREAM) {
    disable_data_reporting(); // Tell the mouse to stop sending data.
  }
  write(0xf3); // Tell the mouse we are going to set the sample rate.
  read_byte(); // Read Ack Byte
  write(rate); // Send Set Sample Rate
  read_byte(); // Read ack byte
  if (_mode == STREAM) {
    enable_data_reporting(); // Tell the mouse to start sending data again
  }
  delayMicroseconds(100);
}
 
void PS2Mouse::set_scaling_2_1() {
  set_mode(0xe7); // Set the scaling to 2:1
}
 
void PS2Mouse::set_scaling_1_1() {
  set_mode(0xe6); // set the scaling to 1:1
}
 
// This only effects data reporting in Stream mode.
void PS2Mouse::enable_data_reporting() {
  if (!_enabled) {
    write(0xf4); // Send enable data reporting
    read_byte(); // Read Ack Byte
    _enabled = true;
  }
}
 
// Disabling data reporting in Stream Mode will make it behave like Remote Mode
void PS2Mouse::disable_data_reporting() {
  if (!_disabled) {
    write(0xf5); // Send disable data reporting
    read_byte(); // Read Ack Byte    
    _disabled = true;
  }
}
 
void PS2Mouse::set_resolution(int resolution) {
  if (_mode == STREAM) {
    enable_data_reporting();
  }
  write(0xe8); // Send Set Resolution
  read_byte(); // Read ack Byte
  write(resolution); // Send resolution setting
  read_byte(); // Read ack Byte
  if (_mode == STREAM) {
    disable_data_reporting();
  }
  delayMicroseconds(100);
}
 
void PS2Mouse::write(int data) {
  char i;
  char parity = 1;
  pull_high(_data_pin);
  pull_high(_clock_pin);
  delayMicroseconds(300);
  pull_low(_clock_pin);
  delayMicroseconds(300);
  pull_low(_data_pin);
  delayMicroseconds(10);
  pull_high(_clock_pin); // Start Bit
  while (digitalRead(_clock_pin)) {;} // wait for mouse to take control of clock)
  // clock is low, and we are clear to send data 
  for (i=0; i < 8; i++) {
    if (data & 0x01) {
      pull_high(_data_pin);
    } else {
      pull_low(_data_pin);
    }
    // wait for clock cycle 
    while (!digitalRead(_clock_pin)) {;}
    while (digitalRead(_clock_pin)) {;}
    parity = parity ^ (data & 0x01);
    data = data >> 1;
  }  
  // parity 
  if (parity) {
    pull_high(_data_pin);
  } else {
    pull_low(_data_pin);
  }
  while (!digitalRead(_clock_pin)) {;}
  while (digitalRead(_clock_pin)) {;}  
  pull_high(_data_pin);
  delayMicroseconds(50);
  while (digitalRead(_clock_pin)) {;}
  while ((!digitalRead(_clock_pin)) || (!digitalRead(_data_pin))) {;} // wait for mouse to switch modes
  pull_low(_clock_pin); // put a hold on the incoming data.
}
 
int * PS2Mouse::report(int data[]) {
  write(0xeb); // Send Read Data
  read_byte(); // Read Ack Byte
  data[0] = read(); // Status bit
  data[1] = read_movement_x(data[0]); // X Movement Packet
  data[2] = read_movement_y(data[0]); // Y Movement Packet
  return data;
}
 
int PS2Mouse::read() {
  return read_byte();
}
 
int PS2Mouse::read_byte() {
  int data = 0;
  pull_high(_clock_pin);
  pull_high(_data_pin);
  delayMicroseconds(50);
  while (digitalRead(_clock_pin)) {;}
  delayMicroseconds(5);  // not sure why.
  while (!digitalRead(_clock_pin)) {;} // eat start bit
  for (int i = 0; i < 8; i++) {
    bitWrite(data, i, read_bit());
  }
  read_bit(); // Partiy Bit 
  read_bit(); // Stop bit should be 1
  pull_low(_clock_pin);
  return data;
}
 
int PS2Mouse::read_bit() {
  while (digitalRead(_clock_pin)) {;}
  int bit = digitalRead(_data_pin);  
  while (!digitalRead(_clock_pin)) {;}
  return bit;
}
 
int PS2Mouse::read_movement_x(int status) {
  int x = read();
  if (bitRead(status, 4)) {
    for(int i = 8; i < 16; ++i) {
      x |= (1<<i);
    }
  }
  return x;
}
 
int PS2Mouse::read_movement_y(int status) {
  int y = read();
  if (bitRead(status, 5)) {
    for(int i = 8; i < 16; ++i) {
      y |= (1<<i);
    }
  }
  return y;
}
 
void PS2Mouse::pull_low(int pin) {
  pinMode(pin, OUTPUT);
  digitalWrite(pin, LOW);  
}
 
void PS2Mouse::pull_high(int pin) {
  pinMode(pin, INPUT);
  digitalWrite(pin, HIGH);
}
 

No comments:

Post a Comment