|
|
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
|