// A to D test code // NOTE -- Aref is pin 32 #include <Mega32.h> #include <stdio.h> // sprintf #include <stdlib.h> #include <math.h> //I like these definitions #define begin { #define end } #define LCDwidth 16 //characters //calc constants #define clock_tick 6.25e-8 #define mps2 6.0956392045e-2 //convert to disp units //#define velocity_convert .0981 // m/s // .0981 * .001 m/km /3600 #define velocity_convert 0.35316 //km/hr #define distance_convert .000000981//m #define hp_convert 0.0003725 //State machine state names #define MaybePush 1 #define MaybePush1 2 #define Push 3 #define NoPush 4 #define MaybeNoPush 5 //State machine for program #define Calibrate 0 #define GetWeight 1 #define Measure 2 #define Type 3 #define ZeroGWait 4 #define Accel 1 #define Velocity 2 #define Distance 3 #define HP 4 #define Time 5 //calistate #define zero 1 #define one 2 #define negone 3 #define Display 4 //type states #define zero60 1 #define zero30 2 #define quarter 3 #define eighth 4 #define brake 5 #define zero100 0 //sub state #define Stop_Measure 0xff #define Start_Measure 0x00 /* Use an 1x16 alphanumeric LCD connected to PORTC as follows: [LCD] [AT90S8515 DIP40] 1 GND- 20 GND 2 +5V- 40 VCC 3 VLC 10k trimpot wiper (trimpot ends go to +5 and gnd) 4 RS - 21 PC0 5 RD - 22 PC1 6 EN - 23 PC2 11 D4 - 25 PC4 12 D5 - 26 PC5 13 D6 - 27 PC6 14 D7 - 28 PC7 3.22 =-1g 3.82 =0g 4.57= 1g */ #asm .equ __lcd_port=0x15 #endasm #include <lcd.h> // LCD driver routines char lcd_buffer_g[4]; // LCD display buffer char lcd_buffer_g2[4]; char lcd_buffer_v[10]; char lcd_buffer_d[10]; char lcd_buffer_t[10]; char lcd_buffer[10]; double zerog,oneg,negoneg;//calibration values char lcd_buffer_w[5]; int Ain ; //raw A to D number double voltage ; //scaled input voltage double current_g,previous_g,current_v, previous_v,current_d,previous_d,maxg,maxv; double truev,trued; double weight;//weight of car + person unsigned int dispCounter; float finaltime;// count to when to update lcd char ProgState, substate, stateIter,firstint,isdone; //state var, and state loop counter char currentOut,dispState,buttonState,caliState,typeState; double hp,maxhp,max1g,maxn1g; double bottomslope; char stopCondition , AutoStart; double round(double,char ); void main(void) begin // initialize the LCD for 16 char wide lcd_init(LCDwidth); //initialize the display lcd_clear(); //clear the display //init the A to D converter //channel zero/ left adj / ADMUX = 0b00100000; //enable ADC and set prescaler to 1/64*8MHz=125,000 ADCSR = 0x80 + 0x06; MCUCR = 0b00001000; //choose ADC mode DDRD = 0x00; //input PORTD= 0xFF; //init timer 1 to generate time base for measuring OCR1A = 2500; //generate 10msec time base TCCR1B = 11; //pre-scalar at 64; clear-on-match TCCR1A = 0x00; //turn off pwm and oc lines TIMSK = 0x10; //enable interrupt T1 cmp firstint= 1; dispCounter = 0; isdone =0; dispState= 0; caliState = one; typeState = zero60; AutoStart= 0; stopCondition=1; buttonState = NoPush; substate = Stop_Measure; maxn1g = 128; #asm sei #endasm //collect weight information // measure and display loop stateIter = 0; ProgState = Calibrate; //weight = 0; while (1) { switch(typeState) { case zero60: if (truev >= 97 && ProgState == Measure) finaltime = (float)dispCounter/100; break; case zero30: if (truev >= 48.5 && ProgState == Measure) finaltime = (float)dispCounter/100; break; case zero100: if (truev >= 159 && ProgState == Measure) finaltime = (float)dispCounter/100; break; case quarter: if (trued >= .398 && ProgState == Measure) finaltime = (float)dispCounter/100; break; case eighth: if (trued >= .199 && ProgState == Measure) finaltime = (float)dispCounter/100; break; case brake: if (current_g==0 && dispCounter > 150 && ProgState == Measure) finaltime = (float)dispCounter/100; break; } } } //timer 1 overflow ISR interrupt [TIM1_COMPA] void t1_cmpA(void) { switch(ProgState){ //semi-auto matic calibrtion case Type: switch(typeState) { case zero60: lcd_gotoxy(0,0); lcd_putsf("00-60mph"); break; case zero30: lcd_gotoxy(0,0); lcd_putsf("00-30mph"); break; case zero100: lcd_gotoxy(0,0); lcd_putsf("0-100mph"); break; case quarter: lcd_gotoxy(0,0); lcd_putsf("1/4 mile"); break; case eighth: lcd_gotoxy(0,0); lcd_putsf("1/8 mile"); break; case brake: lcd_clear(); lcd_gotoxy(0,0); lcd_putsf("brake"); break; } switch (buttonState) { case NoPush: if (PIND==0b11111101) buttonState = MaybePush; break; //if pushed case MaybePush: if (PIND==0b11111101) { buttonState = Push; typeState = (typeState+1)%6;//wrap around } else buttonState= NoPush; break; case Push: if (PIND==0b11111101) { } else buttonState = MaybeNoPush; break; case MaybeNoPush: if (PIND==0b11111101) buttonState = Push; else buttonState= NoPush; break; } if (PIND==0b11111011) ProgState = GetWeight; break; case Calibrate: if (stateIter==0) { lcd_gotoxy(0,0); lcd_putsf("Calibrate"); lcd_gotoxy(0,1); lcd_putsf("1G VERT"); buttonState = NoPush; stateIter++; } ADCSR = ADCSR | 0x40; Ain = ADCH; voltage = (double)Ain ; lcd_buffer[1] = 0; lcd_gotoxy(8,1); itoa(Ain,lcd_buffer); lcd_puts(lcd_buffer); switch (buttonState) { case NoPush: if (PIND==0b11111101) buttonState = MaybePush; switch (caliState) { case one: //when searching for 1 g point take max sample max1g= fmax(max1g,voltage); break; case negone: //take min for neg 1 g maxn1g = fmin(maxn1g,voltage); break; } break; //if pushed case MaybePush: if (PIND==0b11111101) { buttonState = Push; //voltage = (voltage/256)*4.92 ; switch (caliState) { case one: oneg= max1g; caliState = negone; //set up next poart lcd_gotoxy(0,1); lcd_putsf("-1G VERT"); break; case negone: //negoneg = voltage; negoneg= maxn1g; ProgState = Type; caliState = Display;//ensure it doesn't go back thr // do some serious calc zerog = (oneg+ negoneg)/2.0;//extrapolate 0g bottomslope = (oneg-negoneg)/2.0; //slope lcd_clear(); break; } } else buttonState= NoPush; break; case Push: if (PIND==0b11111101) { } else buttonState = MaybeNoPush; break; case MaybeNoPush: if (PIND==0b11111101) buttonState = Push; else buttonState= NoPush; break; } break; case GetWeight: //pin4 is hardware reset lcd_gotoxy(0,0); lcd_putsf("Enter Weight(kg)"); if (PIND==0b11111101) { weight = weight + 5; } else if (PIND==0b11111011) { weight = weight - 5; weight = fmax(weight,0); } if (PIND==0b11111110) { ProgState = ZeroGWait; buttonState = NoPush; stateIter=0; } lcd_gotoxy(0,1); ftoa(weight,0,lcd_buffer_w); lcd_puts(lcd_buffer_w); break; case ZeroGWait: /* lcd_gotoxy(0,0); ftoa(oneg,2,lcd_buffer_g); lcd_puts(lcd_buffer_g); lcd_gotoxy(8,0); ftoa(negoneg,2,lcd_buffer_g); lcd_puts(lcd_buffer_g); lcd_gotoxy(0,1); ftoa(zerog,2,lcd_buffer_g); lcd_puts(lcd_buffer_g); /*/ if (stateIter==0) { lcd_clear(); lcd_gotoxy(0,0); lcd_putsf("Level:0.0g"); stateIter++; } ADCSR = ADCSR | 0x40; Ain = ADCH; voltage = (double)Ain ; //find g values if (voltage< zerog-10) { current_g = (voltage - zerog)/bottomslope; }// in g-units else if (voltage>zerog+10) { current_g = (voltage - zerog)/bottomslope; }// in g-units else {current_g = 0.0;} if (PIND == 0b11111101){//auto or manual start? AutoStart++; AutoStart=AutoStart%2; } switch (buttonState) { case NoPush: if (PIND==0b11111011) buttonState = MaybePush; break; case MaybePush: if (PIND==0b11111011) { dispCounter = 0; ProgState = Measure; buttonState = NoPush; if (AutoStart==0) { substate= Start_Measure; } lcd_clear(); } else buttonState= NoPush; break; case Push: if (PIND==0b11111011) { } else buttonState = MaybeNoPush; break; case MaybeNoPush: if (PIND==0b11111011) buttonState = Push; else buttonState= NoPush; break; } if (dispCounter%25==0) { //do display lcd_gotoxy(0,1); ftoa(current_g,2,lcd_buffer_g); lcd_puts(lcd_buffer_g); lcd_gotoxy(7,1); if (AutoStart==0) { lcd_putsf("Manu"); } else { lcd_putsf("Auto"); } //ftoa(voltage,2,lcd_buffer_g); //lcd_puts(lcd_buffer_g); } break; case Measure: switch(typeState) { case zero60: if (truev >= 99) stopCondition = 0; break; case zero30: if (truev >= 49) stopCondition = 0; break; case zero100: if (truev >= 160) stopCondition = 0; break; case quarter: if (trued >= .4) stopCondition = 0; break; case eighth: if (trued >= .2) stopCondition = 0; break; case brake: if (current_g==0 && dispCounter > 150) stopCondition = 0; break; } if (stopCondition==0) { if (isdone==0) { lcd_gotoxy(2,0); if (current_g > 0) { ftoa(current_g,2 ,lcd_buffer_g); lcd_puts(lcd_buffer_g); } else { ftoa(current_g,2 ,lcd_buffer_g2); lcd_puts(lcd_buffer_g2); } //distance lcd_gotoxy(10,0); ftoa(current_d*distance_convert,2 ,lcd_buffer_d); lcd_puts(lcd_buffer_d); //velocity lcd_gotoxy(2,1); truev = current_v*velocity_convert; //ftoa(truev,10,lcd_buffer_v); ftoa((float)finaltime/100,2,lcd_buffer_v); lcd_puts(lcd_buffer_v); isdone= 1; currentOut= 1; lcd_clear(); } else{ switch (buttonState) { case NoPush: if (PIND==0b11111101) buttonState = MaybePush; break; case MaybePush: if (PIND==0b11111101) buttonState = MaybePush1; else buttonState= NoPush; break; case MaybePush1: if (PIND==0b11111101) { buttonState = Push; if (currentOut ==Time) currentOut= 1; else currentOut++; dispState = 0; lcd_clear(); } else buttonState= NoPush; break; case Push: if (PIND==0b11111101) { } else buttonState = MaybeNoPush; break; case MaybeNoPush: if (PIND==0b11111101) buttonState = Push; else buttonState= NoPush; break; } switch (currentOut) { case Accel: lcd_gotoxy(0,0); lcd_putsf("Max Accel(g):"); lcd_gotoxy(1,1); ftoa(maxg,2,lcd_buffer_g); lcd_puts(lcd_buffer_g); break; case Velocity: lcd_gotoxy(0,0); lcd_putsf("Max Velocity(mph):"); lcd_gotoxy(1,1); ftoa(maxv*0.62,2,lcd_buffer_v); lcd_puts(lcd_buffer_v); break; case Distance: lcd_gotoxy(0,0); lcd_putsf("Distance:(ft)"); lcd_gotoxy(1,1); ftoa(trued*3280,3,lcd_buffer_d); lcd_puts(lcd_buffer_d); break; case HP: lcd_gotoxy(0,0); lcd_putsf("Max HP:"); lcd_gotoxy(1,1); ftoa(maxhp,2,lcd_buffer_t); lcd_puts(lcd_buffer_t); break; case Time: lcd_gotoxy(0,0); lcd_putsf("Time(s):"); lcd_gotoxy(1,1); ftoa(finaltime,2,lcd_buffer_t); lcd_puts(lcd_buffer_t); }//end switch if (PIND==0b11111110) { firstint= 1; dispCounter = 0; isdone =0; dispState= 0; caliState = one; ProgState = Type; typeState = zero60; AutoStart= 0; stopCondition=1; buttonState = NoPush; substate = Stop_Measure; current_g= 0; current_d = 0; current_v = 0; truev = 0; trued= 0; lcd_clear(); stateIter= 0; } } //stop } else if (substate == Start_Measure) { //32.184975ft/s^2 = 1g //0.0060956392045 miles/s^2 = 1g //1 clock tick = 0.0000000625sec+ ADCSR = ADCSR | 0x40; Ain = ADCH; voltage = (double)Ain ; //find g values if (voltage< zerog-10) { current_g = (voltage - zerog)/bottomslope; }// in g-units else if (voltage>zerog+10) { current_g = (voltage - zerog)/bottomslope; }// in g-units else {current_g = 0.0;} current_g=round(current_g,2); if (firstint==1) { current_v = 0; //firstint=0; } //integrate current_v = current_g + previous_v; current_d = current_v + previous_d; if (dispCounter%50==0) { if (firstint==1) { maxg= 0; current_v = 0; current_d= 0; firstint=0; maxhp = 0; } // display the voltage //g force lcd_gotoxy(0,0); lcd_putsf("g="); lcd_gotoxy(8,0); lcd_putsf("d="); lcd_gotoxy(0,1); lcd_putsf("t="); lcd_gotoxy(2,0); if (current_g > 0) { ftoa(current_g,2 ,lcd_buffer_g); lcd_puts(lcd_buffer_g); } else { ftoa(current_g,2 ,lcd_buffer_g2); lcd_puts(lcd_buffer_g2); } //distance lcd_gotoxy(10,0); ftoa(trued,2 ,lcd_buffer_d); lcd_puts(lcd_buffer_d); //velocity lcd_gotoxy(2,1); //ftoa(truev,10,lcd_buffer_v); //itoa(dispCounter,lcd_buffer_v); ftoa((float)dispCounter/100,2,lcd_buffer_v); lcd_puts(lcd_buffer_v); dispCounter++; isdone= 0 ; } else{ dispCounter++; } //calucate carryover values, pass over integration truev = current_v*velocity_convert; trued = current_d*distance_convert; hp = truev* current_g*9.81 *weight*hp_convert; previous_g = current_g; previous_v = current_v; previous_d = current_d; if(dispCounter > 3) maxg = fmax(current_g,maxg); maxv = fmax(truev,maxv); maxhp = fmax(hp,maxhp); } else { ADCSR = ADCSR | 0x40; Ain = ADCH; voltage = (double)Ain ; //find g values if (voltage< zerog-7) { current_g = (voltage - zerog)/bottomslope; }// in g-units else if (voltage>zerog+7) { current_g = (voltage - zerog)/bottomslope; }// in g-units else {current_g = 0.0;} if (fabs(current_g)>0.25) {//acceleration threshold to start measure substate=Start_Measure; } }//end if }//end switch } //rounds a float to 'places' digits including leading 0 //0.xxx or x.xxx or even xxxxe^ double round(double toRound, char places) { char rounda[10]; ftoa(toRound,places,rounda); return atof(rounda); }