#include #include #define CENTER_POINT 0x0AC5 void lcd_delay(); // short delay (50000 clocks) void lcd_init(); // sets lcd in 4 bit mode, 2-line mode, with cursor on and set to blink void lcd_cmd(); // use to send commands to lcd void lcd_disp(); // use to display text on lcd void lcd_clear(); // use to clear LCD and return cursor to home position void lcd_row(int row); // use to put the LCD at the desired row void cam_string(); // extracts data from CMUcam2 T strings void cam_value(); // extracts the next value from lineR starting with extractPos void cam_init(); // perform CMUCam2 initialization process void port_init(); // initialize I/O of ports void serial_init(); // initialize serial communication void left_motor(int value); void right_motor(int value); int get_SonarOne(); // use to read value from sonar module int get_SonarTwo(); void config_adcZero(void); void config_adcOne(void); void init_adc( void ); int get_IR(void); void fullRotate0(void); void degreeRotate(int degrees); void fullRotate1(void); void pwm_init(void); void obstacleAvoid(void); int lookFor(void); void lineUpWithWall(void); void forward(void); void stop(void); void right(void); void left(void); void reverse(void); void wallRight(void); void dforward(void); void dright(void); void dleft(void); void followWall(void); void deal(void); /* IMPORTANT! Before using this code make sure your LCD is wired up the same way mine is, or change the code to match the wiring of your own LCD. My LCD is connected to PortC of the At-Mega128 in the following manner: PortC bit 7 : LCD data bit 7 (MSB) PortC bit 6 : LCD data bit 6 PortC bit 5 : LCD data bit 5 PortC bit 4 : LCD data bit 4 (LSB) PortC bit 3 : (not connected) PortC bit 2 : LCD enable pin (clock) PortC bit 1 : LCD R/W (read / write) signal PortC bit 0 : LCD RS (register select) pin Also remember you must connect a potentiometer (variable resistor) to the vcc, gnd, and contrast pins on the LCD. The output of the pot (middle pin) should be connected to the contrast pin. The other two can be on either pin. */ void lcd_delay() // delay for 10000 clock cycles { long int ms_count = 0; while (ms_count < 10000) { ms_count = ms_count + 1; } } void lcd_cmd( unsigned int myData ) { /* READ THIS!!! The & and | functions are the BITWISE AND and BITWISE OR functions respectively. DO NOT confuse these with the && and || functions (which are the LOGICAL AND and LOGICAL OR functions). The logical functions will only return a single 1 or 0 value, thus they do not work in this scenario since we need the 8-bit value passed to this function to be preserved as 8-bits */ unsigned int temp_data = 0; temp_data = ( myData | 0b00000100 ); // these two lines leave the upper nibble as-is, and set temp_data = ( temp_data & 0b11110100 ); // the appropriate control bits in the lower nibble PORTC = temp_data; lcd_delay(); PORTC = (temp_data & 0b11110000); // we have written upper nibble to the LCD temp_data = ( myData << 4 ); // here, we reload myData into our temp. variable and shift the bits // to the left 4 times. This puts the lower nibble into the upper 4 bits temp_data = (temp_data & 0b11110100); // temp_data now contains the original temp_data = (temp_data | 0b00000100); // lower nibble plus high clock signal PORTC = temp_data; // write the data to PortC lcd_delay(); PORTC = (temp_data & 0b11110000); // re-write the data to PortC with the clock signal low (thus creating the falling edge) lcd_delay(); } void lcd_disp(unsigned int disp) { /* This function is identical to the lcd_cmd function with only one exception. This least significant bit of PortC is forced high so the LCD interprets the values written to is as data instead of a command. */ unsigned int temp_data = 0; temp_data = ( disp & 0b11110000 ); temp_data = ( temp_data | 0b00000101 ); PORTC = temp_data; lcd_delay(); PORTC = (temp_data & 0b11110001); lcd_delay(); // upper nibble temp_data = (disp << 4 ); temp_data = ( temp_data & 0b11110000 ); temp_data = ( temp_data | 0b00000101 ); PORTC = temp_data; lcd_delay(); PORTC = (temp_data & 0b11110001); lcd_delay(); // lower nibble } void lcd_init() { lcd_cmd(0x33); // writing 0x33 followed by lcd_cmd(0x32); // 0x32 puts the LCD in 4-bit mode lcd_cmd(0x28); // writing 0x28 puts the LCD in 2-line mode lcd_cmd(0x0F); // writing 0x0F turns the display on, curson on, and puts the cursor in blink mode lcd_cmd(0x01); // writing 0x01 clears the LCD and sets the cursor to the home (top left) position //LCD is on... ready to write } void lcd_string(char *a) { /* This function writes a string to the LCD. LCDs can only print one character at a time so we need to print each letter or number in the string one at a time. This is accomplished by creating a pointer to the beginning of the string (which logically points to the first character). It is important to understand that all strings in C end with the "null" character which is interpreted by the language as a 0. So to print an entire string to the LCD we point to the beginning of the string, print the first letter, then we increment the pointer (thus making it point to the second letter), print that letter, and keep incrementing until we reach the "null" character". This can all be easily done by using a while loop that continuously prints a letter and increments the pointer as long as a 0 is not what the pointer points to. */ while (*a != 0) { lcd_disp((unsigned int) *a); // display the character that our pointer (a) is pointing to a++; // increment a } return; } void lcd_int(int value) { /* This routine will take an integer and display it in the proper order on your LCD. Thanks to Josh Hartman (IMDL Spring 2007) for writing this in lab */ int temp_val; int x = 10000; // since integers only go up to 32768, we only need to worry about // numbers containing at most a ten-thousands place while (value / x == 0) // the purpose of this loop is to find out the largest position (in decimal) { // that our integer contains. As soon as we get a non-zero value, we know x/=10; // how many positions there are int the int and x will be properly initialized to the largest } // power of 10 that will return a non-zero value when our integer is divided by x. while (x >= 1) // this loop is where the printing to the LCD takes place. First, we divide { // our integer by x (properly initialized by the last loop) and store it in temp_val = value / x; // a temporary variable so our original value is preserved. Next we subtract the value -= temp_val * x; // temp. variable times x from our original value. This will "pull" off the most lcd_disp(temp_val+ 0x30); // significant digit from our original integer but leave all the re'ing digits alone. // After this, we add a hex 30 to our temp. variable because ASCII values for integers x /= 10; // 0 through 9 correspond to hex numbers 30 through 39. We then send this value to the } // LCD (which understands ASCII). Finally, we divide x by 10 and repeat the process // until we get a zero value (note: since our value is an integer, any decimal value return; // less than 1 will be truncated to a 0) } void lcd_clear() // this function clears the LCD and sets the cursor to the home (upper left) position { lcd_cmd(0x01); return; } void lcd_row(int row) // this function moves the cursor to the beginning of the specified row without changing { // any of the current text on the LCD. switch(row) { case 0: lcd_cmd(0x02); case 1: lcd_cmd(0xC0); } return; } int lineTPos = 0; char *lineT; // used for receiving int lineRPos = 0; int lineRChoose = 0; char lineR[30]; char linePrint[30] = "Nothing Here "; // used for extracting cam data int valueTemp, ballX, ballY, ballPix, ballCon; int extractPos; int dealTimes=4; int main(void) { long sonarOneVal = 1; long sonarTwoVal=1; long i=0; long camk; int temp; int y=0; DDRA = 0x03;// sonar is connected with trigger on PortA.7 and echo on PortA.0 DDRC = 0xFF; // set all pins on portC to output (could also use DDRC = 0b11111111) lcd_init(); // set lcd in 4 bit mode, 2-line mode, with cursor on and set to blink port_init(); // set port directions serial_init(); // initializes and activates interrupt routines cam_init(); // Initializes camera lcd_string("Your LCD is working."); // if your LCD is wired up correctly, you will see this text // on it when you power up your Micro-controller board. lcd_row(1); lcd_string("Good luck! :)"); pwm_init(); OCR1C = 1425; OCR1B = 1500; OCR1A = 900; forward(); int t=0; while(t<500){ obstacleAvoid(); if(ballX<55){ dright(); } else if(ballX>110){ dleft(); } else { dforward(); } //lcd_clear(); // lcd_string("Ball X: "); //lcd_int(ballX); //lcd_row(1); //lcd_string("Ball Y: "); //lcd_int(ballY); //for (camk = 0; camk < 3; camk++) { // lcd_delay(); //delay to read LCD (humans reading) //} t++; } OCR1A = 1425; OCR1B = 1350; stop(); lcd_clear(); lcd_string("YO BITCHES"); forward(); while(lookForWall()) { } lineUpWithWall(); forward(); lcd_clear(); lcd_string("1"); while(lookForWall()){ followWall(); deal(); } dealTimes=4; lineUpWithWall(); forward(); lcd_clear(); lcd_string("2"); while(lookForWall()){ followWall(); deal(); } dealTimes=4; lineUpWithWall(); forward(); lcd_clear(); lcd_string("3"); while(lookForWall()){ followWall(); deal(); } dealTimes=4; lineUpWithWall(); forward(); lcd_clear(); lcd_string("4"); while(lookForWall()){ followWall(); deal(); } dealTimes=4; lineUpWithWall(); forward(); lcd_clear(); lcd_string("5"); while(lookForWall()){ followWall(); deal(); } dealTimes=4; lineUpWithWall(); forward(); lcd_clear(); lcd_string("6"); while(lookForWall()){ followWall(); deal(); } dealTimes=4; lineUpWithWall(); forward(); lcd_clear(); lcd_string("7"); while(lookForWall()){ followWall(); deal(); } dealTimes=4; lineUpWithWall(); forward(); lcd_clear(); lcd_string("8"); while(lookForWall()){ followWall(); deal(); } stop(); } void obstacleAvoid(){ int i = 0; long sonarOneVal=get_SonarOne(); long sonarTwoVal=get_SonarTwo(); //lcd_clear(); //lcd_int(sonarOneVal); //lcd_string("+"); //lcd_int(sonarTwoVal); //for( i=0; i<25; i++){ //lcd_delay(); //} if(sonarOneVal<900 && sonarTwoVal<900 && PORTB!=0b11101010){ reverse(); lcd_clear(); lcd_string("Reverse"); } if(sonarOneVal<1400 && sonarTwoVal>1400 && PORTB!=0b11100110){ left(); lcd_clear(); lcd_string("Turn Left"); } if(sonarOneVal>1400 && sonarTwoVal<1400 && PORTB!=0b11101001){ right(); lcd_clear(); lcd_string("Turn Right"); } if(sonarOneVal>1400 && sonarTwoVal>1400 && PORTB!=0b11100101){ forward(); } } int lookForWall(){ int i = 0; long sonarOneVal=get_SonarOne(); long sonarTwoVal=get_SonarTwo(); //lcd_clear(); //lcd_int(sonarOneVal); //lcd_string("+"); //lcd_int(sonarTwoVal); // for( i=0; i<25; i++){ // lcd_delay(); // } if(sonarOneVal<1100 || sonarTwoVal<1100){ //lcd_clear(); //lcd_string("Found a fucking wall"); return 0; } return 1; } int get_SonarOne() { int i = 0; int n = 0; //send trigger PORTA = (PINA & 0xFE); // these two lines create a rising edge PORTA = (PINA | 0x01);// on PortA pin 0 //lcd_clear(); //lcd_string("rising edge done"); while (n < 10000) { n++;//waste enough clock cycles for at least 10us to pass } PORTA = (PINA & 0xFE); // force PortA pin 7 low to create a falling edge // this sends out the trigger while (!(PINA & 0x02)) { // do nothing as long as echo line is low } n = 0; //re-use our dummy variable for counting while (PINA & 0x02) { n += 1; // add 1 to n as long as PortA pin 0 is high } //when we get here, the falling edge has occured return n; } int get_SonarTwo() { int i = 0; int n = 0; PORTA = (PINA & 0xFB); // these two lines create a rising edge PORTA = (PINA | 0x04); // on PortA pin 2 //lcd_clear(); //lcd_string("rising edge done"); while (n < 10000) { //waste enough clock cycles for at least 10us to pass n++; } PORTA = (PINA & 0xFB); // force PortA pin 2 low to create a falling edge // this sends out the trigger while (!(PINA & 0x08)) { // do nothing as long as echo line is low } n = 0; //re-use our dummy variable for counting while (PINA & 0x08) { n += 1; // add 1 to n as long as PortA pin 0 is high } //when we get here, the falling edge has occured return n; } int get_SonarThree() { int i = 0; int n = 0; PORTA = (PINA & 0xEF); // these two lines create a rising edge PORTA = (PINA | 0x10); // on PortA pin 2 //lcd_clear(); //lcd_string("rising edge done"); while (n < 10000) { //waste enough clock cycles for at least 10us to pass n++; } PORTA = (PINA & 0xEF); // force PortA pin 2 low to create a falling edge // this sends out the trigger while (!(PINA & 0x20)) { // do nothing as long as echo line is low } n = 0; //re-use our dummy variable for counting while (PINA & 0x20) { n += 1; // add 1 to n as long as PortA pin 0 is high } //when we get here, the falling edge has occured return n; } void config_adcZero() { DDRF = 0b00000000; // set port F to all input // Note: when JTAGEN fuse is set, F4 - F7 don't work PORTF = 0x00; // make sure pull up resistor is not enabled ADMUX = 0b01000000; // 5V reference, select channel0 (pin F0) ADCSRA |= 0b10100111; // turn on ADC, don't start conversions // free funning // divide clock by 128 } void config_adcOne() { DDRF = 0b00000000; // set port F to all input // Note: when JTAGEN fuse is set, F4 - F7 don't work PORTF = 0x00; // make sure pull up resistor is not enabled ADMUX = 0b01000001; // 5V reference, select channel0 (pin F0) ADCSRA |= 0b10100111; // turn on ADC, don't start conversions // free funning // divide clock by 128 } void init_adc( ) { ADCSRA |= 0b01000000; // start free running conversions } int get_IR(){ int analogLow=0; int analogHigh=0; int i=0; while(i<1200){ i++; } analogLow = ADCL&0b11110000; analogHigh = ADCH; return analogLow; } void pwm_init() { TCCR3A = 0b10100000; TCCR3B = 0b00010010; TCCR1A = 0b10101000; TCCR1B = 0b00010010; ICR1 = 0x8F9C; ICR3 = 0x8F9C; DDRF = 0xFF; PORTB=0b11100101; //OCR1A=1366; //OCR1B= 1500 //OCR1C= 1366; } void lineUpWithWall() { int i=0; int sonarTwoVal; int sonarThreeVal; right(); //for (i=0; i<120; i++){ //lcd_delay(); //} int irZeroVal=0; int irOneVal=1000; do { do{ config_adcZero(); init_adc(); irZeroVal=get_IR(); config_adcOne(); init_adc(); irOneVal=get_IR(); sonarThreeVal = get_SonarThree(); sonarTwoVal = get_SonarTwo(); //lcd_clear(); //lcd_int(irOneVal); //lcd_string("+"); //lcd_int(irZeroVal); //lcd_string("="); //lcd_int(sonarThreeVal); //for(i=0; i<20;i++){ //lcd_delay(); // } wallRight(); }while (sonarTwoVal<2000); } while(irZeroVal>irOneVal); } void followWall(){ int irZeroVal=0; int irOneVal=1000; int sonarThreeVal; int i=0; int ik=0; config_adcZero(); init_adc(); irZeroVal=get_IR(); config_adcOne(); init_adc(); irOneVal=get_IR(); ik=irOneVal-irZeroVal; sonarThreeVal = get_SonarThree(); //lcd_clear(); //lcd_int(irOneVal); //lcd_string("+"); //lcd_int(irZeroVal); //lcd_int(ik); //for(i=0; i<20;i++){ // lcd_delay(); // } //if(sonarThreeVal<465){ // dright(); // } if (irOneVal>140) { //lcd_clear(); //lcd_string("dright"); dright(); } else if (irZeroVal<100){ //lcd_clear(); //lcd_string("dright"); dright(); } else if (irOneVal<100){ //lcd_clear(); //lcd_string("dleft"); dleft(); } else if (irZeroVal>140 && sonarThreeVal>465){ //lcd_clear(); //lcd_string("dleft"); dleft(); } else if (irZeroVal>100 && irZeroVal<140 && irOneVal>100 && irZeroVal<140) { dforward(); //lcd_clear(); //lcd_string("dforward"); } } void serial_init() { UCSR0B = 0b00000000; // don't enable anything UCSR0C = 0b00000110; // asynch, no parity, 1 stop bit, 8 bit characters UBRR0L = 23; // initialize transfer speed for 38400 baud sei(); // enable all interupts } void port_init() { DDRC = 0xFF; // set portC to output (could also use DDRC = 0b11111111) DDRB = 0xFF; // set portB to output DDRE = 0xFF; // set portE to output DDRA = 0b00010101; // set portA bits 2-0 to input DDRF = 0b00000000; // set port F to all input // DDRA = 0b11111000; // set portA bits 2-0 to input } SIGNAL(SIG_UART0_DATA) { if (lineTPos < 15) { UDR0 = lineT[lineTPos]; if (lineT[lineTPos] == 13 || lineTPos == 14) { // if character is carriage return UCSR0B &= 0b11010111; // then turn off interrupt for transmission } lineTPos++; } } SIGNAL(SIG_UART0_RECV) { if (lineRPos < 30) { lineR[lineRPos] = UDR0; if (lineR[lineRPos] == 13 || lineRPos == 29) { // if character is carriage return if (lineR[0] == 'T') { cam_string(); // lineR[lineRPos] = 0; // int i; // for (i=0;i<30;i++) { // linePrint[i] = lineR[i]; // use for immediate printing of raw data // } // lcd_clear(); // lcd_string(linePrint); } lineRPos = 0; } else lineRPos++; } } void cam_string() { extractPos = 0; cam_value(); ballX = valueTemp; cam_value(); ballY = valueTemp; cam_value(); ballPix = valueTemp; cam_value(); ballCon = valueTemp; } void cam_value() { char tempC; int tempI = 0; long tenPower = 1; int pos = 0; // find the next number tempC = lineR[extractPos]; while (!(tempC>47 && tempC<58) && extractPos<30) { // while tempC is not a number and is in bounds extractPos ++; // then increment extractPos tempC = lineR[extractPos]; // and reset tempC } // find how many digits it is (tempI) while ((tempC>47 && tempC<58) && (extractPos+tempI)<=30) { // while tempC is a number and is in bounds tempI ++; // then increment tempI tenPower *= 10; // increment tenPower by a power of ten tempC = lineR[extractPos + tempI]; // and reset tempC } // extract this number to valueTemp valueTemp = 0; while (pos < tempI) { // for as many digits as are in the number tenPower /= 10; // reduce tenPower by a factor of ten tempC = lineR[extractPos + pos]; // reset tempC tempC -= 48; // convert tempC from ASCII to decimal valueTemp += (tenPower * tempC); // place the value in tempC as the correct digit in valueTemp pos ++; } extractPos += tempI; } void cam_init() { int i, j; lcd_clear(); lcd_string("Setting up"); lcd_row(1); lcd_string(" CMUCam2"); //for (i = 0; i < 1000; i++) { lcd_delay(); //delay to read LCD (humans reading) //} if (1) { char newLine[15] = "OM 0 195 "; newLine[8] = 13; // insert carriage return lineT = newLine; lineTPos = 0; UCSR0B |= 0b00101000; // turn on transmission // for (i = 0; i < 500; i++) { lcd_delay(); //delay to read LCD (humans reading) //} } if (1) { char newLine[15] = "HR 1 "; newLine[4] = 13; // insert carriage return lineT = newLine; lineTPos = 0; UCSR0B |= 0b00101000; // turn on transmission //for (i = 0; i < 500; i++) { lcd_delay(); //delay to read LCD (humans reading) //} } if (1) { char newLine[15] = "CR 18 44 "; newLine[8] = 13; // insert carriage return lineT = newLine; lineTPos = 0; UCSR0B |= 0b00101000; // turn on transmission } lcd_clear(); lcd_string("Adjusting white"); for (j = 5; j > 0; j--) { lcd_row(1); lcd_string(" balance..."); lcd_int(j); //for (i = 0; i < 1000; i++) { lcd_delay(); //delay to read LCD (humans reading) //} } if (1) { char newLine[15] = "CR 18 40 "; newLine[8] = 13; // insert carriage return lineT = newLine; lineTPos = 0; UCSR0B |= 0b00101000; // turn on transmission } lcd_row(1); lcd_string(" balance...Done"); // for (i = 0; i < 1000; i++) { lcd_delay(); //delay to read LCD (humans reading) //} if (1) { char newLine[15] = "PS 4 "; newLine[4] = 13; // insert carriage return lineT = newLine; lineTPos = 0; UCSR0B |= 0b00101000; // turn on transmission } lcd_clear(); lcd_string("Acquiring ball"); for (j = 5; j > 0; j--) { lcd_row(1); lcd_string(" color in "); lcd_int(j); // for (i = 0; i < 1000; i++) { lcd_delay(); //delay to read LCD (humans reading) // } } if (1) { char newLine[15] = "TW "; newLine[2] = 13; // insert carriage return lineT = newLine; lineTPos = 0; UCSR0B |= 0b00101000; // turn on transmission } lcd_row(1); lcd_string(" color done"); // for (i = 0; i < 1000; i++) { lcd_delay(); //delay to read LCD (humans reading) // } UCSR0B |= 0b10010000; // turn on recieve } void deal(){ int z=0; OCR1C = 1500; for(z=0; z<60; z++){ lcd_delay(); } } void forward(){ stop(); PORTB=0b11100101; OCR3A = 0x506C; OCR3B = 0x47CE; } void stop(){ int j = 0; PORTB=0b11100000; //lcd_clear(); //lcd_string("STOP!"); lcd_clear(); lcd_string("DONE stopping"); } void right(){ stop(); PORTB=0b11101001; OCR3A = 0x47CE; OCR3B = 0x47CE; } void left(){ stop(); PORTB=0b11100110; OCR3A = 0x47CE; OCR3B = 0x47CE; } void reverse(){ stop(); PORTB=0b11101010; OCR3A = 0x47CE; OCR3B = 0x506C; } void wallRight(){ PORTB=0b11101001; OCR3A = 0x47CE; OCR3B = 0x47CE; } void dforward(){ OCR3A=0x506C; OCR3B=0x47CE; } void dright(){ OCR3A = 0x506C; OCR3B = 0x0956; } void dleft(){ OCR3A = 0x0956; OCR3B = 0x47CE; }