Pages

Super Train Controller



Introduction

A simple way to keep people interested in learning is to have them work with familiar systems in new and interesting ways. Our idea was to design a project that could be used as an instructional tool for student, away to learn about micro-controllers without the monotony of standard design projects.  The train controller allows students to get hands on experience with programming the Atmel 90s8515, while exploring the concepts of analog design, such as isolation of power supplies using inductors and opto-couplers, motor control, sensor design, and signal control.


The following sections show how we implemented the train controller.  Using inexpensive and readily available parts, we designed a controller for the N-scale Bachman Highballer Chessie train set.  The track is a standard Bachman e-z snap together track, and was mounted to a piece of plywood using cable ties and a staple gun.  Rubber feet are placed one the bottom of the board to allow wired to be strung for ease of connection.  The remaining portion of this report documents how the hardware and software was developed to control the mounted train set, provides detailed schematics and code for the hardware, explains possible improvements for the future, and shares our concluding remarks.

Sensors
In order to detect where the train was on the track, optical sensors were placed at four points on the track.  Each of these sensors was an infra-red (IR) emitting diode and photo-transistor pair.  The sensors output a logical 0 when there was no train present and a logical 1 while the train was breaking the beam.  This was accomplished because the LED constantly emitted a beam into the optical base of the photo-transistor, so the transistor was on except while the beam was being broken.  The output of the transistor was buffered using a Burr-Brown OPA2350 op-amp, and then connected to both the port pin on the Atmel 90s8515 (PORTA[0..4}) and to 4 green LED's to allow us to visibly ensure the sensors were working properly..  Schematics showing the wiring for the LED's and photo-transistors are shown in figure 1 below.
Figure 1: Diagram of Sensors for the Train

AC Motor Control
Controlling the speed of the train us the 90s8515 was accomplished through the use of an h-bridge scheme of transistors.  This indicates the AC motor is controlled by four transistors, with only two opposite ones turned on at any time.  One must be careful to not turn on two transistors on the same side, else some components may be blown due to excessive current.  The discrete logic shown in figure 2 was used in order to ensure only proper signals could be sent to the H-bridge.  The F/R control allows for one pin to control the direction of the train, 1 for forward and a 0 for reverse.  The PWM input is the output from the pulse width modulator (PWM) from the 90s8515.  This allows control of the train using only two pins.  The outputs from the logic are the inputs indicated on the H-bridge in figure 3.
Figure 2: H-Bridge Controller
In order to get an appropriate gain out of the TIP31 and TIP32 power transistors, a Darlington pair was assembled using 2n3904 and 2n3906 transistors and show in figure 3 below.  To ensure no noise could feedback from the noisy train 17V power supply, 4n35 opto-couplers were used, and the grounds were separated with an inductor (not shown) and a 50 micro-farad capacitor (not shown) was placed across the terminals of the trains power supply to reduce the noise emitted.
Figure 3: H-Bridge
Attaching all of the parts to the 90s8515 completes the hardware design.  In figure 4, the pins for the motor control and sensors are shown.  Pushbuttons are added to manually control the train as it moves around the track. Not shown on this schematic is the UART control, which is from PORTD[0..1].  This is where the train will receive programs and instructions from the computer.  Also, the programmer for the chip is not shown.  This is a 10 pin header connected to pins on the 8515 for on-board programming. 
Figure 4: Atmel 8515 Connections
The LCD (not shown) is connected to PORT C of the 8515, and the connections are listed in table 1:
Table 1: LCD connections
8515 PinLCD pinFunctionality
Ground1Ground
Vcc2Power
N/C3Contrast
PC04RS
PC15RD
PC26Enable
PC311D4
PC512D5
PC613D6
PC714D7





Software

Sensor Inputs
The sensors are connected to Pins 0 through 3 on Port A.  This system is set up to poll the sensors for a hit every 30 milliseconds. Once a hit is received it is recorded, but another hit cannot be recorded until the sensor reads 0, no hits, for 1.8s straight.  This is necessary so that the passing train does not trigger more than one sensor hit as the breaks between train cars pass.

Motor Control
The motor control unit is set up to interface with the H-bridge control circuit.

Forward and Backward motion is controlled with Pin 6 on Port D.  If 1 the train is in forward mode, 0 the train is in backward mode.  The setting of this pin is controlled in two ways, by external push buttons attached to Pins 3 and 4 on Port B and over UART.

                Forward
PortD.6 = 1 =>     (PortB.3 = 0)         or                 (UART command = “f”)
Backward
PortD.6 = 0 =>     (PortB.4 = 0)         or                 (UART command = “b”)

 The speed of the train is controlled with the pulse width modulator (PWM) attached to timer 1.  To increase or decrease the speed of the train after it has been set into forward or backward motion use the external push buttons attached to Pins 0 and 1 on Port B.  The speed increases in increments of 5% for every .1 seconds that the button is held down.  If the speed decrease button is held and the current speed is at 0% the train will switch from forward operation to backward, likewise if the increase button is held and the current speed is at 0% the train will switch from backward operation to forward operation.  The control of the pulse width modulator relies in changing the value of the OCR1A register, which is set to interrupt on a match of the lower 10-bits to the timer 1 value.  It is loaded with 1024 times the percentage currently given.

                 Increase Speed
Increase OCR1A by 5%                => (PortB.0 = 0 for .1s)
                 Decrease Speed
Decrease OCR1A by 5%                => (PortB.1 = 0 for .1s)

 There is also a command to stop the train, controlled by a push button on Pin 2 of Port B or over UART.  This command sets both Pin 5 and Pin 6 of Port D to 0 and turns off the pulse width modulator.

                 Stop
                PWM turned off
                PortD.5 = 0 PortD.6 = 0 =>                (PortB.2 = 0)         or                 (UART command = “s”)

 Speed Control Optimizations

To make the train more realistic we implemented two speed control optimizations.
The first optimization is inertia.  This means that when the train starts, stops, or changes direction it must slowly ramp up or down to the desired speed.  The model train right out of the box can start, stop, and change directions at will, but a train in real life requires time to slow down because of weight.  We decided to simulate this weight by implementing a software loop that ramps the OCR1A register up or down.

The second optimization is slowing the train on curves.  Our track is an oval shape, which has straight-aways and curves.  It is safe for the train to go at full speed on the straight-aways, but if it exceeds 60% speed on the curves it chances flying off the track. Therefore using the optical sensors we made it so that the train ramps down to 60% speed, if it is over 60%, for the curves and then ramps back to its initial speed when it returns to a straight-away.

Programming the Train

The final implementation decision that we made was to give the user the ability to run short programs on the train through a command in UART.  

A program statement has the form:
                p $# $# $# $# $#

The “p” at the beginning indicates that the system is going to run a program.  The program to run is specified by the $# entries. There is a maximum of 5 of these entries, but there is no minimum number for entries.  The $ represents either an “f” to tell the train to go forward or a “b” to tell the train to go backward.  The # is a number from 0-9 representing the number of laps to do in the specified direction.  For example the sequence: p f2 b3 would make a program of 2 forward laps and 3 backward laps.

All programs are run at 100% speed, with all of the speed optimizations enabled.  All pushbuttons and UART commands are disabled except for the stop command.  A stop command during a program immediately ends the running program and returns to normal functionality.

LCD Output

The LCD output is fairly simple.

The first line of the LCD always reads “B&C’s Super Train” to indicate the title of our project.
The second line of the LCD always reads “Lap Count #”, where # is the number of times that the train has passed by the sensor connected to Pin 0 on Port A.

The third line displays the current operating status of the train, either forward, backward, or stop.  Next to that is the current percentage of the velocity.

The fourth line is only used when running a program.  When a program is running the fourth line reads “Program”, and next to that it reads “Lap #”.  The # is the number of laps left to run for the current direction in the program.

Results

Once all of the hardware was assembled and the software was programmed, the system worked well.  We had control of the train so that we could control its speed and direction, program the train so that it would do a certain number of laps forward and backward, and count the laps as the train went around.  In addition, ramping the speed of the train allowed us to make sure the train did not derail itself as it switched direction.  Also, the speed control as the train went into the curves kept the whole train on the track and did not allow for high speeds around the curves.

A few minor unfixed bugs (due to time constraints) were:
  • Train would not stay below 60 when passing sensors due to dynamic speed control.
  • Directions would get confused if changing directions on curve.
Below, are pictures of the circuitry that was actually built.


                        Figure 5: Complete train controller brought to life with all parts labeled

 
Figure 6: output on 4X20 LCD screen showing details about the train                Figure 7: H-bridge and Controller

 
Figure 8: Sensor power and push buttons with sensor 4 light lit                   Figure 9: Connections to the UART and programmer


Looking Ahead

Some functionality had to be left out due to time restrictions.  Possible improvements include:
  • Use of dynamic sensor control:  We would have like to have more control over the train starting and stopping positions using all four sensors as starting and stopping points.
  • Better speed optimization:  A few bugs in the code cause the train to speed up to over 60%, regardless of the previous speed.  More time in debugging code would have eliminated this error.
  • More programming options:  When programming the train, control of the speed and more dynamic positioning so it could be stopped at any sensor.
  • Different track styles and shapes:  Using the micro-controller it would have been possible to control different shapes of track, such as a figure 8 or other complicated shapes.
  • More trains at once:  Further development in hardware would have allowed for more than one train to be running and collisions avoidance would have been interesting.

Conclusion

This project helped understanding about:
  • Power circuitry and isolation of power supplies and reduction of noise
  • Sensors and converting from analog sensing to digital output
  • Precision control of an AC motor
  • Comparison between UART control and push button control
  • Using an LCD to print information
Overall the project brought much personal satisfaction due to the interesting nature of the project.  It allows one to learn about a variety of topics important in today's industries that are not taught at Universities due to their practical nature. One learns many important lessons without realizing they are ding so because they are having so much fun but are kept engaged by complexity of the circuitry.


C-Code Listing


/*
Chad Potocky
Ballard Smith
EE476 Spring 2001
Final Project: Train Controller

This is the code for a train controller which runs a train motor that is connected to an H bridge. The train is run at different speeds using the PWM on timer 1. There are also optical sensors used to indicate the position of the train on the track for speed optimization and lap counting. Finally the output is to a 4x20 LCD panel connected to PORTC.

*/ 
#include <90s8515.h> 
#include <stdio.h> 
#include <string.h> //For UART comparisons 
#include <math.h> //Needed the abs function
#include <delay.h> //Needed delay_ms for ramping

#define t1 60 

#define begin {
#define end }

/* Use an 4x20 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 
*/

#asm
.equ __lcd_port=0x15
#endasm 
#include <lcd.h> // LCD driver routines

//timer 1 constants 
#define prescale1 1 // Sets the timer 1 prescalar to 8
#define t2 20 // Timeout constant for polling the push 
buttons
#define t3 30 // Timeout constant for polling the sensors
#define ptime 100 // Amount of time the button must be pressed 
before changing velocity, in ms
#define senseDelay 60 // Amount of time to wait for sensor 
debouncing = senseDelay * t3

//the subroutines
void task1(void); //test for a UART command, and decode it
void gets_int(void); //starts command from serial line
void initialize(void); //setup the whole process
void press(void); //check for a button press
void velChange(void); //change the velocity
void checkSensor(void); //check if the train has crossed a sensor
void runProg(void); //run a program given over UART
void rampup(void); //ramp the train up to speed
void rampdown(void); //ramp the train down to 0
void rampupcorner(void); //after a corner ramp back up to speed 
before the corner
void rampdowncorner(void); //save speed and ramp down to 60

char lcd_buffer[17]; //Output to the LCD
unsigned char last_forward; //Flag if the train was last going forward
unsigned char last_backward; //Flag if the train was last going 
backward
unsigned char senseDone; //Flag if sensor 0 is done sensing
unsigned char senseDone1; //Flag if sensor 1 is done sensing
unsigned char senseDone2; //Flag if sensor 2 is done sensing
unsigned char senseDone3; //Flag if sensor 3 is done sensing
unsigned char program; //Flag if a program is being run
unsigned char curr_prog; //Index into prog_buffer
unsigned char prog_lap; //Laps left in program
unsigned char prog_buffer[16];//Buffer of commands from a UART program
unsigned char doneLap; //Flag if the train has completed a lap at 
sensor 0
unsigned char doneLap1; //Flag if the train has completed a lap at sensor 1
unsigned char doneLap2; //Flag if the train has completed a lap at sensor 2
unsigned char doneLap3; //Flag if the train has completed a lap at sensor 3
unsigned char lapCount; //Total lap count since last reset
unsigned char addin; //Flag to add or subtract from velocity
unsigned char pressed; //Flag if the button is still pressed
unsigned char presstime; //Counter to see how long a button was 
pressed
int velocity; //Percentage of 1024 to place into OCR1A
int velsave; //Saved velocity when ramped down on curves
int vel; //Used in rampup function
int vel2; //Used in rampupcorner function
unsigned char reload; //timer 0 reload to set 1 mSec
unsigned char time1; //UART command decode timer
unsigned char time2; //Button poll timer 
unsigned char time3; //Sensor poll timer 
//RXC ISR variables 
unsigned char r_busy; //recieve ISR is running
unsigned char r_index; //current string index
unsigned char r_buffer[16]; //input string
unsigned char r_ready; //flag for receive done
unsigned char r_char; //current character

//**********************************************************
//timer 0 overflow ISR
interrupt [TIM0_OVF] void timer0_overflow(void)
begin 

//reload to force 1 mSec overflow
TCNT0=reload;

//Decrement the three times if they are not already zero
if (time1>0) --time1; 
if (time2>0) --time2; 
if (time3>0) --time3;
if ((pressed == 1) && (presstime > 0)) {
--presstime; 
}

end 

//**********************************************************
//UART character-ready ISR
interrupt [UART_RXC] void uart_rec(void)
begin
r_char=UDR; //get a char
UDR=r_char; //then print it
//build the input string
if (r_char != '\r') r_buffer[r_index++]=r_char;
else
begin
putchar('\n'); //use putchar to aoid overwrite
r_buffer[r_index]=0x00; //zero terminate
r_busy=0; //and clean up
r_ready=1; //signal cmd processor
UCR.7=0; //stop rec ISR
end
end

//********************************************************** 
//Entry point and task scheduler loop
void main(void)
begin 
initialize();

//main task scheduler loop -- never exits!
while(1)
begin 
if (time1==0) task1(); //Check UART for a command 
if (time2==0) press(); //Check for a button press
if (time3==0) checkSensor(); //Check for a sensor hit
if (senseDone == 0) doneLap = 1; //If the sensor is done, 
1.8s of 0, then the next hit is a lap
if (senseDone1 == 0) doneLap1 = 1; //If the 
sensor is done, 1.8s of 0, then the next hit is a lap
if (senseDone2 == 0) doneLap2 = 1; //If the sensor is 
done, 1.8s of 0, then the next hit is a lap
if (senseDone3 == 0) doneLap3 = 1; //If the 
sensor is done, 1.8s of 0, then the next hit is a lap
if (presstime==0) velChange(); //If button 
pressed for .1s change velocity
if ((program == 1) && (prog_lap == 0)) runProg(); //If running a program and the lap is 0 run the next command
if (program == 1) { //Output program info if running one
lcd_gotoxy(10,3);
lcd_putsf("Lap ");
sprintf(lcd_buffer,"%-i",prog_lap);
lcd_puts(lcd_buffer);
//Output info to LCD, name of project, lap count, and train direction with speed
lcd_gotoxy(0,0);
lcd_putsf("B&C's Super Train");
lcd_gotoxy(0,1);
lcd_putsf("Lap Count");
lcd_gotoxy(10,1);
sprintf(lcd_buffer,"%-i",lapCount);
lcd_puts(lcd_buffer); 
lcd_gotoxy(10,2);
lcd_putsf("V = "); 
if ((abs(velocity/100)) == 1) {
sprintf(lcd_buffer,"%-i",abs(velocity));
lcd_puts(lcd_buffer);
}else if ((abs(velocity/10)) >= 1) {
lcd_putsf(" ");
sprintf(lcd_buffer,"%-i",abs(velocity));
lcd_puts(lcd_buffer);
}else {
lcd_putsf(" ");
sprintf(lcd_buffer,"%-i",abs(velocity));
lcd_puts(lcd_buffer);
}
end 
end 

/*
Reduces the velocity of the train to 60% before a corner
*/
void rampdowncorner(void){
vel2 = 10.24 * 60;
while (OCR1A > vel2) {
OCR1A--;
}

/*
Increases the velocity of the train after a corner to the
velocity it was before the rampdowncorner
*/
void rampupcorner(void){
vel2 = 10.24*(abs(velsave));
while (OCR1A < vel2) {
OCR1A--;
}
}

/*
Slowly decreases the velocity of the train to 0,
gives the train intertia
*/
void rampdown(void) {
while (OCR1A > 0) {
OCR1A--; 
delay_ms(1.5);
}

/*
Slowly increases the velocity of the train to the desired velocity,
gives the train intertia
*/
void rampup() { 
vel = 10.24 * abs(velocity);
while (OCR1A < vel) {
OCR1A++; 
delay_ms(1.5);
}
}

/***************************************************
* Run the given program
*/ 
void runProg(void) { 
//program is done
if (curr_prog >= 16)
program = 0; 
//program is done so stop
else if (prog_buffer[curr_prog] == 0) {
program = 0;
rampdown(); 
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Stop"); 
lcd_gotoxy(0,3);
lcd_putsf(" ");
TCCR1A = 0x00; //Set PWM on and to toggle OC1A pin
TCCR1B = 0x00;
OCR1A = 0;
velocity = 0;
curr_prog = 0;
last_backward = 0;
last_forward = 0;
//program says to go forward
}else if ((char)prog_buffer[curr_prog] == 'f') {
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Forward"); 
if (last_backward == 1) rampdown();
PORTD.6 = 1;
TCCR1A = 0x83; //Set PWM on and to toggle OC1A pin
TCCR1B = 0x03;
prog_lap = prog_buffer[curr_prog + 1] - 48;
velocity = 100; 
rampup(); 
OCR1A = 10.24 * abs(velocity);
velsave = 100;
rampdowncorner();
velocity = 60;
curr_prog = curr_prog + 3;
last_backward = 0;
last_forward = 1;
//program says to go backward
else if ((char)prog_buffer[curr_prog] == 'b') {
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Backward");
if (last_forward == 1) rampdown();
PORTD.6 = 0;
TCCR1A = 0x83; //Set PWM on and to toggle OC1A pin
TCCR1B = 0x03;
prog_lap = prog_buffer[curr_prog + 1] - 48; 
velocity = -100; 
rampup();
OCR1A = 10.24 * abs(velocity);
velsave = -100;
rampdowncorner();
velocity = -60;
curr_prog = curr_prog + 3;
last_backward = 1;
last_forward = 0;
}
}

//********************************************************** 
//Task 1 -- detect a pusbutton
void task1(void) 
begin
int i;
time1=t1; //reset the task timer 
//PORTD.5 = PWM, PORTD.6=F/R 
//train is going backward
if ((program == 0) && r_ready && (strcmpf(r_buffer,"f")==0))
begin 
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Forward"); 
if (last_backward == 1) rampdown();
PORTD.6 = 1;
TCCR1A = 0x83; //Set PWM on and to toggle OC1A pin
TCCR1B = 0x03; 
rampup();
last_backward = 0;
last_forward = 1; 
velocity = abs(velocity);
end 

//train is going backward
if ((program == 0) && r_ready && (strcmpf(r_buffer,"b")==0)) 
begin
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Backward");
if (last_forward == 1) rampdown();
PORTD.6 = 0;
TCCR1A = 0x83; //Set PWM on and to toggle OC1A pin
TCCR1B = 0x03; 
rampup();
last_backward = 1;
last_forward = 0; 
velocity = -abs(velocity);
end 

//Stop the train, turn off PWM
if (r_ready && (strcmpf(r_buffer,"s")==0)) 
begin
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Stop"); 
rampdown();
PORTD.6 = 0;
PORTD.5 = 0; 
TCCR1A = 0x00;
TCCR1B = 0x00;
program = 0; 
velocity = 0; 
last_backward = 0;
last_forward = 0;
end 

//Detect a given program, set the program flags and fill the program buffer
if ((program == 0) && r_ready && ((char)r_buffer[0] == 'p')) {
lcd_gotoxy(0,3); 
lcd_putsf(" ");
lcd_gotoxy(0,3); 
lcd_putsf("Program");
for (i = 0; i<=13; i++) {

prog_buffer[i] = r_buffer[i+2];
}
PORTD.6 = 0;
PORTD.5 = 0;
program = 1; 
prog_lap = 0; 
curr_prog = 0;
}



//get another serial cmd 
if (r_ready ){
gets_int(); 
}
end 

//********************************************************** 
//Detect a button push on the input and set the button number
void press(void) {
time2 = t2; 
if (program == 0) { 
if ((PINB.0 == 0) && (pressed == 0)) { //Detect button 0 press to increase velocity 
pressed = 1; 
addin = 1; 
presstime = ptime;
}else if ((PINB.1 == 0) && (pressed == 0)) { //Detect button 1 press to decrease velocity
pressed = 1;
addin = 0; 
presstime = ptime;
}else if (PINB.2 == 0){ //Detect button 2 press to stop
pressed = 0;
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Stop"); 
rampdown();
PORTD.6 = 0;
PORTD.5 = 0; 
TCCR1A = 0x00;
TCCR1B = 0x00;
program = 0; 
velocity = 0; 
last_backward = 0;
last_forward = 0;
}else if (PINB.3 == 0){ //Detect button 3 press to go forward
pressed == 0;
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Forward"); 
if (last_backward == 1) rampdown();
PORTD.6 = 1;
TCCR1A = 0x83; //Set PWM on and to toggle OC1A pin
TCCR1B = 0x03; 
rampup();
last_backward = 0;
last_forward = 1; 
velocity = abs(velocity); 
}else if (PINB.4 == 0){ //Detect button 4 press to go backward
pressed == 0;
lcd_gotoxy(0,2); 
lcd_putsf(" ");
lcd_gotoxy(0,2); 
lcd_putsf("Backward"); 
if (last_forward == 1) rampdown();
PORTD.6 = 0;
TCCR1A = 0x83; //Set PWM on and to toggle OC1A pin
TCCR1B = 0x03; 
rampup();
last_backward = 1;
last_forward = 0; 
velocity = -abs(velocity); 
} else if ((PINB.0 == 1) && (PINB.1 == 1)) pressed = 0; //If button 0 and 1 are not pressed reset pressed flag
}
/**************************************************************
* Check if the sensors are being hit
*/ 
void checkSensor(void) {
time3 = t3; 
if ((PINA.0 == 1) && (doneLap == 1)) { //Sensor 0 being hit and counting lap 
lapCount++; 
if (program == 1) prog_lap--;
if ((last_forward == 1) && (abs(velocity) > 60)) {
velsave = velocity;
rampdowncorner(); 
velocity = 60;
}else if ((last_backward == 1) && (abs(velsave) > 60)){
rampupcorner(); 
velocity = velsave;
}
doneLap = 0; 
senseDone = senseDelay;
}else if (PINA.0 == 1) //Sensor 0 being hit within 1.8s 
of another sensor hit
senseDone = senseDelay;
else if ((PINA.0 == 0) && (senseDone > 0)) //Sensor 0 not being hit, decrement senseTime
senseDone--;

if ((PINA.1 == 1) && (doneLap1 == 1)) { //Sensor 1 being hit and counting lap
if ((last_forward == 1) && (abs(velsave) > 60)) {
rampupcorner();
velocity = velsave;
}else if ((last_backward == 1) && (abs(velocity) > 60)){
velsave = velocity;
rampdowncorner(); 
velocity = -60;
}
doneLap1 = 0; 
senseDone1 = senseDelay;
}else if (PINA.1 == 1) //Sensor 1 being hit within 1.8s of another sensor hit
senseDone1 = senseDelay;
else if ((PINA.1 == 0) && (senseDone1 > 0)) //Sensor 1 not being hit, decrement senseTime
senseDone1--;

if ((PINA.2 == 1) && (doneLap2 == 1)) { //Sensor 2 being hit and counting lap
if ((last_forward == 1) && (abs(velocity) > 60)){
velsave = velocity;
rampdowncorner(); 
velocity = 60;
}else if ((last_backward == 1) && (abs(velsave) > 60)) {
rampupcorner(); 
velocity = velsave;
}
doneLap2 = 0; 
senseDone2 = senseDelay;
}else if (PINA.2 == 1) //Sensor 2 being hit 
within 1.8s of another sensor hit
senseDone2 = senseDelay;
else if ((PINA.2 == 0) && (senseDone2 > 0)) //Sensor 2 not being hit, decrement senseTime
senseDone2--;

if ((PINA.3 == 1) && (doneLap3 == 1)) { //Sensor 3 being hit and counting lap 
if ((last_forward == 1) && (abs(velsave) > 60)){
rampupcorner(); 
velocity = velsave;
}else if ((last_backward == 1) && (abs(velocity) > 60)) {
velsave = velocity;
rampdowncorner(); 
velocity = -60;
}
doneLap3 = 0; 
senseDone3 = senseDelay; //Sensor 3 being hit within 1.8s of another sensor hit
}else if (PINA.3 == 1)
senseDone3 = senseDelay;
else if ((PINA.3 == 0) && (senseDone3 > 0)) //Sensor 3 being hit and counting lap
senseDone3--;

}

//********************************************************** 
// Button 0 was pressed
void velChange(void) {
int temp;
presstime = ptime; 
if ((addin == 1) && (velocity < 100))
velocity = velocity + 5;
else if ((addin == 0) && (velocity > -100))
velocity = velocity - 5; //Increment or Decrement the set speed

lcd_gotoxy(0,2);

//If the velocity has changed positive to negative, or negative to positive
//switch directions on the train
if (velocity < 0) {
lcd_putsf("Backward");
PORTD.6 = 0;
}else{ 
lcd_putsf("Forward");
PORTD.6 = 1;
}

OCR1A = 10.24 * abs(velocity);


//********************************************************** 
// -- non-blocking keyboard check initializes ISR-driven
// receive. This routine merely sets up the ISR, which then
//does all the work of getting a command.
void gets_int(void) 
begin 
int x;
for (x = 0; x<16; x++)
r_buffer[x] = 0;
r_busy=1; 
r_ready=0;
r_index=0;
UCR.7=1;
end

//********************************************************** 
//Set it all up
void initialize(void)
begin 
//set up the ports
DDRA=0xf0; // PORT A is an input for sensors
PORTA = 0xff;
DDRD=0xe7; // PORT D is motor control 
PORTD = 0xff;
DDRC=0xff; // PORT C is an ouput 
DDRB=0x00; //PORT B is an output for leds
PORTB = 0xff;
PORTC=0; 
PORTB=0xf2; //all LEDs off and transistors off

//serial setup for commands. 
UCR = 0x18 ;
UBRR = 25 ; 

//set up timer 0 
//62.5 x (64x.25) microSec = 1.0 mSec, so prescale 64, and count 62 times.
reload=256-62; //value for 1 Msec 
TCNT0=reload; //preload timer 1 so that is interrupts after 1 mSec.
TCCR0=3; //prescalar to 64
TIMSK=2; //turn on timer 0 overflow ISR 

//set up timer 1
OCR1A = 512; //disable timer 1 until song starts 
velocity = 0;
TCNT1 = 0; //and zero the timer 
TCCR1A = 0x00; //Turn off timer 1 until needed
TCCR1B = 0x00;
PORTD.5 = 0; //Turn train off 
PORTD.6 = 0; //Turn train off
OCR1A = 0; //zero compare register

//initialize button press variables 
pressed = 0; 
presstime = ptime; 

//initialize lap count and sensor variables
lapCount = 0;
senseDone = 0;
doneLap = 0; 
senseDone1 = 0;
doneLap1 = 0;
senseDone2 = 0;
doneLap2 = 0;
senseDone3 = 0;
doneLap3 = 0;

//initialize program variables
program = 0;
prog_lap = 0; 
curr_prog = 0;

//init the task timers
time1=t1; 
time2=t2; 
time3 = t3;

putsf("\r\nStart\r\n"); 

// initialize the LCD for 16 char wide
lcd_init(20); 
// clear it
lcd_clear(); 
lcd_gotoxy(0,2); 
//Initially in the stop state.
lcd_putsf("Stop");
//crank up the ISRs
#asm
sei
#endasm 
gets_int();
end



Schematics

For a detailed description of what each circuit, please visit the Hardware page.
Figure 10: Top level Design showing the Atmel 90s8515 and pin connections

Figure 11: Control logic for the H-Bridge

Figure 12: H-bridge Motor controller

Figure 13: Optical Sensors using IR LED's and Photo-transistors





0 comments:

Post a Comment

Share your knowledge

Related Posts Plugin for WordPress, Blogger...

Popular Projects

program for Dual DAC 8051 Microcontroller Based DC Motor Control A Microcontroller Based Turbidity Meter A m -Controller Based Thermostat ASCII to BCD conversion in 8051 AT90LS8515 Digital Message Machine Audio Frequency Response Analyzer Audio Homing Robot Automated Juice Mixer Automated Pet Feeder Autonomous Car Autonomous Parallel Parking RC Car Autonomous Search Robot Autonomous Tank Autonomous Vehicle Contrast Following Rover Autonomous navigating robot BCD number to ASCII in 8051 Balance Bot Blind Bot Blood Pressure Monitor Bloodshed Dev-C++ 5 Compiler/IDE Breath Alcohol Tester Converters on TI MSP430 CrossStudio MSP430 IDE Design of a Real-Time Digital Guitar Tuner Digital Oscilloscope Digital Stethoscope Digital clock project using PIC16C54A microcontroller Digital thermometer ECG monitoring system GPS Data Logger with Wireless Trigger Handwriting Recognition Systm Home Security System Home energy managment IAR Embedded Workbench IDE INFRARED TRACKING SYSTEM IntelliBOT Laser Communications System Line following van MSP-EXP430FG4618 Development Tool and the eZ430 kits MSP430FG4618 device implement a Buzzer tone generator MSP430FG4618 device implement a Real Time Clock MSP430FG4618 device implement a voltage ramp generator MSP430FG4618 device present a message on the LCD Basic Microcontroller(8051) Lab Mivo- RFID based mobile payment system Multi-Zone Fire Alarm System PC based temperature control PIC 16f877 RPM Meter PIC16C54 dual dice electronic project circuit PIC16F84A digital thermometer microcontroller project PIC16F886 horn driver PWM motor contoller with MSP430 Program Block data transfer in 8051 Program to add two BCD numbers in 8051 Program to check whether a 4th bit of a byte is 1 Program to convert ASCII to hex in 8051 Program to count from 0-9 in 8051 Program to count number of 1's in a given data byte in 8051 Program to divide an 8 bit no by another 8 bit number in 8051 Program to find largest of n numbers in 8051 Program to find the LCM of two numbers in 8051 Program to find the square of an 8 bit number in 8051 Program to generate 50msec delay in 8051 Program to implement BCD counter to count from 0-99 in 8051 Program to implement BCD counter to count from 99-0 in 8051 Program to interchange two blocks of data in 8051 Program to multiply 16 bit number by 8 bit number in 8051 Program to search an element in an array in 8051 Program to sort an array of 10 elements in 8051 Programming the ez430 Proximity Security System RAMP wave in 8051 RC Car Controller RObo Dog Radio-controlled Truck Retina color tracker Robotic Arm Controller with GUI Robotic Car Traction Control Safety-sensor vehicle Security Entrance System Self-Powered Solar Data Logger Snake Arm Ultrasonic Positioning Control System Store FFh if 1 Super Train Controller TI MSP430 Microcontrollers Timers on the MSP430 TouchPad Drawing Board Ultra-Sonic Parking Assistant Ultrasonic Parking Controller Ultrasonic Range finder Voice Activated Alarm Clock Voice Recognition Robotic Car Voting Machine Weather Station Web-Monitored Thermostat Wireless Drawing Device Wireless Telemetry Wireless message Communicator Write a C program to display the code of the key pressed in 8051 Zigbee Wireless Relay Control and Power Monitoring System add two multibyte numbers in 8051 convert a decimal number to hex number in 8051 convert an 8bit Hex number to decimal number in 8051 convert hex number to ASCII number in 8051 eZ430-F2013 Development Tool use SD16_A ADC eZ430-RF2500 Development Tool use ADC10 else store 00 in the same location in 8051 find the GCF of two numbers in 8051 find the average of 10 numbers in 8051 generate Fibonacci series in 8051 metal detector project microcontroller using IAR Embedded Workbench program for Elevator Interface in 8051 program for Stepper motor interface in 8051 spectrum analyser square wave in 8051 triangle wave in 8051 voice recognition security system

Sites U missed

Hint

Open Pictures in new page by right click on it, if it is not shown full image.