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 Pin | LCD pin | Functionality |
Ground | 1 | Ground |
Vcc | 2 | Power |
N/C | 3 | Contrast |
PC0 | 4 | RS |
PC1 | 5 | RD |
PC2 | 6 | Enable |
PC3 | 11 | D4 |
PC5 | 12 | D5 |
PC6 | 13 | D6 |
PC7 | 14 | D7 |
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
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