分类:
2009-06-29 21:42:37
The program below should keep printing the character A to the serial port forever. There is, however, one piece missing: the baud rate still needs to be set. Look through your book and figure out what settings are needed to set the baud rate to 9600 bps. An important bit of information: the robots' MCUs have a crystal frequency of 8 MHz; this allows the clock speed to operate at 2 MHz. In particular, you should refer to Tables 9-1 and 9-2 in the HC11 Reference Manual.
When you think you have it right, run minicom to communicate with the serial port on the computer. No configuration should be necessary, but if it is, configure it to use the following settings:
Bits per second: 9600 Data bits: 8 Parity: none Stop bits: 1 Flow control: off
Once minicom is running and you have the robot connected and you have uploaded your program, you can start the program on the robot. If everything goes as planned, the screen should fill with As.
minicom uses Emacs-like commands. To quit, type C-a q, then press Enter to confirm. Type C-a z for some very basic usage information.
void pc (char c) { volatile char *scsr = (char*) 0x102e; volatile char *scdr = (char*) 0x102f; /* Wait until the serial port is available for sending data */ while (!(*scsr & 0x80)); /* Send the data */ *scdr = c; } int main (void) { /* notice the volatile keyword on these variables. This tells the C compiler that other things besides your program may be changing its value so not to perform optimizations that assume it stays the same. */ /* pointer to the baud control register locate at memory address 0x102B*/ unsigned volatile char * baud = (unsigned volatile char *)0x102B; /* pointer to serial communication control register 1 */ unsigned volatile char * sccr1 = (unsigned volatile char *)0x102C; /* pointer to serial communication control register 2 */ unsigned volatile char * sccr2 = (unsigned volatile char *)0x102D; /* pointer to serial communication status register */ unsigned volatile char * scsr = (unsigned volatile char *)0x102E; /* pointer to serial communication data register */ unsigned volatile char * scdr = (unsigned volatile char *)0x102F; // Initialize serial *baud = // ? figure out this setting *sccr1 = 0; // 1 start bit, 8 data bits, 1 stop bit *sccr2 = 0x0C; // enable transmit and recieve // end initialization while(1) { pc('A'); } return 0; }
Now take a look at the printString () function you wrote many labs ago (remember that?). Notice how you used to use the print_char () function to print each character. You'll need to modify the routine to print over the serial line instead.
Note that the initialization of the serial port only needs to be performed once. Therefore, you should make a new function, serial_init (), to initialize the serial port. You need to call this function before using the serial port for communication.
Once you have done this, try using your new printString () function to print something over the serial port to the terminal.
Remember, you can use your old routines, like printHex (), printBinary (), printUnsignedDec (), and printSignedDec () to print debugging information from the robot. You'll find that debugging becomes much easier while using the serial port.
The TA will:
looking back on the previous lab you will remember how we had to use long variable declarations such as
unsigned volatile char * sccr1 = (unsigned volatile char *)0x102C;
and then access them as follows
*sccr1 = 0;
#define SCCR1 *((unsigned volatile char *)0x102C)
Everywhere you type SCCR1, the compiler will replace it with *((unsigned volatile char *)0x102C). To read from or write to SCCR1 you just use it like you would a normal character. so to set it to 10 you would use SCCR1 = 10;. If you take a look at the file portsio.h then you will see that we have defined most of the ports and bits for all the registers that will be used in these labs all you have to do is include that file in all the files where you use the macros. As you can see in the example below it makes the code much cleaner and easier to read. Most of the register macros are named exactly the same as the registers are in your book. Also note that macros in C are traditionally all capital letters so that you can tell them apart from other parts of the code
Below is a program that reads the input from the buttons using the analog to digital converter. once the conversion is done the result is stored in the BUTTONS register. use your printUnsignedDecimal function to print out the conversion values for when the buttons are pressed. Once you have the robot printing values out over the serial line then record the values for all possible combinations of button presses
#include "portsio.h" int main () { /* Enable analog to digital converter by setting the ADPU bit in the OPTION register */ OPTION |= ADPU; char result; while(1) { ADCTL = 0; // writing to the analog to digital contol register signals the AD converter to start its conversion. // once the conversion is finished then the CCF bit in the analog to digital control register will be set. while(!(ADCTL & CCF)); // wait until conversion is finished result = BUTTONS; // BUTTONS is the register where the output of the conversion is stored // print out the results } return 0; }
Program should print number read from button a/d and also name the combination. Good solutions are not brittle. README should indicate how their button identification algorithm was desginged and how they picked any threshold values.
more comments, FLIP all LED bits
.sect text .globl main ldd 0x100E ; load current timer count TCNT addd 40000 ; 20ms = 40000 cycles std 0x1018 ; store new time into output compare register OC2 ldd ledHandler std 0xFFE6 ; set OC2 Interrupt Vector ldaa 0x40 ; enable OC2 interrupts staa 0x1022 ; enable interrupts cli .globl ledHandler ; toggle led ldaa 0x1000 eora 0x20 staa 0x1000 ldd 0x1018 ; load current output compare count 0C2 addd 40000 ; 20ms = 40000 cycles std 0x1018 ; store new time into output compare register OC2 ldaa 0x40 staa 0x1023 ; this is an interrupt subroutine so we use rti instead of rts rti
Modify the program above so that the LED is toggled once every second.
The timer is a 16-bit number which is too small to count the 2 million cycles needed for 1 second. You will need to count how many times the interrupt handler routine is called and only toggle the led at the appropriate count
Make new lab with enumerated speed: fwd_slow, rev_slow, fwd_nor, rev_nor, rot_right, rot_left
In the example only one of the motors is running. Modify the example so that both motors are running in the same direction with the same speed. Remember that the motors are hooked up in opposite directions so you will have to send different signals to each motor to have them go the same direction. You can do this using only one interrupt handler, counting cycles and having a time variable for each motor.
#include "ioports.h" static inline void cli(void) /* clear interrupts */ { /* the __asm__ instructions is not C code but is a compiler directive for Gcc (the compiler that you are using) that * allows you to insert assembly code directly into your C code. */ __asm__ __volatile__ ("cli"); } /* note interrupt attribute!! this tells the compiler to use an rti insted of rts when returning from the function*/ void interruptHandler (void) __attribute__((interrupt)); long elapsedCycles; short leftOnCycles = 5000; short leftOffCycles = 35000; long leftExpired; long nextInterrupt; void interruptHandler() { elapsedCycles += nextInterrupt; nextInterrupt = 64000; /* 64000 is the max time we will be using between interrupts*/ /* check if it is time to switch pulse state*/ if(leftExpired <= elapsedCycles) { PORTA ^= LMOT; if(PORTA & LMOT) { leftExpired = elapsedCycles + leftOnCycles; } else { leftExpired = elapsedCycles + leftOffCycles; } } /* if this is the soonest and is less than the max time timer value * then use it as the next interrupt time */ long timeLeft = leftExpired - elapsedCycles; if(timeLeft < nextInterrupt) { nextInterrupt = timeLeft; } /* set the time of the next interrupt*/ TOC2 = TOC2 + nextInterrupt; /* clear the output compare 2 interrupt flag to allow more interrupts to occur*/ TFLG1 |= OC2F; } int main (void) { elapsedCycles = 0; leftExpired = 0; nextInterrupt = 2000; /* the first interrupt will occur after 1mx */ /* Set bi-directional port to output (For right motor) */ PACTL |= DDRA7; /* set the interrupt vector to the address of our interrupt handler function */ OC2_VECTOR = (unsigned short)interruptHandler; /* set the first interrupt to occur in 1ms*/ TOC2 = TCNT + nextInterrupt; /* set output compare 2 to generate interrupts */ TMSK1 |= OC2I; cli(); /* clear the global interrupt flag to allow interrupts to occur*/ return 0; }
Use your knowledge of how the buttons work on the robots and your knowledge of interrupts to write an interrupt handler that checks the buttons every second and prints out over the serial line the name or names of which button or buttons were pressed.