| 
	
	|  |  |  
	
		| 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
 
 
			    
 
 | 
			
				| PS/2 Mouse Driver (uses interrupts) |  
				|  Posted: Tue Aug 30, 2011 3:22 pm |   |  
				| 
 |  
				| 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
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Aug 30, 2011 3:36 pm |   |  
				| 
 |  
				| 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
 
 
 
			        
 
 | 
			
				|  |  
				|  Posted: Sun Oct 02, 2011 9:39 am |   |  
				| 
 |  
				| 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
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Oct 24, 2011 2:49 pm |   |  
				| 
 |  
				| 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
 
 
 
			          
 
 | 
			
				| Hello |  
				|  Posted: Mon Nov 21, 2011 10:24 pm |   |  
				| 
 |  
				| 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
 
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Mon Aug 20, 2012 12:24 pm |   |  
				| 
 |  
				| uN_Eof thanks for the code. I've tried this code with a 16f877a and it works perfectly. 
  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.
  |  |  
		|  |  
		| faqrul 
 
 
 Joined: 27 Aug 2012
 Posts: 4
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sat Sep 08, 2012 9:41 am |   |  
				| 
 |  
				| 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
  |  |  
		|  |  
		| Phoenixalone 
 
 
 Joined: 27 Jan 2013
 Posts: 1
 
 
 
			    
 
 | 
			
				| It didn't work with my PIC18F4431 |  
				|  Posted: Tue Jan 29, 2013 9:24 am |   |  
				| 
 |  
				| I can not read data from PS2 optical mouse. I used your example code but it's didn't work  , can you help me? |  |  
		|  |  
		| fkl 
 
 
 Joined: 20 Nov 2010
 Posts: 44
 
 
 
			    
 
 | 
			
				| Re: It didn't work with my PIC18F4431 |  
				|  Posted: Fri May 10, 2013 7:53 am |   |  
				| 
 |  
				| 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: 44
 
 
 
			    
 
 | 
			
				| PS/2 Mouse Driver (uses interrupts) PIC18F4550 |  
				|  Posted: Sun May 12, 2013 1:55 am |   |  
				| 
 |  
				| 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.
 
 
  |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |