//************************************************* // // Mouse Code // ECE476 SP 2005 // Arthur Zhang, Yewen Ying // Adapted from // Steven Keiper and Ragavan Mahedevan // Paint Program with Mouse Control // // //************************************************* #include #include // sprintf #include // delay_ms #include #include //timeout value #define t3 200 // for sampling mouse #define DATA_IN PINA.0 //data line from mouse #define CLK_IN PINA.1 //clock line from mouse #define DATA_OUT PORTA.0 //data line from mouse #define LOW 0 #define HIGH 1 #define CURSOR_X_MAX 248 #define CURSOR_X_MIN 0 #define CURSOR_Y_MAX 174 #define CURSOR_Y_MIN 22 #define lineTime 1018 register unsigned char data @4; // Alphanumeric LCD Module functions #asm .equ __lcd_port=0x15 ; #endasm #include #define LCD PORTD #asm .equ PORTA=0x1b .equ DDRA=0x1a .MACRO DATALOW sbi DDRA,0 ;DDRA.0=1 cbi PORTA,0 ;PORTA.0=0 .ENDM .MACRO RELDATA cbi DDRA,0 ;DDRA.0=0 sbi PORTA,0 ;PORTA.0=1 .ENDM .MACRO CLKLOW sbi DDRA,1 ;DDRA.1=1 cbi PORTA,1 ;PORTA.1=0 .ENDM .MACRO RELCLK cbi DDRA,1 ;DDRA.1=0 sbi PORTA,1 ;PORTA.1=1 .ENDM #endasm void mouse_send(char data); // Send 1 byte of data to mouse. unsigned char mouse_read(void); // Read 1 byte of data from mouse void initialize(void); //all the usual mcu stuff unsigned int time3; unsigned char mouse_x,mouse_y,mouse_status; unsigned char sendX, sendY, count; int cursor_x, cursor_y; //current cursor position unsigned char last_cursor_x,last_cursor_y; unsigned char button, dummy; unsigned char lcdString[16]; //string to put to LCD //********************************************************** interrupt [TIM1_COMPA] void t1_cmpA(void) { //Decrement the time if not already zero if (time3>0) --time3; } //********************************************************** // Send a byte of data to mouse. It consist of 1 start bit, 8 data bits, 1 parity bit, 1 stop bit. // After the mouse recieved the data correctly, the mouse will send back an ACK bit. // "data" is the data to be sent. parity bit is odd parity of the 8 bits data. // Data is read by mouse at rising edge of CLK. void mouse_send(char data) { unsigned char Bit,parity,i; #asm("RELDATA"); #asm("RELCLK"); delay_us(300); #asm("CLKLOW"); //Pull CLK Low delay_us(300); // need to wait for at least 100us #asm("DATALOW"); // Pull DATA Low when holding CLK Low delay_us(100); #asm("RELCLK"); //Release CLK and continue to hold Data Low. This is also the Start bit. delay_us(40); while(CLK_IN!=LOW) { } // wait for CLK to go low i=0; Bit=0b00000001; parity=1; // odd parity = 1 ^ bit0 ^ bit1 ^ ... ^ bit7 while(i<=8) { if(i==8) // If i=8 send parity bit otherwise, send the next bit of data. { if(parity) // DATA_OUT=(i==8? parity : (data & Bit) ); { #asm("RELDATA"); } else { #asm("DATALOW"); } } else { if(data & Bit) { #asm("RELDATA"); } else { #asm("DATALOW"); } } while(CLK_IN!=HIGH) {} // wait for CLK to go high. mouse read data at rising edge. while(CLK_IN!=LOW) {} // wait for CLK to go low. parity=parity ^ DATA_OUT; // update parity bit. Bit=Bit<<1; // Prepare mask i++; } #asm("RELDATA"); // Release Data line. This is the stop bit. delay_us(50); // give time for transient to settle. while(DATA_IN!=LOW) {} // wait for Data line to go low while(CLK_IN!=LOW) {} // wait for CLK to go low. Start of ACK from mouse. while(DATA_IN==LOW || CLK_IN==LOW) {} // End of ACK from mouse. #asm("CLKLOW"); // Inhibit the mouse from transmitting data. } //********************************************************** // This function read a byte of data from the mouse and return the byte unsigned char mouse_read(void) { unsigned char i,t[10]; #asm("RELCLK"); //release the CLK #asm("RELDATA"); //release DATA line. delay_us(200); // wait for at least 100us while(CLK_IN==HIGH) {} // wait for falling edge. we read data at falling edge of CLK i=0; delay_us(5); while(CLK_IN==LOW) {} // wait for CLK to go high. while(i<=8) { while(CLK_IN==HIGH) {} // wait for falling edge of CLK t[i]=DATA_IN; // store each bit i++; while(CLK_IN==LOW) {} } while(CLK_IN==LOW) {} data=128*t[7]+64*t[6]+32*t[5]+16*t[4]+8*t[3]+4*t[2]+2*t[1]+t[0]; //combine the collected bits into a byte #asm("CLKLOW"); //pull CLK low to prevent mouse from sending data until being asked return data; } //****************************************** //Update the cursor's variables with new location void update_cursor(void) { last_cursor_x = cursor_x; last_cursor_y = cursor_y; if (mouse_y!=0) //calculate vertical position according to its sign and value if ((mouse_status & 0b00100000)!=0) { cursor_y=cursor_y+(256-mouse_y); } else { cursor_y=cursor_y-(mouse_y); } if (mouse_x!=0) //calculate horizontal position according to its sign and value if ((mouse_status & 0b00010000)!=0) { cursor_x=cursor_x-(256-mouse_x); } else { cursor_x=cursor_x+(mouse_x); } if (cursor_x>CURSOR_X_MAX) cursor_x=CURSOR_X_MAX; // limit cursor to within the screen if (cursor_xCURSOR_Y_MAX) cursor_y=CURSOR_Y_MAX; if (cursor_y>1); //reduce sensitivity and get ready to send sendY=(unsigned char)(cursor_y>>1); button=mouse_status & 0b00000111; //button presses } //******************************************* // This routine poll the mouse's status and movement data. void poll_mouse(void) { mouse_send(0xeb); //Request data from mouse mouse_read(); //Read the acknowledge byte mouse_status=mouse_read(); //Read mouse status mouse_x=mouse_read(); //Read mouse horizontal movement mouse_y=mouse_read(); //Read mouse vertical movement } //********************************************** // This function is called to reset the mouse and put it into remote mode. // In remote mode, mouse only send data upon request from the microcontroller. // This function is called when manual reset of the mouse is required. This is for // overcoming interference problem from some unknown EM field. void reset_mouse(void) { mouse_send(0xff); // reset mouse mouse_read(); // read mouse acknowledge (0xFA) mouse_read(); // read some blank bytes. mouse_read(); mouse_send(0xf0); // Set mouse to remote mode. mouse_read(); // read mouse acknowledge (0xFA) delay_ms(100); } //Main void main(void) { initialize(); /*send over one byte to sync up the two MCU's if you don't send this over, its possible for the MCU's to be one byte off and may have shaky behavior. After you include this, to sync up the two mcu's reset the slave mcu first, then reset the master and everything is fine */ SPDR=0b10000001; while(!(SPSR&0b10000000)); dummy=SPDR; //main task scheduler loop while(1) { poll_mouse(); // Poll mouse update_cursor(); //get ready to send x position SPDR=sendX; while(!(SPSR&0b10000000)); //check if x position sent dummy=SPDR; //clear the SPIF flag //get ready to send y position SPDR=sendY; while(!(SPSR&0b10000000)); //check if y position sent dummy=SPDR; //clear the SPIF flag //get ready to send button SPDR=button; while(!(SPSR&0b10000000)); //check if button sent dummy=SPDR; //clear the SPIF flag } //end main } //********************************************************** //Initialize void initialize(void) { DDRA = 0b11111100; DDRA.0=1; PORTA.0=1; delay_ms(500); DDRA.0=0; DDRA.1=1; PORTA.1=1; delay_ms(500); DDRA.1=0; DDRB=0b01000000; //miso output all else input //no interrupt, spi enable, slave, f/4 SPCR=0x45; DDRD = 0xFF; PORTD.7 = 1; DDRA=0xFF; PORTA=0xFF; button=0; // init mouse variables cursor_x=4; cursor_y=4; sendX=(unsigned char)(cursor_x>>1); sendY=(unsigned char)(cursor_y>>1); #asm("RELCLK"); #asm("RELDATA"); count=0; //init mouse state reset_mouse(); #asm("sei") }