// 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);
}