/* Vincent Ng (vsn2) / Jerry Wang (jw293) ECE 476: Wednesday 1:30 lab Final Project Handheld Ultrasonic Rangefinder */ #include #include // sprintf #include // ftoa #define LCDwidth 16 //characters #define t1 1 //timer vars #define t2 2400 #define nopush 1 #define maybepush 2 #define pushed 3 #define maybenopush 4 #define pulsecount 6 //# of pulses to send #define waittime 0 //wait time which isn't neccessary #define dp 3 //decimal points #asm .equ __lcd_port=0x15 #endasm #include // LCD driver routines void initialize(void); void pulse(void); void debounce(void); void checkpin7(void); unsigned char time1, time2, delayedsend, wait; char sendpulse, calibrate, displayspeed,received, speedmode, normal, pushstate, D1,D2, D3, mode; char lcd_buffer[17]; // LCD display buffer int count, rcount, samples; unsigned long ticks, loopcount, ovrflwcount, stoptime, stopcount; double distance, currdist, prevdist,speed, distsum, speedsum, tsum, ctpm, tpm; interrupt [TIM0_OVF] void timer0_ovrflw(void){ ovrflwcount++; } void main(void) { initialize(); while (1) { if(delayedsend == 0){ //a delay before sending the next pulse if(time1 == 0){ pulse(); time1 = t1; } } if(time2 == 0){ //timer for 30 ms debounce(); time2 = t2; } checkpin7(); } } void checkpin7(void){ if((ovrflwcount>500)&&(received==0)){ lcd_gotoxy(0,0); //position to upper left on display lcd_putsf("d ="); //another string from flash received = 1; lcd_gotoxy(4,0); lcd_putsf("out of range"); } if((~PIND.7)&&(wait == 0)&&(received==0)){ //if the pin goes high we received stoptime = TCNT0; //count the # of ticks stopcount = ovrflwcount; //count # of times counter over flowed before receiving received = 1; //received the pulse lcd_clear(); lcd_gotoxy(0,0); //position to upper left on display lcd_putsf("d ="); //another string from flash ticks = ((stopcount*256)+stoptime); //calculate total ticks distance = (((double)ticks)*1.36*(tpm/ctpm))/2; //# of ticks * (1.36 mm pertick)*(ticks per 5 cm/calibrated) //all over 2 to compensate for sending and receiving prevdist = currdist; //store previous dist currdist = distance; //store current dist ftoa(distance,dp,lcd_buffer); //display distance lcd_gotoxy(4,0); lcd_putsf(" "); lcd_gotoxy(4,0); lcd_puts(lcd_buffer); if(normal){ if(rcount>0){ delayedsend = 60000; //delay enough before sending next pulse sendpulse = 1; count = 2*pulsecount; wait = waittime; distsum = distsum + distance; //add up the samples if(rcount == (samples/2)){ //take the middle and last samples speedsum = distance; //for speed calculation }else if(rcount == 1){ speedsum = speedsum - distance; } rcount--; }else{ distsum = distsum/(samples); //take the average speedsum = (speedsum/(samples/100)); //calculate speed between first and last ftoa(distsum,dp,lcd_buffer); //displaystuff lcd_gotoxy(4,0); lcd_putsf(" "); lcd_gotoxy(4,0); lcd_puts(lcd_buffer); lcd_gotoxy(0,1); lcd_putsf("spd = "); lcd_gotoxy(9,1); ftoa(speedsum,dp,lcd_buffer); lcd_puts(lcd_buffer); //end displaying stuff distsum = 0; //reset variables speedsum = 0; normal = 0; } }else if(calibrate){ /*takes 200 samples of how many ticks for 5cm *averages it and sets it as the calibrated ticks per 5 cm */ if(rcount>0){ delayedsend = 60000; sendpulse = 1; count = 2*pulsecount; wait = waittime; distsum = distsum + distance; //sum up the distances tsum = tsum + ticks; //sum up the ticks rcount--; }else{ distsum = distsum/((float)samples); //average the distances tsum = tsum/((float)samples) ; //average the ticks ftoa(distsum,dp,lcd_buffer); //display all this stuff to lcd lcd_gotoxy(4,0); lcd_putsf(" "); lcd_gotoxy(4,0); lcd_puts(lcd_buffer); lcd_gotoxy(0,1); lcd_putsf("avgtick = "); lcd_gotoxy(10,1); ftoa(tsum,dp,lcd_buffer); lcd_puts(lcd_buffer); //end displaying stuff distsum = 0; //reset variables ctpm = tsum; tsum = 0; calibrate = 0; } } } } void debounce(void){//standard debounce state machine as given in lecture switch(pushstate){ case nopush: if((~PIND.1) || (~PIND.2) || (~PIND.3)) // button pushed? pushstate = maybepush; else pushstate = nopush; break; case maybepush: if((~PIND.1) || (~PIND.2) || (~PIND.3)) pushstate = pushed; else pushstate = nopush; break; case pushed: if((~PIND.1) || (~PIND.2) || (~PIND.3)){ // button pushed? pushstate = pushed; if(~PIND.1) D1 = 1; //pushflags for each button else if(~PIND.2) D2 = 1; else if(~PIND.3) D3 = 1; }else pushstate = maybenopush; break; case maybenopush: if((~PIND.1) || (~PIND.2) || (~PIND.3)) // button pushed? pushstate = pushed; else{ pushstate = nopush; /* D1 is normal operation D2 is speed detection mode D3 is calibration mode This checks which button was pressed and sets the appropriate flags for each mode */ if(received){ if(!mode){ if(D1){ sendpulse = 1; //sends a pulse count = 2*pulsecount; wait = waittime; //wait for receive rcount = samples; //count for # of samples D1 = 0; normal = 1; //mode of operation }else if(D2){ ctpm = 73; //reset the calibration mode = 1; //set mode to change samples mode lcd_clear(); //clear the display lcd_putsf("Sample #"); lcd_gotoxy(0,1); lcd_putsf("b1- "); lcd_putsf("b2+ b3 back"); D2 = 0; }else if(D3){ sendpulse = 1; //sends pulse count = 2*pulsecount; wait = waittime; calibrate = 1; //calibrate mode on D3 = 0; rcount = samples; } }else if(mode){ //mode two for changing sample number if(D1){ //decrement sample # if(samples>50){ samples = samples - 50; //minimum number 50 } D1 = 0; lcd_gotoxy(0,0); //display sample number to LCD lcd_putsf(" "); lcd_gotoxy(0,0); sprintf (lcd_buffer, "n = %i", samples); lcd_puts(lcd_buffer); }else if(D2){ //increment sample # samples = samples+50; lcd_gotoxy(0,0); lcd_putsf(" "); lcd_gotoxy(0,0); sprintf (lcd_buffer, "n = %i", samples); lcd_puts(lcd_buffer); D2 = 0; }else if(D3){ ctpm = 73; //reset the calibration mode = 0; //set mode to change samples mode lcd_clear(); //clear the display lcd_gotoxy(0,0); //show regular operation options lcd_putsf("b1 sendpulse"); lcd_gotoxy(0,1); lcd_putsf("b2 mode2 "); lcd_putsf("b3 cal"); D3 = 0; } } }//end received if } break; } // switch } void pulse(void){ //sends a certain number of pulses depending on what the count is if(sendpulse){ received = 0; if(count>0){ TCCR1A = 0b01000011; count--; }else{ sendpulse = 0; TCCR1A = 0b00000011; TCNT0 = 0; ovrflwcount = 0; } } } void initialize(void) { //initialize pushflags for buttons D1 = 0; //which pin is pushed D2 = 0; D3 = 0; normal = 0; prevdist = 0; currdist = 0; rcount =0; distsum = 0; speedsum = 0; tsum = 0; // initialize the LCD for 16 char wide lcd_init(LCDwidth); //initialize the display lcd_clear(); //clear the display lcd_putsf("b1 sendpulse"); lcd_gotoxy(0,1); lcd_putsf("b2 mode2 "); lcd_putsf("b3 cal"); sendpulse = 0; //set up the ports DDRD=0b00100000; // PORT D.5 is output rest is inputs PORTD=0; //initialize the variables to their proper values stoptime = 0; displayspeed = 0; speedmode = 0; loopcount = 0; speed = 0; mode = 0; received = 1; samples = 200; calibrate = 0; pushstate = nopush; ticks = 0; ctpm= 73.0; //init ticks per 5 cm tpm = 73.0; //set up timer 0 and timer 1 TCCR0=0b000000011; //prescalar to 64 and turn on clear-on-match TIMSK = 0x11; //timer1 compA and TIMER0 COMP interrupts on OCR1A = 24; //timer1 OCR to count 25 times and toggle OC1A at 40kHz TCCR1A = 0b00000011; //divide the clock by 8 PWM mode on TCCR1B = 0b00011010; //init the timers time1=t1; time2=t2; wait = 0; delayedsend = 0; #asm sei #endasm } interrupt [TIM1_COMPA] void timer1_compare(void) { if (time1>0) --time1; //40khz if (time2>0) --time2; //debounce machine if (wait>0) --wait; //wait to receive if (delayedsend>0) --delayedsend; //wait to send another pulse }