/************************************************** ********************************************
* T A X I M E T E R
*
* MCU Family: 8051 *
* MCU: AT89C51ED2
*
************************************************** ********************************************/
/*
* Group No. : 2
* Group Members: 0205002,
* 0205003,
* 0205004,
* 0205014,
* 0205026
* Author : Tamal Saha, #0205002, Email: saha_tamal2002***********,
tamal.saha******.com
* Date : 20-01-2007
*/
/*
* Assumptions:
* 1. External interrupt 0 used for STOP Button
* 2. External interrupt 1 used for START/PAUSE Button
* 3. Timer 0 used for rotation count
* 4. Timer 1 used for slowdown timer
* 5. Diameter of wheel of Taximeter = 30 cm = 0.3 m
* 6. pi = 3.141592654
* 7.a. Max velocity of Taximeter = 80 km/h
* 7.b. Max rps = 24
* 8. Rotation count incremented every 10 rotation
* 9.a. Slowdown timer threshold velocity = 5 km/h
* 9.b. Waiting time incremented if slowdown timer value >= 6.785 sec
*/
/*---------------------- *
* I N C L U D E S *
*---------------------- */
#include "reg_c51.h"
/*---------------------- *
* D E F I N E S *
*---------------------- */
#define MIN_FARE 120 // 12.0 Tk. minimum fare
#define DISTANCE_PER_ROTATION 0.942477796 // 0.942477796 m/rotation
#define DISTANCE_LEVEL_1 20 // 2.0 km
#define FARE_LEVEL_1 6 // FARE rate 6.0 Tk/km for first 2.0 km
#define MAX_LEVEL_1_FARE 120 // 12.0 Tk. Eqn: DISTANCE_LEVEL_1 * FARE_LEVEL_1 /100
#define FARE_LEVEL_2 5 // FARE rate 5.0 Tk/km after first 2.0 km
#define WAITING_FARE_RATE 2 // 2.0 Tk./min of waiting time
#define ROTATION_PER_OVERFLOW 10
#define TH0_AUTO_RELOAD_VALUE 246 //Timer 0 auto reload value = 256 - ROTATION_PER_OVERFLOW
#define MIN_SLOWDOWN_TIME 6785 // in ms; Maximum time for 10 rotation
#define FULL_OVERFLOW_COUNT 103 // 6.785840132/65536E-06 = 103.5437032
#define TH1_DEFAULT_INIT_VALUE 0 // TH1 = 0; Timer 1 normally starts from 0
#define TL1_DEFAULT_INIT_VALUE 0 // TL1 = 0;
#define TH1_LAST_INIT_VALUE 116 // TH1 = 116; Timer 1 starts from 29904(= 116*256 + 208) during
// FULL_OVERFLOW_COUNT overflows
#define TL1_LAST_INIT_VALUE 208 // TL1 = 208;
#define LAST_INIT_VALUE 29904 // 29904 = 116*256 + 208 = 65536- (6.785840132E+06 - 103*65536)
//Meter status values
#define ACTIVE 1
#define PAUSED 2
#define STOPPED 0
//DELAY(N); function
#define DELAY(N) for(i=0; i<N; i++)
/*-----------------------------------------*
* G L O B A L V A R I A B L E S *
*-----------------------------------------*/
unsigned char meterStatus; // meterStatus in first 128 byte
unsigned char timer1OverflowCount; // counts # of times Timer 1 overflows
bit hasSlowed; // vehicle has slowed down
unsigned int fractionSlowdownTime; // in ms the fraction slowdown time in timer 1 counter
unsigned long rotationCount; // # of rotations
unsigned long waitingTime; // waiting time in ms
unsigned long distance; // distance in meter
unsigned long waitingHHMMSS; // waiting time in ms
unsigned long fare; // fare in paisa
unsigned char P_Dummy; // dummy port data
char index; // 7 segment display index : FARE:0-4, DISTANCE:5-9,
// WAITING_TIME: 10-11: 12-13: 14-15
unsigned char digitShowed; // flag used to show at least 2 digits
unsigned char temp; // temporary variable used for showing time
unsigned char i; // delay loop counter
void main(void)
{
//interrupt configuration
IT0 = 1; //low level triggered external interrupt 0
IT1 = 1; //low level triggered external interrupt 1
IPL0 = 0x01; //interrupt priority = 0 0 0 0 0 0 0 1
IEN0 = 0x8F; //interrupt enable = 1 0 0 0 1 1 1 1
//interrupt configuration ends
while(1)
{
if(meterStatus != STOPPED)
{
distance = (rotationCount*DISTANCE_PER_ROTATION + 50)/100; // in meter
// 50 added for ceiling
// distance approximated to one digit meter
waitingHHMMSS = (waitingTime + 500)/1000; // in ms;
// 500 added for ceiling
// waiting time approximated to one digit second
fare = waitingHHMMSS * WAITING_FARE_RATE / 6; // fare for waiting time in one digit paisa
if(distance <= DISTANCE_LEVEL_1)
{
fare += distance * FARE_LEVEL_1; // fare
}
else
{
fare += (MAX_LEVEL_1_FARE + (distance - DISTANCE_LEVEL_1)* FARE_LEVEL_2);
}
if(fare < MIN_FARE)
{
fare = MIN_FARE;
}
// display F A R E
index = 0; // 7 segment display index set to LSD of FARE
digitShowed = 0;
while( (digitShowed < 2 || fare > 0) && index <= 4) //show at least two digits OR until fare > 0
{
//index >0 is just for overflow(FARE >= 9999.9 Tk) protection
P_Dummy = fare%10;
P_Dummy = P_Dummy << 4;
P_Dummy |= index;
P0 = P_Dummy; // out fare digit
P2_0 = index == 1 ? 0 : 1; // set decimal point for 7 Seg #3
fare /= 10;
index++;
digitShowed++;
DELAY(25);
}
// display F A R E ends
// display D I S T A N C E
index = 5; // 7 segment display index set to LSD of DISTANCE
digitShowed = 0;
while((digitShowed < 2 || distance > 0) && index <= 9)
{
P_Dummy = distance%10;
P_Dummy = P_Dummy << 4;
P_Dummy |= index;
P0 = P_Dummy; // out distance digit
P2_0 = index == 6 ? 0 : 1; // set decimal point of 7 Seg #8
distance /= 10;
index++;
digitShowed++;
DELAY(25);
}
// display D I S T A N C E ends
// display W A I T I N G T I M E
//display S E C O N D
temp = waitingHHMMSS%60; // temp set to second
index = 10; // 7 segment display index set to LSD of SECOND
while(index <= 11)
{
P_Dummy = temp%10;
P_Dummy <<= 4;
P_Dummy |= index;
P0 = P_Dummy; // out 'SECOND' digit
P2_0 = 1; // no decimal point
temp /= 10;
index++;
DELAY(25);
}
//display M I N U T E
waitingHHMMSS /= 60;
temp = waitingHHMMSS%60; // temp set to minute
while(index <= 13)
{
P_Dummy = temp%10;
P_Dummy <<= 4;
P_Dummy |= index;
P0 = P_Dummy; // out 'MINUTE' digit
P2_0 = 1; // no decimal point
temp /= 10;
index++;
DELAY(25);
}
//display H O U R
waitingHHMMSS /= 60;
while(index <= 15)
{
P_Dummy = temp%10;
P_Dummy <<= 4;
P_Dummy |= index;
P0 = P_Dummy; // out 'HOUR' digit
P2_0 = 1; // no decimal point
temp /= 10;
index++;
DELAY(25);
}
// display W A I T I N G T I M E ends
}
}
}
/*
* Purpose: External interrupt 0 is used to stop the meter
*
*/
void external0(void) interrupt 0 using 0
{
P3_2 = 1; //remove the low level triggered signal from P3.2 pin
TR0 = 0; //stop timer 0(rotation counter)
TR1 = 0; //stop timer 1(slowdown counter)
P2_1 = 1; //74154 Decoder is disabled to stop power loss through the 7 Segment Display
meterStatus = STOPPED; //meter status set to stopped
}
/*
* Purpose: External interrupt 1 is used to handle Start/Pause tole button
*
*/
void external1(void) interrupt 2 using 0
{
P3_3 = 1; //remove the low level triggered signal from P3.3 pin
if(meterStatus == ACTIVE)
{
TR0 = 0; //stop timer 0(rotation counter)
TR1 = 0; //stop timer 1(slowdown counter)
meterStatus = PAUSED; //meter status set to pause
}
else if(meterStatus == PAUSED)
{
meterStatus = ACTIVE; //meter status set to active
TR0 = 1; //start timer 0(rotation counter)
TR1 = 1; //start timer 1(slowdown counter)
}
else //if(meterStatus == STOPPED)
{
//initialize rotation & waiting time counter
rotationCount = 0;
waitingTime = 0;
//timer configuration
TMOD = 0x16; //timer0 GATE = 0, counter, mode 2 (auto reload)
//timer1 GATE = 0, timer, mode 1 ()
TH0 = TH0_AUTO_RELOAD_VALUE; //interrupt in every 10 rotations
TL0 = TH0_AUTO_RELOAD_VALUE;
TL1 = TL1_DEFAULT_INIT_VALUE; // clear low timer1
TH1 = TH1_DEFAULT_INIT_VALUE; // clear high timer1
timer1OverflowCount = 0; // clear timer1 overflowCount
hasSlowed = 0; // cleared at start of timer
//timer configuration ends
P2_1 = 0; //74154 Decoder is enabled to give power to the 7 Segment Display
meterStatus = ACTIVE; //meter status set to active
TR0 = 1; //start timer 0(rotation counter)
TR1 = 1; //start timer 1(slowdown counter)
}
}
/*
* Purpose: Since Timer 0 is configured to work as counter, an overflow occurs every
* 10 rotation. We stop the slowdown timer(timer 1). Then timer 1 is configured
* to start count from 0. Then timer 1 is restarted. */
void timer0(void) interrupt 1 using 0
{
TR1 = 0; // stop timer1 (slowdown timer)
if(hasSlowed == 1)
{
if(timer1OverflowCount > 0)
{
waitingTime += (((timer1OverflowCount - 1) * 65536)/1000);
}
fractionSlowdownTime = TH1;
fractionSlowdownTime <<= 4;
fractionSlowdownTime |= TL1;
if(timer1OverflowCount > FULL_OVERFLOW_COUNT)
{
fractionSlowdownTime -= LAST_INIT_VALUE;
}
waitingTime += (fractionSlowdownTime/1000);
hasSlowed = 0;
}
TL1 = TL1_DEFAULT_INIT_VALUE; // clear low timer1
TH1 = TH1_DEFAULT_INIT_VALUE; // clear high timer1
timer1OverflowCount = 0; // clear timer1 overflowCount
rotationCount += ROTATION_PER_OVERFLOW; // ten more rotations completed
TR1 = 1; // start timer1 (slowdown timer)
}
/*
* Purpose: Since Timer 0 is configured to work as counter, an overflow occurs every
* 10 rotation. We stop the slowdown timer(timer 1). Then timer 1 is configured
* to start count from 0. Then timer 1 is restarted.
*
* Calculation:
*
* 3600 * pi * diameter_wheel [diameter_wheel in meter]
* 1 rotation = -------------------------- sec
* max_velocity*1000 [max_velocity in km/h]
*
* = 0.6785840132 sec where diameter_wheel = 0.3m, max_velocity = 5 km/h
*
* 10 rotation = 6.785840132 sec
* = 103 full range overflow + 1 35632(29,904-65,535) range overflow
*
*/
void timer1(void) interrupt 3 using 0
{
timer1OverflowCount++;
if(timer1OverflowCount == FULL_OVERFLOW_COUNT)
{
TH1 = TH1_LAST_INIT_VALUE;
TL1 = TL1_LAST_INIT_VALUE;
}
else if(timer1OverflowCount > FULL_OVERFLOW_COUNT)
{
waitingTime += MIN_SLOWDOWN_TIME;
timer1OverflowCount = 0;
hasSlowed = 1;
}
}