CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to support@ccsinfo.com

PS/2 Mouse Driver (uses interrupts)

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
uN_Eof



Joined: 17 May 2010
Posts: 29
Location: I live in Spain, with the toros, paella and tortilla

View user's profile Send private message

PS/2 Mouse Driver (uses interrupts)
PostPosted: Tue Aug 30, 2011 3:22 pm     Reply with quote

Here is a PS/2 mouse driver I just wrote.
Works great with all of my PS/2 mouses.
Very easy to use, some variables you can access in your main(); store the data the mouse sends.
The variables are:
Code:

unsigned int __ltbtn;         //LEFT BUTTON FLAG
unsigned int __rtbtn;         //RIGHT BUTTON FLAG
unsigned int __mdbtn;         //MIDDLE BUTTON FLAG
unsigned int __xoverflow;      //OVERFLOW IN X MOV
unsigned int __yoverflow;      //OVERFLOW IN Y MOV
unsigned int __xmsign;         //X MOV SIGN (0=positive, 1=negative)
unsigned int __ymsign;         //Y MOV SIGN (0=positive, 1=negative)
unsigned int pkt_s;            //STATUS PACKET
unsigned int pkt_x;            //X MOV PACKET
unsigned int pkt_y;            //Y MOV PACKET


As you probably guess the variables store this:

__ltbtn -> left button state, 1=pressed
__rtbtn -> right button state, 1=pressed
__mdbtn -> middle button state, 1=pressed
__xoverflow -> overflow in X movement register
__yoverflow -> overflow in Y movement register
__xmsign -> X movement sign (0=positive->moving left, 1=negative->moving right)
__ymsign -> Y movement sign (0=positive->moving up, 1=negative->moving down)
pkt_s -> this is the packet the mouse sends first and it contains all the button states, overflows and signs. I splitted them in individual variables for easy use so no need to use this one.
pkt_x -> X movement register
pkt_y -> Y movement register

This last two have to be combined with the __xmsign and __ymsign to detect the direction of the mouse.

You also have to configure the library in order to work with your mouse using this defines, this routine, and doing a small modification of the code, which is all explained below:

Code:
#define MOCLOCK   PIN_B0 //INT_EXT
#define MODATA     PIN_B1

You have to define the pins you want to use to connect the mouse. Make sure the MOCLOCK pin is an interrupt pin, otherwise it will not work.

You also have to modify this lines of the library so that the pin you used for the clock matches the interrupt the library uses:
Code:
#INT_EXT
void resepsionar() {
   output_low(pin_c7);
   switch(rcv_mbits) { [ ... ]


Code:
void moconf(unsigned int reset, remote, sten, delay) {
   ext_int_edge(H_to_L);
   clear_interrupt(INT_EXT);
    enable_interrupts(INT_EXT);
    enable_interrupts(GLOBAL);
[ ... ]

Refer to the datasheet of your MCU to change the #INT_EXT line, clear_interrupts(INT_EXT) and enable_interrupts(INT_EXT) to the ISR of your external interrupt pin.

Finally, you have to call a configuration routine. This should be done before the main loop:

Code:
void moconf(unsigned int reset, remote, sten, delay)


1 on reset means the library will reset the mouse. Remote must always be 1. sten must be always 0 and delay should be between 1 and 3.

Now in your main loop you have to call this to make the mouse send data:
Code:
mouse_write(0xEB, 4);


And thats it. Please note this will not enable the mouse to use scrolling wheel or 4th and 5th buttons. libmo_loop(); may be called in your main loop, but it's not necessary.

Now a small sample program for a 18F4550 (will turn LED at D0 when left clicking, and should be easily adapted to other chips) and the library itself:

Code:

#include "18F4550.h"

#fuses INTRC_IO, NOWDT, NOLVP

#define LED PIN_D0

/***********LIBMO SETTINGS*****************/
#define MOCLOCK      PIN_B0 //INT_EXT
#define MODATA        PIN_B1
#include "libmo.h"
/*****END***LIBMO SETTINGS*****************/

void main(){
moconf(1,1,0,3);

do {
   mouse_write(0xEB, 4);
   
   if(__ltbtn){
      output_high(LED);
   } else {
      output_low(LED);
   }
} while (1);

}

Please note that I wrote this program at the same time I wrote this post, this means that the program is not tested, but should work just fine.


libmo.h (its a H file cause its easier to configure Mplab to compile things in the correct order this way)
Code:
#ifndef _libmo
#define _libmo
#endif

/************VARIABLES**************/
unsigned int libmo_err = 0;      //ERROR CODE
unsigned int startbit_mo;      //STARTBIT
unsigned int scancode_mo;      //SCANCODE
unsigned int __ltbtn;         //LEFT BUTTON FLAG
unsigned int __rtbtn;         //RIGHT BUTTON FLAG
unsigned int __mdbtn;         //MIDDLE BUTTON FLAG
unsigned int __xoverflow;      //OVERFLOW IN X MOV
unsigned int __yoverflow;      //OVERFLOW IN Y MOV
unsigned int __xmsign;         //X MOV SIGN (0=positive, 1=negative)
unsigned int __ymsign;         //Y MOV SIGN (0=positive, 1=negative)
unsigned int pkt_s;            //STATUS PACKET
unsigned int pkt_x;            //X MOV PACKET
unsigned int pkt_y;            //Y MOV PACKET
unsigned int parity_mo;         //PARITY BIT
unsigned int stopbit_mo;      //STOP BIT
unsigned int rcv_mbits = 0;      //RECEIVED BITS COUNT
unsigned int rcv_en = 0;      //ENABLE RECEIVE PACKET FLAG
unsigned int pkt_id;         //PACKET NUMBER
unsigned int last_pkt;         //LAST SENT PACKET

#INT_EXT
void resepsionar() {
   output_low(pin_c7);
   switch(rcv_mbits) {
      case 0: //START BIT
         startbit_mo = input(MODATA);
      break;

      case 1: //DATA 0 (Y OVERFLOW)
         if(pkt_id == 0 && rcv_en)
            __ltbtn = input(MODATA);
         scancode_mo = (scancode_mo >> 1)|(input(MODATA) << 7);
      break;
   
      case 2: //DATA 1 (X OVERFLOW)
         if(pkt_id == 0 && rcv_en)
            __rtbtn = input(MODATA);
         scancode_mo = (scancode_mo >> 1)|(input(MODATA) << 7);
      break;
   
      case 3: //DATA 2 (Y SIGN BIT)
         if(pkt_id == 0 && rcv_en)
            __mdbtn = input(MODATA);
         scancode_mo = (scancode_mo >> 1)|(input(MODATA) << 7);
      break;
   
      case 4: //DATA 3 (X SIGN BIT)
         scancode_mo = (scancode_mo >> 1)|(input(MODATA) << 7);
      break;
   
      case 5: //DATA 4 (ALWAYS 1)
         if(pkt_id == 0 && rcv_en)
            __xmsign = input(MODATA);
         scancode_mo = (scancode_mo >> 1)|(input(MODATA) << 7);
      break;
   
      case 6: //DATA 5 (MID BUTTON)
         if(pkt_id == 0 && rcv_en)
            __ymsign = input(MODATA);
         scancode_mo = (scancode_mo >> 1)|(input(MODATA) << 7);
      break;
   
      case 7: //DATA 6 (RT BUTTON)
         if(pkt_id == 0 && rcv_en)
            __xoverflow = input(MODATA);
         scancode_mo = (scancode_mo >> 1)|(input(MODATA) << 7);
      break;
   
      case 8: //DATA 7 (LT BUTTON)
         if(pkt_id == 0 && rcv_en)
            __yoverflow = input(MODATA);
         scancode_mo = (scancode_mo >> 1)|(input(MODATA) << 7);
      break;
   
      case 9: //ODD PARITY
         parity_mo = input(MODATA);
      break;

      case 10: //STOP BIT
         stopbit_mo = input(MODATA);
      break;
   }
   
   if (++rcv_mbits > 10){            //ADD BITS AND IF ALL BITS
      if(rcv_en) {               //IF GOING TO RECEIVE A PACKET
         pkt_id++;
         switch (pkt_id) {
            case 1:
               pkt_s = scancode_mo;   //FIRST PACKET IS STATUS
            break;
            case 2:
               pkt_x = scancode_mo;   //SECOND IS X MOV
            break;
            case 3:
               pkt_y = scancode_mo;   //THIRD IS Y MOV
               rcv_en = 0;            //RCV FLAG DISABLE PKT DONE
               pkt_id = 0;            //PKT COUNTER RESET
            break;
         }      
      }
      if (scancode_mo == 0xFA && last_pkt == 0xEB && rcv_en != 1) {   //IF SC IS ACK, AND LAST SENT IS 0xEB, AND NOT RECEIVING ANYTHING
         rcv_en = 1;      //ENABLE PACKET RECEIVE
      }
      rcv_mbits = 0;      //RESET RCV BIT COUNT
   }
}


libmo_loop() {
   if(!libmo_err == 0){   //IF THERE IS AN ERROR FLAG SET
      //printf("libmo error: 0x%x \n", libmo_err);
      return libmo_err;   //RETURN WHAT HAPPENED
   } else {
   libmo_err = 0;         //OR MAYBE IF EVERYTHING WAS OK
   return 0;            //WE CAN RESET THE ERROR FLAG :D
   }
}

int mouse_write(unsigned int data, delay) {      //WRITE TO MOUSE. POLLING :(
   unsigned int i;
   unsigned int parity = 1;

   output_high(pin_c7);
   last_pkt = data;

   disable_interrupts(GLOBAL);

   output_low(MOCLOCK);

   delay_us(90);

   output_low(MODATA);

   delay_us(35);

   input(MOCLOCK);

   while (input(MOCLOCK) == 1);
   for (i=0; i < 8; i++) {
      if (data & 0x01) {
         input(MODATA);
      } else {
         output_low(MODATA);
      }
      while (input(MOCLOCK) == 1);
      while (input(MOCLOCK) == 0);

      parity = parity ^ (data & 0x01);
      data = data >> 1;
   }

   if (parity) {
      input(MODATA);
   } else {
      output_low(MODATA);
   }

   while (input(MOCLOCK) == 0);
   while (input(MOCLOCK) == 1);

   input(MODATA);

   delay_us(50);

   while (input(MOCLOCK) == 1);

   clear_interrupt(INT_EXT);
   enable_interrupts(GLOBAL);
   
   delay_ms(delay);

   return 1;
}

void moconf(unsigned int reset, remote, sten, delay) {
   ext_int_edge(H_to_L);
   clear_interrupt(INT_EXT);
    enable_interrupts(INT_EXT);
    enable_interrupts(GLOBAL);

   if(reset){
      mouse_write(0xFF, delay);
   }
   if(remote){
      mouse_write(0xF0, delay);   
   } else {
      mouse_write(0xEA, delay);
   }
   if(sten){
      mouse_write(0xF4, delay);
   }
}
uN_Eof



Joined: 17 May 2010
Posts: 29
Location: I live in Spain, with the toros, paella and tortilla

View user's profile Send private message

PostPosted: Tue Aug 30, 2011 3:36 pm     Reply with quote

By the way soon I'll be posting a PS/2 Keyboard driver and a DualShock emulator, stay tuned.
sonkhadt



Joined: 02 Oct 2011
Posts: 1

View user's profile Send private message Visit poster's website Yahoo Messenger

PostPosted: Sun Oct 02, 2011 9:39 am     Reply with quote

Dear uN_Eof

I tried this code with PIC16F877A but it doesn't work. I referred to the datasheet of your MCU and changed the #INT_EXT line, clear_interrupts(INT_EXT) and enable_interrupts (INT_EXT).
I have some questions
- In these lines:
Quote:

#INT_EXT
void resepsionar() {
output_low(pin_c7);
switch(rcv_mbits) { [ ... ]

What do you use pin_c7 to do ?

- Should we use "time out" while microcontroller gets bytes ?
- Why is type of __ltbtn "unsigned int" while in ext_int you use it as bit type (__rtbtn,__mdbtn,__xoverflow,__yoverflow,startbit_mo ... is same)
Please review your program and help me.
Thanks so much.
uN_Eof



Joined: 17 May 2010
Posts: 29
Location: I live in Spain, with the toros, paella and tortilla

View user's profile Send private message

PostPosted: Mon Oct 24, 2011 2:49 pm     Reply with quote

Hello. I tested it today for a new project and it works for me. I'm using a f4550. Remember you have to use pullups in the data and clock lines, otherwise it wont work.
Assuming your hardware is correct, I don't see why it should not work in another pic device.
As for your questions, pin_c7 was used to know when the pic was taking control of the lines and when no in the logic analyzer. I forgot to remove that line before uploading my code, remove it, nothing will happen. It's not necessary to use a watchdog timer or any timer at all always that the clock of the mouse and the mouse itself are correct. The data types (AFAIK of course) are correct, don't worry about that.

Please post your main program so i can help you better.
CAIFAN



Joined: 21 Nov 2011
Posts: 3

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

Hello
PostPosted: Mon Nov 21, 2011 10:24 pm     Reply with quote

Hi there, I was looking for something like your code, and its great!!!
I couldn't find a ps/2 mouse, so i build the circuit in ISIS, but it doesn't nothing, can your code run in ISIS???

Thanx

Greetings from Mexico!!!!
_________________
Ozz Raw
still_water



Joined: 03 Jul 2012
Posts: 1

View user's profile Send private message Send e-mail

PostPosted: Mon Aug 20, 2012 12:24 pm     Reply with quote

uN_Eof thanks for the code. I've tried this code with a 16f877a and it works perfectly.
Very Happy But a small problem, if __xmsign ==1 the initial value is 255 and it gets reduced from that. Actually I'm trying to run a servo with ps2mouse
so
Code:

if(__xmsign==0)
  xVal += pkt_x;
if(__xmsign==1)
  xVal -= (255-pkt_x);

xVal to servo.

But when the __xmsign is 1 there is a big spike in the numbers randomly. Can anyone help me with this problem ? The random spike value is more than 255 sometimes. Mad
faqrul



Joined: 27 Aug 2012
Posts: 4

View user's profile Send private message

PostPosted: Sat Sep 08, 2012 9:41 am     Reply with quote

hi.. thanks for code.. i new for programming and in study.. actually i was try your code using 18f4550 and usb mouse with usb to ps/2 converter.. but it not working.. can you explain to me the coding so i can alter for it working??

thank you soo much Smile
Phoenixalone



Joined: 27 Jan 2013
Posts: 1

View user's profile Send private message

It didn't work with my PIC18F4431
PostPosted: Tue Jan 29, 2013 9:24 am     Reply with quote

I can not read data from PS2 optical mouse. I used your example code but it's didn't work Crying or Very sad , can you help me?
fkl



Joined: 20 Nov 2010
Posts: 40

View user's profile Send private message

Re: It didn't work with my PIC18F4431
PostPosted: Fri May 10, 2013 7:53 am     Reply with quote

Can help? Don't work. Use pic18f14k50.


Code:
/***********LIBMO SETTINGS*****************/
#define MOCLOCK      PIN_C0 //INT_EXT
#define MODATA        PIN_C1
#include "libmo.h"
/*****END***LIBMO SETTINGS*****************/
fkl



Joined: 20 Nov 2010
Posts: 40

View user's profile Send private message

PS/2 Mouse Driver (uses interrupts) PIC18F4550
PostPosted: Sun May 12, 2013 1:55 am     Reply with quote

pic18f4550 - works.

But when connected via an adapter usb/ps2 usb mouse does not work. How to add the ability to work with a usb&adapter_ps2? If connect a mouse to the computer via an adapter - mouse works as ps2_mouse.

Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group