Sie sind auf Seite 1von 18

How Do I Use the MSP430FR6989 General Purpose Timer?

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.

Copyright 2012-2015 Page 1 of 18


Valparaiso University
4. Below, we list the TA0CTL bits that we will be using, their code names, and their assigned
functions.

Bits 0 Timer_A Interrupt FlaG (TAIFG)


This bit will go HI when the timer has counted up to its specified value.
It will remain LO if the timer has not finished counting yet.

Bit 4 - 5 Mode Control (MC)


These two bits are used to put the peripheral into UP mode. This allows
the peripheral to count up from 0 to a value you will choose.

Bits 8 - 9 Timer A Source SELect (TASSEL)


These two bits are used to specify how fast we want the timer to count.

Copyright 2012-2015 Page 2 of 18


Valparaiso University
5. To put the Timer_A0 peripheral into UP mode, we make the MC bits 01B.

We will do this with the following #define statement:

#define UP 0x0010 // That is: 0000 0000 0001 0000 binary

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

Copyright 2012-2015 Page 3 of 18


Valparaiso University
7. We can now use our two #define statements to setup and start the Timer_A0 peripheral
counting:

TA0CTL = ACLK | UP; // Takes the logic OR of 0x0100 and 0x0010


// and stores the result in TA0CTL
// When complete, TA0CTL = 0x0110

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.

TA0CCR0 = 20000 // Count for 20,000 x 25microseconds


// (20000)(25us) = 0.5 seconds

Copyright 2012-2015 Page 4 of 18


Valparaiso University
9. Now that we know how to set up the general purpose timer peripheral, let us add some additional
instructions to stop the watchdog and configure the P1.0 LED.

#include <msp430.h>

#define RED_LED 0x0001 // P1.0 is the Red LED


#define DEVELOPMENT 0x5A80 // Stop the watchdog timer
#define ENABLE_PINS 0xFFFE // Required to use inputs and outputs
#define ACLK 0x0100 // Timer_A ACLK source
#define UP 0x0010 // Timer_A UP mode
#define TAIFG 0x0001 // Used to look at the Timer A Interrupt FlaG

main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs

TA0CCR0 = 20000; // We will count up from 0 to 20000


TA0CTL = ACLK | UP; // Use ACLK, for UP mode

P1DIR = RED_LED; // Set Red LED as an output

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.

Copyright 2012-2015 Page 5 of 18


Valparaiso University
12. Once our program gets into the infinite while loop, we will have it check to see if the general
purpose timer has counted to 20,000.

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:

if(TA0CTL & TAIFG) // Will be TRUE if the TAIFG bit in TA0CTL


// is HI

Copyright 2012-2015 Page 6 of 18


Valparaiso University
14. We have looked at this instruction before, but we will do it one more time to refresh your
memory how this works.

if(TA0CTL & TAIFG) // Will be TRUE if the TAIFG bit in TA0CTL


{ // is HI

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.

Copyright 2012-2015 Page 7 of 18


Valparaiso University
15. Now, let us look at the entire loop.

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.

P1OUT = P1OUT ^ RED_LED; // Then, toggle red P1.0 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.

Copyright 2012-2015 Page 8 of 18


Valparaiso University
17. Next, we need to make sure that the general purpose timer keeps going. This instruction does two
things. First, it takes the bit-wise inverse of our TAIFG value. Since TAIFG was 0x0001, the result
of the inversion becomes 0xFFFE (or 1111111111111110B).

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.

TA0CTL = TA0CTL & (~TAIFG); // Count again

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.

Copyright 2012-2015 Page 9 of 18


Valparaiso University
18. Altogether, the program looks like this:

#include <msp430.h>

#define RED_LED 0x0001 // P1.0 is the Red LED


#define DEVELOPMENT 0x5A80 // Stop the watchdog timer
#define ENABLE_PINS 0xFFFE // Required to use inputs and outputs
#define ACLK 0x0100 // Timer_A ACLK source
#define UP 0x0010 // Timer_A UP mode
#define TAIFG 0x0001 // Used to look at Timer A Interrupt FlaG

main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs

TA0CCR0 = 20000; // We will count up from 0 to 20000


TA0CTL = ACLK | UP; // Use ACLK, for UP mode

P1DIR = RED_LED; // Set red LED as an output

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.

20. Save and Build your project.

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.

Copyright 2012-2015 Page 10 of 18


Valparaiso University
22. When you are ready, click Terminate to return to the CCS Editor.

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

TA0CCR0 = 20000; // We will count up from 0 to 20000


TA0CTL = 0x0110; // Use ACLK, for UP mode

P1DIR = 0x01; // Set red LED as an output

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.

Copyright 2012-2015 Page 11 of 18


Valparaiso University
24. Alright, let us try a few things out with our general purpose timer program. Modify your program
so that you load a value of 5000 into the TA0CCR0 register.

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>

#define RED_LED 0x0001 // P1.0 is the Red LED


#define DEVELOPMENT 0x5A80 // Stop the watchdog timer
#define ENABLE_PINS 0xFFFE // Required to use inputs and outputs
#define ACLK 0x0100 // Timer_A ACLK source
#define UP 0x0010 // Timer_A UP mode
#define TAIFG 0x0001 // Used to look at Timer A Interrupt FlaG

main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs

TA0CCR0 = 5000; // We will count up from 0 to 5000


TA0CTL = ACLK | UP; // Use ACLK, for UP mode

P1DIR = RED_LED; // Set red LED as an output

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.

Copyright 2012-2015 Page 12 of 18


Valparaiso University
26. You can slow down the blinking by making the general purpose timer count to a higher number.
Since the Timer_A0 peripheral is a 16-bit timer, the highest number it can count to is 65,535.

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>

#define RED_LED 0x0001 // P1.0 is the Red LED


#define DEVELOPMENT 0x5A80 // Stop the watchdog timer
#define ENABLE_PINS 0xFFFE // Required to use inputs and outputs
#define ACLK 0x0100 // Timer_A ACLK source
#define UP 0x0010 // Timer_A UP mode
#define TAIFG 0x0001 // Used to look at Timer A Interrupt FlaG

main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs

TA0CCR0 = 65535; // We will count up from 0 to 65535


TA0CTL = ACLK | UP; // Use ACLK, for UP mode

P1DIR = RED_LED; // Set red LED as an output

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
}
}
}

Copyright 2012-2015 Page 13 of 18


Valparaiso University
27. What happens if you try to load a number into TA0CCR0 that is too big? Lets try it with 70,000
and see.

Copy the code below into your main.c file. Save, Build, Debug, and run your program when
you are ready

#include <msp430.h>

#define RED_LED 0x0001 // P1.0 is the Red LED


#define DEVELOPMENT 0x5A80 // Stop the watchdog timer
#define ENABLE_PINS 0xFFFE // Required to use inputs and outputs
#define ACLK 0x0100 // Timer_A ACLK source
#define UP 0x0010 // Timer_A UP mode
#define TAIFG 0x0001 // Used to look at Timer A Interrupt FlaG

main()
{
WDTCTL = DEVELOPMENT; // Stop the watchdog timer
PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs

TA0CCR0 = 70000; // We will count up from 0 to 70000


TA0CTL = ACLK | UP; // Use ACLK, for UP mode

P1DIR = RED_LED; // Set red LED as an output

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
}
}
}

Copyright 2012-2015 Page 14 of 18


Valparaiso University
28. What happened? The first thing you may have noticed is that CCS did not give you an error when
you tried to fit 70,000 into the 16-bit register.

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:

70,000 65,535 = 4,465

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:

135,535 65,535 65,535 = 4,465

Click Terminate when you are ready to return to the CCS Editor.

Copyright 2012-2015 Page 15 of 18


Valparaiso University
29. So, if we can only count up to 65,535 with a 16-bit timer, how do we count for longer period of
time? The answer is that you write a program to count to 65,535 multiple times.

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>

#define RED_LED 0x0001 // P1.0 is the red LED


#define DEVELOPMENT 0x5A80 // Stop the watchdog timer
#define ENABLE_PINS 0xFFFE // Required to use inputs and outputs
#define ACLK 0x0100 // Timer_A ACLK source
#define UP 0x0010 // Timer_A UP mode
#define TAIFG 0x0001 // Used to look at Timer A Interrupt FlaG

main()
{
unsigned char intervals=0; // Count number of 50,000 counts

WDTCTL = DEVELOPMENT; // Stop the watchdog timer


PM5CTL0 = ENABLE_PINS; // Enable inputs and outputs

TA0CCR0 = 50000; // We will count up from 0 to 50,000


TA0CTL = ACLK | UP; // Use ACLK, for UP mode

P1DIR = RED_LED; // Set red LED as an output

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

if (intervals == 10) // If counted 10*50,000 = 500,000


{
intervals = 0; // Reset interval count
P1OUT = P1OUT ^ RED_LED; // Then, toggle red P1.0 LED
}
}
}
}

Copyright 2012-2015 Page 16 of 18


Valparaiso University
30. Ok, are you ready for your first challenge for this section? Can you create a new CCS project
called Timer_Up_20seconds that turns on the red LED for approximately 20 seconds and then
turns it off. The program should then keep the red LED off forever (or, at least until you stop the
program).

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?

Copyright 2012-2015 Page 17 of 18


Valparaiso University
All tutorials and software examples included herewith are intended solely for
educational purposes. The material is provided in an as is condition. Any
express or implied warranties, including, but not limited to the implied warranties
of merchantability and fitness for particular purposes are disclaimed.

The software examples are self-contained low-level programs that typically


demonstrate a single peripheral function or device feature in a highly concise
manner. Therefore, the code may rely on the device's power-on default register
values and settings such as the clock configuration and care must be taken when
combining code from several examples to avoid potential side effects.
Additionally, the tutorials and software examples should not be considered for use
in life support devices or systems or mission critical devices or systems.

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.

Copyright 2012-2015 Page 18 of 18


Valparaiso University

Das könnte Ihnen auch gefallen