Designed for the “Pre-defined hardware” event at NSIT Innovision’06
Please scroll down for the schematic.
Please click here for pictures.
I. Name & address of the college:
Maharaja Agrasen Institute of Technology
Sector-22, Rohini, New Delhi – 110085
II. Name of the team members:
1) Rohit Rawat
VI Sem. ECE
Roll No. 55
Ph No.: 9818058035
2) Pawan Prakash Sant
VI Sem. ECE
Roll No. 8
Ph No.: 9868815956
3) Raghav Maheshwari
VI Sem. ECE
Roll No. 24
Ph No.: 9899087084
III. Name of the team: Code101
IV. Introduction:
Such a project would have been very difficult to implement with discrete
counters, register etc. Even if it is implemented with reasonable accuracy in
that way, its cost and power consumption would have been unjustified.
A microcontroller comes out as a simple and cost effective solution. Even though
we have not studied microcontrollers yet, our knowledge of the C language and
the various embedded tools (CodeVisionAVR C Compiler) helped us to implement
this project in a record time.
On choosing the Atmel Mega8515 microcontroller: It has a large amount of code
and data memory and sufficient RAM to accurately solve the given problem. It has
an inbuilt oscillator so we did not have to connect an external crystal. The
display used in an HD44780 compatible 2x16 character display.
Features:
1) Simultaneous display of velocity, acceleration, trip distance and total mileage.
2) Intelligent EEPROM writes. EEPROM has a limited lifecycle, approximately 10,000 writes. In other similar devices, the contents of the odometer are written to the EEPROM after every few minutes or so. This decreases the life of the EEPROM; also if the power supply is cut in between the EEPROM write cycles, the mileage traversed within those few minutes would be lost. In out design, the EEPROM contents are read at system startup, and are written only when the main power to the system gets cut.
3) Automatically senses a decrease in velocity even if there are no interrupts to the microprocessor. In other such devices, the device waits for another pulse to calculate the new velocity and if the pulse arrives very late or never at all, the same velocity is displayed. Also the changes are very abrupt. We have coded an algorithm which corrects this phenomenon and gives the accurate velocity display at all time, be it acceleration or de-acceleration.
4) Easily accessible buttons for changing diameter and resetting trip distance.
5) Almost infinite range. The range of the odometer is only limited by the
display size.
Acceptable ranges: Speed 1Km/hr to 400 Km/hr Resolution 0.1 Km/hr
Acceleration upto +/- 99 m/s2 Resolution 0.1 m/s2
Trip distance range upto 6400 Km Resolution 0.1 Km
Odometer range upto 99,999 Km Resolution 0.1 Km
V. Short technical description:
1. Power Supply:
The circuit works on the external supply (6V to 12V) provided by the car or
bike or from a battery.
When this supply is cut-off (at switching off the engine), an internal backup
cell (3.6 V Ni-Cd rechargeable cell) is used to power the microcontroller to
enable it to save the odometer data. After about three seconds, this backup is
also cut-off to increase the life of this battery.
Power
2. Microcontroller resources used:
We have used two interrupts, leaving a third one free for future se.
We have used only 2 (total 11 pins) of the available five I/O ports.
Program memory usage:
Code : 1713 words
Constants (dw/db): 54 words
Total : 1767 words
EEPROM memory usage: 5 bytes
So It can be ported to other lower/higher end microcontrollers with the above
resources.
The microcontroller clock was kept 4 MHz, though it is expected to work equally
well at lower locks.
3. Algorithm:
On system reset, the saved diameter is read from the EEPROM and the
circumference is calculated and displayed. The saved odometer reading is also
read from the EEPROM.
Now the program enters an infinite loop in which the variables for speed,
acceleration, trip distance and total distance are displayed on the LCD screen.
Within this loop, two keys: one for entering the diameter adjustment menu and
another for resetting the trip meter are scanned.
The calculation of all the parameters is performed by counting the time between
two consecutive revolutions of the wheel.
The input pulses from the transducer in the wheel are fed into a signal
conditioning circuit to filter out unwanted noise. The output from this circuit
is connected to the interrupt input on the microcontroller (External
Interrupt0).
In the interrupt service routine for Interrupt0:
The current timer count is read, to the accuracy of 2^24 counts.
The count is reset to zero.
The trip distance and total distance are incremented as follows:
1) Add the circumference of the wheel to a variable dcm.
2) When this variable dcm exceeds 10000 (0.1 Km), increment the variables
distance and trip (which store the total distance in Km/10) by one, and subtract
10000 from dcm to keep the calculations accurate.
To calculate the speed, we use the formula:
Speed =
Km/hr
To calculate the acceleration, we use the formula:
Acceleration =
m/s2
where lastspeed is the calculated speed at the last interrupt and
SPEED_MULTIPLIER = 140.616 at a counter clock of 3906 Hz
Calculated from Speed=
Km/hr
ACC_MULTIPLIER = 1805 at a counter clock of 3906 Hz
Calculated as Acc =
m/s2
The External Interrupt1 is connected to a special circuit which triggers this
interrupt in case of power cut-off. The interrupt service routine begins to save
the odometer reading while the external circuit continues to provide power from
the external battery just long enough for the data to be properly written.
The Timer1 is a 16 bit timer which is used along with an overflow variable to
increase its range to 24 bits, to measure really long delays.
The Timer0 is an 8 bit timer which performs an important task of bringing down
the velocity gradually between pulses and further down to zero in case the input
pulses stop arriving. It works by linear prediction:
If the current timer count has exceeded the last timer count between two
interrupts, it calculates what would the velocity be if the input pulse arrived
just now. It helps to keep the velocity accurate at all times; even at extremely
small velocities where other speedometers would be stuck at an incorrect value
or would dumbly show 0 velocity after a timeout.
4. Keyboard:
The four keys used on Port C are software debounced.
During general operation, the Enter/TripReset switch sets the Trip distance to
0.
The Enter diameter key needs to be pressed and held for at least a second to
enter the change diameter menu.
Here the diameter can be incremented/decremented with the ‘+’ and ‘-‘ keys. To
accept a value, the Enter key is pressed and the data is saved in the EEPROM.
Code:
/***************************************************** Project : SPEEDOMETER Version : 0.1 Date : 1/23/2006 Author : Rohit, Pawan, Raghav Company : MAIT Comments: Chip type : ATmega8515 Program type : Application Clock frequency : 4.000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 128 Compiled with CodeVisionAVR C cross-compiler. *****************************************************/ #include// Alphanumeric LCD Module functions #asm .equ __lcd_port=0x1B ;PORTA #endasm #include // Standard library functions (itoa, ftoa etc.) #include // Delay functions #include // Nicknames for port pins #define PLUS_KEY PINC.0 #define MINUS_KEY PINC.1 #define ENTER_KEY PINC.2 #define DIA_KEY PINC.3 #define BUZZER_PORT PORTC.7 // Nicknames for delays #define DEBOUNCE_DELAY 80 #define REFRESH_DELAY 200 #define SPEED_MULTIPLIER 140.616 #define ACC_MULTIPLIER 1805 // Global variables unsigned char dia=60; // Diameter of the wheel (in cm); read from the EEPROM unsigned char circ=0; // Calculated circumference unsigned int dcm=0; // Distance covered in cm (modulo 100m) float speed=0; // Calculated speed float lastspeed=0; // Last sampled speed float acceleration=0; // Calculated acceleration unsigned int trip=0; // Trip distance (0.1 Km) unsigned long distance=0; // Total distance (0.1 Km) unsigned char overflow=0; // Timer1 overflow; for looong delays unsigned long count=0; // Current Timer1 count unsigned long lastcount=0; // Last Timer1 count unsigned char buzz=0; // Buzzer timer // Some messages flash char msg_saving[]="Saving Data..."; flash char msg_circ[]="Circumference:"; flash char msg_dia[]="Enter Diameter"; flash char msg_cm[]=" cm"; // Temporary variables char tempstr[10]; float tempfloat=0; // EEPROM saved variables // Note that these variables are not written periodically. // The diameter is written only when the diameter is changed from the menu. // The odometer reading is saved only when the main power to the system is cut-off. // This helps in increasing the lifespan of the EEPROM many times. eeprom unsigned long int save_odometer=0; eeprom unsigned char save_dia=0; // Timer 0 overflow interrupt service routine // Here we predict the current velocity of the vehicle if no input pulse // arrives within the expected period. // In other words, it helps to bring down the velocity if the input pulses stop arriving. // It interrupts about every 0.06 seconds interrupt [TIM0_OVF] void timer0_ovf_isr(void) { // Supposing a pulse was recieved just now, what will be the speed and acceleration? count=overflow*65536+TCNT1; if(count>lastcount) { speed=((float)circ*SPEED_MULTIPLIER)/(float)count; acceleration=((speed-lastspeed)*ACC_MULTIPLIER)/(float)count; } if(speed>120) { buzz++; if(buzz<30) BUZZER_PORT=1; else BUZZER_PORT=0; if(buzz==60) buzz=0; } else buzz=0; } // Timer 1 overflow interrupt service routine interrupt [TIM1_OVF] void timer1_ovf_isr(void) { overflow++; } // External Interrupt 0 service routine // A pulse is recieved & this function gets called.. interrupt [EXT_INT0] void ext_int0_isr(void) { // Increment dcm modulo 10000 (0.1 Km) dcm=dcm+circ; if(dcm>10000) { dcm=dcm-10000; // For every 10000 cm, trip and distance are incremented by 1 (0.1 Km) trip++; distance++; } count=overflow*65536+TCNT1; speed=((float)circ*SPEED_MULTIPLIER)/(float)count; acceleration=((speed-lastspeed)*ACC_MULTIPLIER)/(float)count; // Reset the timer TCNT1=0; overflow=0; // Save the current count (for automatic damping of speed by Timer0) lastcount=count; // Save the curent speed (for calculating acceleration in future) lastspeed=speed; } // External Interrupt 1 service routine // This interrupt is triggered automatically by the external circuit // whenever the main power to the circuit is removed (turning off the vehicle). // The circuit also provides battery backup for a sufficient duration to save the // odometer reading in the EEPROM. interrupt [EXT_INT1] void ext_int1_isr(void) { // Save odometer reading in EEPROM save_odometer=distance; lcd_clear(); lcd_putsf(msg_saving); // "Saving Data..." delay_ms(1000); } void main(void) { // Input/Output Ports initialization // Port A initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTA=0x00; DDRA=0x00; // Port B initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTB=0x00; DDRB=0x00; // Port C initialization // Func7=Out Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTC=0x00; DDRC=0x80; // Port D initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTD=0x00; DDRD=0x00; // Port E initialization // Func2=In Func1=In Func0=In // State2=T State1=T State0=T PORTE=0x00; DDRE=0x00; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 3.906 kHz // Mode: Normal top=FFh // OC0 output: Disconnected TCCR0=0x05; TCNT0=0x00; OCR0=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 3.906 kHz // Mode: Normal top=FFFFh // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: On // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0x00; TCCR1B=0x05; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // External Interrupt(s) initialization // INT0: On ; Input Pulses // INT0 Mode: Falling Edge // INT1: On ; Save the current odometer reading // INT1 Mode: Falling Edge // INT2: Off ; Not used GICR|=0xC0; MCUCR=0x0A; EMCUCR=0x00; GIFR=0xC0; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x80; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; // LCD module initialization lcd_init(16); //Read saved odometer reading distance=save_odometer; //Read saved diameter dia=save_dia; circ=3.14*(float)dia; lcd_putsf(msg_circ); // "Circumference:" itoa(circ, tempstr); lcd_gotoxy(3,1); lcd_puts(tempstr); lcd_putsf(msg_cm); // " cm" delay_ms(1000); // Global enable interrupts #asm("sei") while(1) { lcd_clear(); // Need not show the speeds of a caterpillar if(speed<1) speed=0; // Convert speed to string ftoa(speed, 1, tempstr); // Display it on the screen lcd_puts(tempstr); lcd_putsf("Kmph"); // Convert acceleration to string ftoa(acceleration, 1, tempstr); // Display it on the screen if(acceleration<0) // To avoid shifting of the displayed number lcd_gotoxy(8,0); else lcd_gotoxy(9,0); lcd_puts(tempstr); lcd_putsf("m/s2"); // Convert trip distance (in Km) to string ftoa((float)trip/10, 1, tempstr); // Display it on the screen lcd_gotoxy(0,1); lcd_puts(tempstr); lcd_putsf("Km"); // Convert total distance (in Km) to string ftoa((float)distance/10, 1, tempstr); // Display it on the screen lcd_gotoxy(8,1); lcd_puts(tempstr); lcd_putsf("Km"); delay_ms(REFRESH_DELAY); // If the Trip Rest switch is pressed, clear the trip meter if(ENTER_KEY==0) { delay_ms(DEBOUNCE_DELAY); if(ENTER_KEY==0) { trip=0; } } // If the Change Diamter key is pressed for more than a second, if(DIA_KEY==0) { delay_ms(1000); if(DIA_KEY==0) { while (1) { lcd_clear(); lcd_putsf(msg_dia); itoa(dia,tempstr); lcd_gotoxy(3,1); lcd_puts(tempstr); lcd_putsf(msg_cm); if(PLUS_KEY==0 && dia<81) { delay_ms(DEBOUNCE_DELAY); if(PLUS_KEY==0) dia=dia+1; } else if(MINUS_KEY==0 && dia>1) { delay_ms(DEBOUNCE_DELAY); if(MINUS_KEY==0) dia=dia-1; } else if(ENTER_KEY==0) { delay_ms(DEBOUNCE_DELAY); if(ENTER_KEY==0) { circ=3.14*(float)dia; lcd_clear(); lcd_putsf(msg_circ); // "Circumference:" itoa(circ, tempstr); lcd_gotoxy(3,1); lcd_puts(tempstr); lcd_putsf(msg_cm); // " cm" // Save in EEPROM save_dia=dia; delay_ms(1000); break; } } else delay_ms(DEBOUNCE_DELAY); }; } } }; }
