```//  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

//enable ADC and set prescaler to 1/64*8MHz=125,000
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++;
}

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++;
}
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+
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 {
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);

}```