Beruflich Dokumente
Kultur Dokumente
1. The first thing you need to know about the general purpose timers in a microcontroller is that they
are very, very flexible peripherals and can often be used in up to dozens of different ways.
However, as we saw in the lecture video, essentially, all the timers do is count.
It is tempting to want to dive into the general purpose timer peripheral (or any peripheral for that
matter) and try to learn everything possible about it. However, I strongly recommend against it.
These peripherals have so many different features, you could spend 6 months (or more!) learning
all of their finer points.
Our goal here is to teach you how to use the general purpose timer in its most commonly used
mode of operation - UP mode. UP mode is probably sufficient for 95% of the developers, 95% of
the time.
2. Timer_A is a 16-bit general purpose timer on the MSP430FR6989. This means that it can count
from 0x0000 up to 0xFFFF (or 0 to 65,535 decimal). There are actually several Timer_A
peripherals on our microcontroller, but the first one we will look at will be Timer_A0. We will
look at some of the other Timer_A peripherals in a later section.
3. Timer_A0 is primarily controlled by a register called the Timer A0 ConTroL (or TA0CTL)
register. Again, you can think of it as a box holding 16 bins (or bits).
By manipulating the bits in the Timer A0 ConTroL register, we can put the timer into UP mode
and specify how long we want it to count.
6. To specify how fast the timer will count, we will also make the TASSEL bits 01B. This tells the
counter to use something called the Auxiliary CLocK (ACLK) as its timing source.
Think of the ACLK like this. If you are measuring time with a regular clock, it will update (or
increment) once every second. With the ACLK timing source, your Timer_A0 peripheral will be
counting (or incrementing) approximately once every 25 microseconds (or 25s). There are other
clock sources available for the general purpose timer, but the ACLK is sufficient for our needs.
#define ACLK 0x0100 // That is: 0000 0001 0000 0000 binary
8. Now that we have told the timer we want it to count UP and how fast we want it to count, about
the only thing left to do is tell the peripheral how high to count. This is done with the Timer_A0
Capture/Compare Register 0 (or TA0CCR0).
There are a lot of different ways that this register can be used, but in the UP mode that we are
using, the peripheral is going to compare its count value to the number you store in TA0CCR0.
For now, we are going to load a value of 20,000 decimal into TA0CCRO. This will cause your
timer to count for approximately 0.5 seconds.
When you count up to TA0CCR0, the peripheral will alert you that it has completed its task.
#include <msp430.h>
main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
while(1)
{
if(TA0CTL & TAIFG) // IF timer has counted to 20000
{
P1OUT ^= RED_LED; // Then, toggle red P1.0 LED
TA0CTL &= ~TAIFG; // Count again
}
}
}
10. Notice, we have added a while(1) loop at the end of the program. We have omitted the
instructions in the loop, but we have added some comments that we will talk through first before
adding the C code.
11. The program begins by disabling the watchdog timer and enabling the input and output pins.
Next, the timer has been started and is counting up from 0 to 20,000 in 25s steps.
Finally, we have made sure that the pin connected to the Launchpads red LED (P1.0) is
configured as an output.
To do this, the program needs to check to see if the Timer_A Interrupt FlaG has moved from LO to
HI.
13. We check to see if the TAIFG bit is HI with the following if statement:
The if instruction begins by taking the bit-wise logic-AND of the contents of the Timer_A0
ConTroL register (TA0CTL) and TAIFG (which we defined as 0x0001).
Since anything ANDed with a 0 is also a 0, the first 15-bits of the result (bits 1-15) will all be LO.
The only bit in the result that may not be LO is bit 0. It all depends on the value of the TAIFG bit
in the TA0CTL register.
If the TAIFG bit in the TA0CTL register is LO, the peripheral has not counted up to 20,000 yet, and
the result of the bit-wise AND will be 0x0000. The if statement will NOT be true.
If the TAIFG bit in the TA0CTL register is HI, the peripheral has counted up to 20,000, and the
result of the bit-wise AND will be 0x0001. The if statement WILL be true. Execution will
continue into the if statement.
while(1)
{
if(TA0CTL & TAIFG) // IF timer has counted to 20000
{
P1OUT ^= RED_LED // Then, toggle red P1.0 LED
TA0CTL &= ~TAIFG; // Count again
}
}
16. Once we have determined that the peripheral has counted to 20,000, we want to toggle the P1.0
red LED and ensure the timer keeps counting. We do this with two separate instructions. The
following instruction toggles the P1.0 red LED.
This is taking the bit-wise exclusive OR (XOR) of the contents of the P1OUT register and the value
defined as RED_LED (0x01). Recalling how the XOR operator works, anything XORed with a 0
stays the same. Anything XORed with a 1 changes. Therefore, since RED_LED was defined as
00000001B, this instruction will toggle bit 0 of P1OUT.
Next, the program takes the bitwise-AND of the contents of the TA0CTL register with the inverted
TAIFG value. The result is stored back in the TA0CTL register.
As we have seen in our previous handouts, this will clear the TAIFG bit in the TA0CTL register.
This allows the program to return to the if statement and continue checking the general purpose
timer peripheral to see if it has reached 20,000 again.
#include <msp430.h>
main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
while(1)
{
if(TA0CTL & TAIFG) // If timer has counted to 20000
{
P1OUT = P1OUT ^ RED_LED; // Then, toggle red P1.0 LED
TA0CTL = TA0CTL & (~TAIFG); // Count again
}
}
}
19. Create a new CCS project called Timer_Up_Mode. Copy the program from above into your new
projects main.c file.
21. When you are ready, click Debug and run your program. The LED should be blinking. It will be
on for approximately 0.5 seconds and then off for approximately 0.5 seconds before the cycle
repeats.
23. Now is probably a good time to look back at the program and reflect on the #define instructions
we used.
Some new programmers want to skip using the #define instructions, and end up creating
something that looks like this:
#include <msp430.h>
main()
{
WDTCTL = 0x5A80; // Stop the watchdog timer
PM5CTL0 = 0xFFFE; // Enable inputs and outputs
while(1)
{
if(TA0CTL & 0x0001) // If timer has counted to 20000
{
P1OUT = P1OUT ^ 0x01; // Then, toggle red P1.0 LED
TA0CTL = TA0CTL & 0xFFFE; // Count again
}
}
}
This program operates exactly like the earlier version of the program. For some people, it may
even be faster to type your programs this way. However, most developers use the #define
instructions to make their code easier to read, both while they are writing it and later when they
have to go back and read it.
If you want to, go ahead and copy this version of the program into your new main.c file to try it
out. You can go ahead and Save, Build, Debug and run the program to verify it works if you
want. However, we will continue to use #define to (hopefully) make these tutorials easier to
read.
Now the program will count up from 0 to 5000 (instead of 20000) before toggling the red LED.
This will cause the LED to blink 4 times faster.
#include <msp430.h>
main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
while(1)
{
if(TA0CTL & TAIFG) // If timer has counted to 20000
{
P1OUT = P1OUT ^ RED_LED; // Then, toggle red P1.0 LED
TA0CTL = TA0CTL & (~TAIFG); // Count again
}
}
}
25. Save, Build, Debug, and run your program when ready to verify that the LED is blinking faster.
Click Terminate when you are ready to return to the CCS Editor.
Lets try that out. Copy the code below into your main.c file. Save, Build, Debug, and run your
program when ready to verify that the LED is blinking slower. Click Terminate when you are
ready to return to the CCS Editor.
#include <msp430.h>
main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
while(1)
{
if(TA0CTL & TAIFG) // If timer has counted to 20000
{
P1OUT = P1OUT ^ RED_LED; // Then, toggle red P1.0 LED
TA0CTL = TA0CTL & (~TAIFG); // Count again
}
}
}
Copy the code below into your main.c file. Save, Build, Debug, and run your program when
you are ready
#include <msp430.h>
main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs
while(1)
{
if(TA0CTL & TAIFG) // If timer has counted to 20000
{
P1OUT = P1OUT ^ RED_LED; // Then, toggle red P1.0 LED
TA0CTL = TA0CTL & (~TAIFG); // Count again
}
}
}
This is one of the reasons that many programmers dont like the C programming language. It
allows you to do things that probably dont make sense.
When you run the program, it is blinking relatively quickly much faster than when we loaded
65,535 into TA0CCR0. In fact, it is blinking at almost the same rate as when we loaded 5,000 into
the register.
This is because of how C program builds its programs from your instructions. When it gets to an
instruction like load 70,000 into a 16-bit register that can only hold numbers up to 65,535 it
does the best job that it can.
You can think of it this way. It starts loading the 70,000 into the register, but when it gets to
65,535, the register is full. When it tries to load a higher number, the value in the register rolls-
over to 0 decimal and starts incrementing again. Therefore, when you tried to load 70,000 into
the register, you actually end up loading:
Similarly, if you try to load 135,535 into TA0CCR0, the value would roll-over twice, and you
would also have a final value of 4,465:
Click Terminate when you are ready to return to the CCS Editor.
Take a look at the program below. It counts up to 500,000 by counting up to 50,000 ten times
(using a variable called intervals). Every time TAIFG goes HI, we add one to intervals.
When intervals reaches 10, we toggle the red LED and reset intervals back to 0 to start the
process over.
Create a CCS project called Timer_Up_Long and copy the program into the main.c file. Save,
Build, Debug, and run the program to verify it works.
#include <msp430.h>
main()
{
unsigned char intervals=0; // Count number of 50,000 counts
while(1)
{
if(TA0CTL & TAIFG) // If timer has counted to 50,000
{
intervals = intervals + 1; // Update number of 50,000 counts
TA0CTL = TA0CTL & (~TAIFG); // Count again
31. Alright, heres one more challenge. Can you create a new CCS project called Timer_Up_31Split
that turns on the red LED for 3 seconds and then turns off the red LED for 1 second before
repeating?
In no event shall the owner or contributors to the tutorials and software be liable
for any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services; loss of
use, data, or profits; or business interruption) however caused and on any theory
of liability, whether in contract, strict liability, or tort (including negligence or
otherwise) arising in any way out of the use of this software, even if advised of
the possibility of such damage.