/******************************************************************** * ECE 476 Final Project * Authors: Ming Qiu (mq23) and Bobbie Chern (bgc5) * Lab Section: I - Monday (4:30-7) * Purpose: Create a RC Car that respond to hand movements and * a regular P/S2 mouse. * * Note: We got our PS/2 mouse interaction code from Steven Keiper and * Ragavan Mahedevan Paint Program with Mouse Control. They cited that it * was originally developed for a Minesweeper Program by Chee Ming, Chaw * and Elaine Siu for 476 in 2003 * * They developed the following functions in this source file: * mouse_send * mouse_read * poll_mouse * reset_mouse * ********************************************************************/ // Library Files #include #include #include // definitions #define begin { #define end } #define t1 10 // poll buttons #define t2 100 // poll accelerometer outputs #define t3 200 // poll mouse outputs #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 register unsigned char data @4; // assembly macro for mouse #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 // function declarations void task1(void); // button detection of record and playback function void task2(void); // motion sensing with accelerometer void task3(void); // motion sensing with mouse void task4(void); // switch interface (mouse -> accel or accel -> mouse) void update(void); // update car position, flash led if recording, and record void accel(void); // get position through accelerometer void play(void); // play recorded driving instruction void decode(char); // decode recorded values 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 initMouse(void); // init board for mouse interface void initAccel(void); // init board for accelerometer interface void initialize(void); // all the usual mcu stuff // Variable declaration int time1, time2, time3, time; // all time variable (time1-3: polling, time: record/playback) char Horz, Vert; // Horizontal and verticle reading from adc (accelerometer) char vcond, hcond, ht_cond, vt_cond, cond; // condition/position variable (t stands for temp.) unsigned char led; // turns on the led in the opto isolator // Array for recording/playback char positions[40]; // recorded position (40 position in all) int times[40]; // recorded time char count; // current recorded array index char x, y; // recorded directions // Flags unsigned char change; // has direction been changed unsigned char lock; // lock out the user during playback unsigned char recorded; // are there anything recorded unsigned char mode; // mode = 1 for mouse 0 for accel unsigned char record; // recording? unsigned char playflag; // play? unsigned char adc; // switch between input pins // Mouse vars unsigned char mouse_x, mouse_y, mouse_status; // mouse x, y movement and status int posx; // x position (mouse) - keep track of horz position //********************************************************** //timer 0 overflow ISR interrupt [TIM0_COMP] void timer0_overflow(void) begin //Decrement the task times if they are not already zero if (time1>0) --time1; if (time2>0) --time2; if (time3>0) --time3; // increment time when recording and decrement when playback if (record == 1) time++; if (playflag == 1 && time > 0) --time; end /**********************************************************/ //Main void main(void) begin // init board initialize(); // default to mouse interface unless user press button if ((~PINB & 0x08) != 0) {initAccel(); mode = 0; } else { initMouse(); mode = 1; } while ((~PINB & 0b00100000) != 0) {} // turn on on/off led - indicates when board is on or off PORTD = 0x00; // run each task if possible while (1) begin if (time1 == 0 && !lock) task1(); if (time2 == 0 && !lock && mode == 0) task2(); if (time3 == 0 && !lock && mode == 1) task3(); if (!lock) task4(); end end //********************************************************** // 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) begin 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) begin 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++; end #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. end //********************************************************** // This function read a byte of data from the mouse and return the byte unsigned char mouse_read(void) begin 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) begin while(CLK_IN==HIGH) {} // wait for falling edge of CLK t[i]=DATA_IN; // store each bit i++; while(CLK_IN==LOW) {} end 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; end //******************************************* // This routine poll the mouse's status and movement data. void poll_mouse(void) begin 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 end //********************************************** // 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) begin 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); end //********************************************************** //task1 - button detections //Button1 = record/stop record //Button2 = playback/stop playback void task1(void) begin time1 = t1; // record instructions for car if (count == 40) record = 0; // if over mem limit stop recording if ((~PINB & 0x01) != 0) { // button 1 pressed if (record == 0) { record = 1; count = 0; } // turn record on if not on else { // turn record off PORTD = 0x00; record = 0; if (count != 0) times[count] = time; time = 0; } while ((~PINB & 0x01) != 0) {} // pause until user release the button } if ((~PINB & 0x02) != 0 && recorded == 1 && record == 0) { // button 2 pressed - turn on play playflag = 1; play(); } end //********************************************************** //task2 - get position from adc //Poll the Pin 3 and 7 for horz and vert position. Two conversion is required for each //due to switching of pins and the resulting corruption to the conversion. Delay is also //added to reduce corruption from one conversion to another. void task2(void) begin time2 = t2; change = 0; // reset flags and run accel LR ADMUX = 0b01100111; // switch pin to A7 adc = 0; // get horz accel(); // junk conversion - remove previous data from reg delay_ms(10); // delay accel(); // get adc conversion and then the resulting horz pos if (ht_cond != hcond) { // if different from previous position change it if (hcond == 1) { led = led | 0b00100000; led = led & 0b11100000; } //right else if (hcond == 2) { led = led & 0b11000000; } //middle else { led = led | 0b00010000; led = led & 0b11010000; } //left ht_cond = hcond; // update change = 1; // set change flag } while (ADCSR.6 != 0) {} // reset flags and run accel BF ADMUX = 0b01100010; // switch pin to A3 adc = 1; // get vert accel(); // junk conversion - remove previous data from reg delay_ms(10); // delay accel(); // get adc conversion and then the resulting vert pos if (vt_cond != vcond) { // if different from previous position change it if (vcond == 1) { led = led | 0b10000000; led = led & 0b10110000; } //back else if (vcond == 2) { led = led & 0b00110000; } //stop else { led = led | 0b01000000; led = led & 0b01110000; } //forward vt_cond = vcond; change = 1; } // update car and record if necessary update(); end //********************************************************** //task3 - get position from mouse //Polls the mouse for its position and status and update car accordingly. void task3(void) begin time3=t3; change = 0; poll_mouse(); // Poll mouse // left click = forward if ((mouse_status & 0b00000001) != 0 && vcond != 3) { led = led | 0b01000000; led = led & 0b01110000; vcond = 3; change = 1; } // right click = backward else if ((mouse_status & 0b00000010) != 0 && vcond != 1) { led = led | 0b10000000; led = led & 0b10110000; vcond = 1; change = 1; } // neither means don't move else if (vcond != 2 && (mouse_status & 0b00000001) == 0 && (mouse_status & 0b00000010) == 0) { led = led & 0b00110000; vcond = 2; change = 1; } // calculate horizontal position according to its sign and value if (mouse_x != 0) { // update relative position var posx if ((mouse_status & 0b00010000)!=0) { posx=posx-((256-mouse_x)>>1); } else { posx = posx + (mouse_x>>1); } // max value for posx - so no wrap around occurs if (posx > 256) posx = 256; if (posx < 0) posx = 0; // right if (posx < 80 && hcond != 3) { hcond = 3; led = led | 0b00010000; led = led & 0b11010000; change = 1; } // left else if (posx > 160 && hcond != 1) { hcond = 1; led = led | 0b00100000; led = led & 0b11100000; change = 1; } // middle else if (hcond != 2 && posx > 95 && posx < 150) { hcond = 2; led = led & 0b11000000; change = 1; } } // update car and record if necessary update(); delay_ms(150); end //********************************************************** //task4 - switch interface //Button 3 pushed then switch enterface void task4(void) begin if ((~PINB & 0x08) != 0) { // if button 3 pushed if (mode == 1) { // if currently in mouse mode switch to accel initAccel(); mode = 0; } else { // else switch to mouse initMouse(); mode = 1; } } while ((~PINB & 0x08) != 0) { } // pause until user release button end //********************************************************** //update - update car position and record if necessary void update(void) begin // update car position by sending on/off signal to opto isolator if (change) PORTC = led; // blink led to indicate recording if (record) PORTD = ~PIND & 0b00100000; // Record /* program code: hcond vcond position 1 1 left & back 1 2 left & stop 1 3 left & forward 2 1 stop & back 2 2 stop & stop 2 3 stop & forward 3 1 right & back 3 2 right & stop 3 3 right & forward */ if (record == 1 && change == 1) { // record position and time positions[count] = 10*hcond + vcond; if (count != 0) times[count-1] = time; // increment flag and counter time = 0; count++; recorded = 1; } end //********************************************************** //accel - get position from accelerometer void accel(void) begin // read pin 3 or 7 - refer to task2 if (adc == 0) { // read horz Horz = ADCH; ADCSR.6 = 1; Vert = 0; } else { // read vert Vert = ADCH; ADCSR.6 = 1; Horz = 0; } // detect changes - threshold determined through experiments // - set condtions see above for pos coding // right if (Horz < 105 && Vert == 0) { hcond = 1; cond = 0; } // stop if (Horz >= 105 && Horz <= 150 && Vert == 0) { hcond = 2; cond = 1; } // left if (Horz > 150 && Vert == 0) { hcond = 3; cond = 2; } // back if (Vert < 113 && Horz == 0) { vcond = 1; cond = 3; } // stop if (Vert >= 113 && Vert <= 155 && Horz == 0) { vcond = 2; cond = 4; } // forward if (Vert > 155 && Horz == 0) { vcond = 3; cond = 5; } end //********************************************************** //play - play pre-programmed instructions //Play can be interrupted by the same button void play(void) begin unsigned char i; // lock out all other functions lock = 1; // pause until user releases button while ((~PINB & 0x02) != 0) {} // led on for play PORTD = ~PIND & 0b00100000; // proceed to play all recorded values for (i=0; i