TI Training home
Getting started - MSP430G2553 value-line LaunchPad™ workshop
Getting Started with the MSP430G2553 LaunchPad - Part 5
Getting started - MSP430G2553 value-line LaunchPad™ workshop
Email
Getting Started with the MSP430G2553 LaunchPad - Part 5
Section 5 of the workshop is where you will get familiar with interrupts and the timer. You will use the timer to generate interrupts to the main routine. If you're not already familiar with the concept of microcontroller interrupts, now would be a good time to go out on the web and look that up.
Some of the features available on the timer A2 and timer A3-- they are an asynchronous 16-bit timer counter. They offer a series of different modes-- continuous, where the timer continuously counts up to FFFF and then rolls over to 0. In most cases like that you'll generate an interrupt at the rollover. That has limited-- that's a limited help to you, as the amount of time that it takes to run that isn't very selectable.
Now, in the up mode that's shown there in the lower left, the timer counts between 0 and the value in the capture compare register 0. So you can pick the time that the interrupts are going to-- at which the interrupts are going to occur.
If you want to do things like pulse width modulation, an up-down counter is very useful. So you can set the mode as an up-down counter and have the timer count between 0, the value in the capture compare register 0, and 0, go up, down, up, down, up, down. The difference, like I've said earlier, between the timer A2 and timer A3, the timer A2 offers two CCR, capture compare register, and the timer A3 offers three.
Now, both of these timers are capable of doing simple PWM. If you need to drive an LED, change the brightness of an LED, if you want to drive a servo motor or something like that, that's very straightforward to do with this timer. And if you look in the code examples available on the TI MSP430 website, you'll find code that does exactly that.
There are two or more interrupt vectors for fast decoding on these timers. Also, bear in mind that some of the parts not only have one timer, but they have two timers. So you could get multiple interrupts on this.
So when a peripheral or a programmed pin or something else, when it creates an interrupt, we need to understand how the interrupts and the stack operate together. When an interrupt happens, any currently executing instruction gets completed.
The program counter, which should be pointing to the next instruction, gets pushed onto the stack, as we can see in the diagram on the bottom down there, bottom right. Then the status register gets pushed onto the stack. You see TOS says the top of stack down there. Then the interrupt with the highest priority is selected. There is no preemption in the interrupt controller of the MSP430. If you have multiple interrupts pending, the interrupt with the highest priority get selected and will be run.
So the interrupt service-- rather, the interrupt request flag for that interrupt that went off, gets reset automatically on those flags that are a single source-- something like the counter compare-- or capture compare register 0 for the timer. That's a single source flag.
There are multiple source flags-- for instance, the GP I/O-- where we have an interrupt for the entire port, not for every single pin. So when you get that, you have to go in there and-- once you get the interrupt, you have to do a little interrupt handler that goes and finds out exactly which one was done. So for multiple source flags, you don't want to reset them automatically. Those have to remain set for your interrupt handler. Then you could service them by software.
So once that's done, the status register gets cleared. That means any low-power mode gets terminated. We're back to active state. Also, the global interrupt enable bit gets cleared. So that will disable any further interrupts.
That's a good thing. It's one of the first rules of microcontroller processing, or microcontroller programming, is that you don't make nestable interrupts. Of course, that's also the first rule that's broken, that people make interrupts nestable. But that means you have to take a lot of care to do that. We'll talk more about that later.
The content of the interrupt vector gets loaded into the program counter. Those interrupt vectors, remember, are up there at the top of Flash memory. That tells us the location of our interrupt service routine. So now the program will continue execution at the interrupt service routine that's loaded at the address that was in the vector table.
The G2553 vector table looks like this. Starting up at the top at FFFE-- in order to program that in, that's FFFE and FFFF-- you'll see that the reset interrupt is there-- the power up, the external reset, the watchdog timer, a Flash violation, the PC out of range will all generate a system reset interrupt. That is at 31, the very highest priority on the device.
Just below that is the non-maskable interrupt. That could also be oscillator faults, Flash memory access violations, would all generate a non-maskable interrupt. Of course, the reset and the NMI are the only non-maskable interrupts in the system. You don't want to be able to mask those out. And they're both the highest priority.
Coming after that, you'll see we have timer 1 interrupts for the CCR0, CCR2, and some of the other registers inside the timer. Next is the single interrupt for the comparator. The interrupt for the watchdog timer is after that. Two interrupts for timer-- the timer 0 A3, CCR0, CCR1, and some of the other registers.
The next two interrupts are for the USCI, the universal serial communications interface, as shown. The one below that is the ADC10 interrupt. Just below that you'll see the I/O port P2, and then I/O port P1.
Now, some of these interrupts have more than one source. Something like an I/O port, for example, have as many as eight sources. So when you take an interrupt and the interrupt is processed, that interrupt will not be-- the interrupt flag will not be automatically cleared for you. You need to go back and clear it after you take a look to find out exactly which pin gave you an interrupt. Something like the watchdog timer, the comparator, the ADC, those things have a single interrupt source, and the interrupt flags will be automatically cleared for you.
So once the processor is interrupted, and the interrupt mechanism has loaded the address of the interrupt service routine to be executed into the program counter, we're going to jump off and do the interrupt service routine. Here's an example of an interrupt service routine right here that we might write in our code.
So you can see we've used this thing called a pragma. This pound pragma up at the top identifies this function as the interrupt service routine for the listed vector, WDT_vector. If you go back to the previous slide, you'll see that the watchdog timer vector is at that exact address. This identifies the following function as being the interrupt service routine that's going to be for that vector when it's called.
So then we need to give it a-- with this interrupt void, we need to identify what the ISR name is. That will give it an address-- that this location identified by WDT_ISR, that address is going to be plugged in automatically by the compiler to the watchdog timer vector. That way, when the interrupt service routine gets run, it will jump right to the first one of these instructions, run all of these, and then jump back into the code. No special return is required. Nothing else is required to do-- to make an interrupt run. And we're going to see all this in the lab.
Lab 5 will use the 16-bit timer running on the ACLK, sourced by the VLO, to generate a delay. When the timer reaches the end of that delay, it will generate an interrupt. The interrupt hardware on the MSP430 will find the correct address of the interrupt service routine that you've written, and go ahead and run it. These are all real world skills that you need over and over when working with the MSP430.
In step 1, create a new project by clicking File, New, CCS Project. Again, we'll make the selections as shown in the drawing below. If you're using the G2231, make sure you make the choices for that part. Make sure you click Empty Project at the bottom, and then click Finish.
The solution file that we had from the last exercise will be used as a starting point for this lab exercise. We went ahead and cleaned the file up a little bit to make it more readable by putting the initialization code into individual functions. So open the Lab5_Start.txt file using File, Open File. That should be in your Lab 5 file folder.
When that opens up, copy all of the code in Lab5_Start.txt, and paste it into main, making sure that you erase all the existing code in main.c. This is going to be the starting point for this lab exercise.
In step 3, go ahead and close the Lab5_Start file. We don't need that anymore.
So go ahead and run the code. And if everything's working right, the green LED should be blinking about once per second. And it should function exactly the same as the previous lab exercise.
When you're done, halt the code and click the Terminate button to return to the editing perspective. Now we want to use the timer to implement that delay. In the next few steps, we're going to implement the one-second timer that was previously implemented using the delay intrinsic with the timer. So go ahead and find the delay cycles 125,000 and delete that line of code.
In step 6, we need to add a function to configure the timer. So add a declaration for this new function to the top of the code underneath the one that already exists for config ADC10. And that should look like void config timer A2 void. Now actually, the timer on the 2553 is the timer A3, but that makes no difference for what we're trying to do here.
When you've done that, add a call to the function underneath the call to config ADC10 that says config timer A2 with no parameters. And then we want to add a template for this function to the very bottom of your program. So there's a void config timer A2 void-- we're not passing any parameters back and forth-- with an open and closing brace.
So that takes us to step 7. So we need to populate that config timer A2 initialization function with the code to configure the timer. We could take this from the example code, but it's pretty simple to do. So let's do it ourselves and take a look at how it works.
Add the following code as the first line. This is CCTL 0 equals CCIE. That's going to enable the counter compare register 0 interrupt in the CCTL 0 capture compare control register. Unlike the previous labs, this one is going to be using interrupts. After that, add the next two lines-- CCR 0 equals 12,000, and then timer A control equals timer A select 1 and MC 2.
We'd like to set up the timer to operate in continuous counting mode, sourced by the ACLK, and generate an interrupt every second. Reference the user's guide and the header files and notice the following-- that TACTL, that's the timer A control register, the TASSEL 1, that selects the ACLK as the input, and MC 2 sets the operation for continuous mode. When the timer reaches the value in CCR 0, the capture compare register 0, an interrupt will be generated. Since the ACLK is running at 12 kilohertz, the value in there needs to be 12,000 cycles if we want it to go off every second.
In step 8, we've enabled the CCR 0 interrupt, but global interrupts need to be turned on in order for the CPU to recognize that individual interrupt. Right before the while loop in main, add the following-- under bis, under SR, GIE. GIE is global interrupt enable.
So now we have the timer enabled, interrupts enabled, now we're going to need to have a interrupt service routine that can actually run. So we've got them set up. We need to create this interrupt service routine that runs when the timer interrupt fires.
Add the following code template to the very bottom of main.c. This is a piece of code. These lines of code identify this as the timer ISR code, and allow the compiler to insert the address at the start of this code-- that's timer A-- into the interrupt vector table at the correct location-- that's Timer0_A0_vector. 0
So the purpose of these two pieces of code is to take the address, timer A, and plug it into the correct place in the vector table. Look it up in the C Compiler user's guide. This user's guide was downloaded in lab 1.
So in step 10, remove all the code from inside your while loop in main and paste it into the ISR template. This will leave the while loop empty for the moment.
So almost everything's in place for the first interrupt to occur. In order for the second, third, fourth, and so on to occur at one-second intervals, two things need to happen. The interrupt flag has to be cleared. Well, that's automatic. The CCR 0 has to be set 12,000 cycles into the future. So add the following as a last line in the interrupt service routine-- CCR 0 plus equals 12,000.
In step 12, we need to have some code running in order to be interrupted. In reality, we don't. You could have a while loop sitting there with nothing in it that would run. But I think it would be more interesting to actually have something running.
So what we're going to do is add a little while loop with some blinking LEDs. So take the four lines of code shown in step 12 and paste them into your while loop. This routine doesn't use any intrinsics, so when we're debugging the interrupts, they'll look good in C, rather than dropping you back and forth between Assembly. Oh, and don't forget to declare I at the top of main.c-- volatile unsigned int I.
As we progress through the labs, what we're trying to do is take you a bit further away from using hex codes, and a bit more into using codes that are much more readable. So let's make some changes to the code for readability and for the LED function. Take a look in your fault routine and you'll see P1 out equals 0x1. We can change that to P1 out equals bit 0. That's easier to read.
In the config LEDs function, you'll see P1 dir-- that's the direction register-- equals 0x41. Let's change that to P1 dir equals bit 6 and bit 0.
In the timer ISR, you'll see P1 out equals 0x40. Let's change that to P1 out or bit 6. Finally, find P1 out equals 0, and change that to P1 out and equals the not of bit 6.
At this point, your code should look like the code that you'll see on the next two pages of the workbook. We added the comments to make it easier to read and understand. Go ahead and click the Save on the menu bar to save the file. And we'll go ahead and page slowly through the code.
Let's go back up to the top, and we'll see the very top of the code. Give you a chance to look at that, and then we'll click down one. Give you a chance to look at that. You should note that for reference, you can find this code in the Lab5_Finished.txt file, in the Files folder.
So in step 15, click the Debug button. The CCS Debug view should open, the program load automatically, and you should now be at the start of main.
Go ahead and run the code, and observe the LEDs. If everything's working correctly, the red LED-- that's what's in the while loop-- should be blinking about twice per second. This is the while loop that the timer's interrupting. The green LED should be blinking about once per second. This is the rate that we're sampling the temperature sensor. And looking at the board, that looks pretty good. Go ahead and click Suspend to stop the code.
In Step 17, make sure that the temp raw variable is still up there in the Expressions window. If not, you can double-click temp raw in the code like we did before. If needed, click on the Expressions tab so you can see the variable in the Watch window up there.
So in step 18, in the timer A2 ISR, find the line with P1 out and equals the not of B6, and place a breakpoint there. Right-click on the breakpoint symbol, and select Breakpoint Properties, or Breakpoint. There we go. Again, we're still having some difficulties with our capture system. So make sure you change the breakpoint property action from Stop to Refresh All Windows, as shown in step 18.
Go ahead, say OK. Go ahead and run the code. The Debug window should quickly stop at the breakpoint, and the temp raw value will be updated. Observe the Watch window, and test the temperature sensor as you did in the previous lab exercise. I'm going to put my finger on there, and hopefully the temperature will go up as it did before. And it does.
Terminate your active debug session using the Terminate button. Close the debugger, return to the Edit view.
In step 21, close your project by right-clicking on Lab 5 in the Project Explorer pane, and select Close Project. 专题讨论会的第 5 部分 将带您熟悉 中断和计时器。 您将使用计时器 生成主例程的 中断。 如果您 尚不熟悉 微控制器中断的 概念, 现在最好可以 上网查阅一下。 我们将介绍计时器 A2 和计时器 A3 的 一些可用特性, 它们是指异步 16 位计时器计数器。 它们提供了一系列 不同的模式, 例如连续模式,在这种模式下计时器 连续不断地计数到 FFFF 然后滚动至 0。 在多数类似情况下, 您将会在滚动中 生成中断。 这会造成一定限制, 对您的帮助有限, 因为运行它 所需的时间 并不是完全可选择的。 现在,在左下方显示的 向上模式下, 计时器在 0 和捕捉比较寄存器 0 的值 之间计数。 因此您可以选择 中断将要 发生的时间, 即在哪个点会发生中断。 如果您想要进行 类似于脉宽调制等事宜, 加减计数器 会非常有用。 因此您可以将模式设置为 加减计数器, 并且使计时器在 0、 捕捉比较寄存器 0 的值 及 0 之间计数, 向上、向下反复计数。 正如我先前提到的, 计时器 A2 和计时器 A3 之间的差异是, 计时器 A2 提供了 两个 CCR, 即捕捉比较寄存器, 而计时器 A3 提供了三个这样的寄存器。 现在,这两种计时器都能 进行简单的脉宽调制。 如果您需要驱动 LED、 调节 LED 的亮度, 如果您想要 驱动伺服电机 或类似的器件,使用 此计时器便可简单直接地 完成。 并且,如果您查看 TI MSP430 网站上提供的 代码示例,您会发现 代码能够准确实现该目标。 这些计时器上具有 两个或更多的中断矢量, 可实现快速解码。 另外,谨记 有些部件不止有 一个计时器, 而是有两个计时器。 您可以从计时器中 获取多个中断。 因此,当外设或 编程引脚或 其他内容 产生了中断, 我们需要了解 中断和堆栈如何 共同运行。 当中断发生时,任何 当前执行的指令 都会结束。 应指向 下一个指令的 程序计数器 会被推至堆栈, 正如我们 可在 右下角图中 看到的那样。 然后, 会将状态寄存器推到堆栈上。 您可以在下方此处看到 TOS, 即堆栈的顶部。 然后选择具有最高 优先级的中断。 MSP430 的 中断控制器中 无占先。 如果您有 多个中断处于等待状态, 则表示已选中 具有最高优先级的中断 并且将会运行该中断。 因此中断服务 -- 更确切地说,已关闭的中断的 中断请求 标记, 在计时器的 计数器比较 或捕捉比较寄存器 0 等单源的 标记上 自动复位。 这是单源标记。 同时 也有多源标记, 例如, GP I/O,在此我们 具有针对整个端口的中断, 而不是针对单个引脚。 因此当您遇到中断时, 应该看一下, 并且,一旦您 遇到中断, 您必须有一个 小型中断 处理程序,运行并准确 找出哪一个中断已完成。 对于 多源标记,您 不会希望它们 自动复位。 必须留待您的 中断处理程序来设置。 然后您可以通过软件 来检修它们。 一旦完成该操作, 状态寄存器会被清除。 这意味着将终止所有 低功耗模式。 我们将会回到工作状态中。 并且会清除全局 中断启用位, 以便禁用 任何进一步中断。 很好。 关于微控制器处理, 即微控制器编程, 首要规则 之一就是 不可以进行嵌套式中断。 当然这也是 第一条被打破的规则, 人们会进行 嵌套式中断。 但这要求 您在建立嵌套式中断时格外小心。 对此,我们稍后 将详细介绍。 中断矢量的 内容 被加载到 程序计数器中。 记住,这些 中断矢量 在闪存存储器的 顶部。 由此可得知 中断服务例程的位置。 这样,程序 将在加载到 矢量表中 地址的 中断服务例程中 继续执行。 G2553 矢量表 显示如下。 从顶部的 FFFE 开始 -- 为了 在 FFFE 和 FFFF 中编程 -- 您将 看到此处的复位 中断 -- 加电、 外部复位、看门狗 计时器、闪存违例、 超出范围的 PC 都将 产生系统复位 中断。 数字 31 在器件上 具有最高的优先级。 其下面的一个数字 为不可屏蔽中断。 振荡器 故障、闪存存储器访问 违例都会生成 不可屏蔽中断。 当然,复位 和 NMI 是 系统中仅有的 不可屏蔽中断。 您不会想要 屏蔽它们。 并且它们两个都 具有最高优先级。 接下来, 您会看到 我们会遇到 CCR0、CCR2 和计时器内部 一些其他寄存器的 计时器 1 中断。 之后是比较器的 单个中断。 看门狗计时器的中断 位于其后。 针对计时器的两个中断 -- 计时器 0 A3、CCR0、CCR1 以及一些其他寄存器。 接下来两个是 针对 USCI, 即通用串行 通信接口的中断, 如图所示。 然后是 ADC10 中断。 然后您会 看到 I/O 端口 P2 和 I/O 端口 P1。 现在,这些中断中有一些 具有多个源。 比如, I/O 端口等部件 有多达八个源。 因此当您遇到中断 且中断被处理时, 将不 会为您 自动清除 中断标记。 在您查看并准确 找出哪个引脚 造成中断后, 您需要返回并 清除它。 像看门狗 计时器、比较器和 ADC, 它们具有 单一中断源, 并且将会为您自动 清除中断标记。 一旦处理器 中断, 并且中断 机制已将 要执行的 中断服务例程的 地址加载到 程序计数器中, 我们将跳转并 执行中断服务例程。 屏幕上是 一个我们可能会写入 代码中的 中断服务例程示例。 您会看到我们使用了 一个名为 pragma 的注释。 上方的 #pragma 将此函数识别为 所列矢量 WDT_vector 的 中断服务例程。 返回 上一张幻灯片, 您会发现 看门狗计时器矢量的 地址与之完全相同。 这将以下 函数识别为 矢量被调用时 针对它 将会出现的 中断服务例程。 因此此中断 失效时, 我们需要确定 ISR 名称是什么。 这将给它一个地址 -- 该位置由 WDT_ISR 识别, 这个地址将 由编译器 自动插入 看门狗计时器矢量中。 这样,当中断 服务例程运行时, 它会跳转至这些 指令中的第一个指令, 运行所有指令,然后 跳回至代码中。 无需特殊的返回。 也不需要执行其他操作 来使中断运行。 我们将会在实验练习 中了解整个过程。 实验练习 5 将使用 ACLK 上运行的 16 位 计时器(使用 VLO 作为源) 来生成延迟。 当计时器达到 延迟结束时间点时, 会生成一个中断。 MSP430 上的 中断硬件 将找出您写的 中断服务例程的 正确地址, 并且继续运行它。 这些都是您使用 MSP430 工作时需要反复利用的 实际技能。 在第 1 步中,单击“File”、 “New”、“CCS Project”,创建一个 新项目。 然后按下图所示, 进行各种选项设置。 如果您使用的是 G2231,请确保 您为该部分进行了选择。 确认您单击了底部的 “Empty Project”, 然后单击“Finish”(完成)。 我们从上次练习中 得到的解决方案文件 用作本实验室练习的起点。 我们继续并清除 一些文件 使其可读性更强,方法是 将初始化代码 放入各个函数中。 在“File”菜单中,选择“Open File” 以打开 Lab5_Start.txt 文件。 该文件应该在您的 Lab 5 文件夹中。 打开文件后,复制 Lab5_Start.txt 中所有的代码, 并将其粘贴到 main 文件中, 请务必清除 main.c 中所有的现有代码。 这将作为此次 实验室练习的起点。 第 3 步,继续并 关闭 Lab5_Start 文件。 我们不再需要该文件了。 然后运行代码。 如果一切正常, 绿色 LED 应 约每秒闪烁一次。 并且其运行方式应与 在上个实验练习中 完全相同。 完成后,停止代码 并单击“Terminate”按钮, 回到 编辑视图。 现在,我们想要做的是使用计时器 来实现该延迟。 在接下来的几个 步骤中,我们将 实施一秒计时器, 该计时器之前 已采用 固有延迟实施。 请继续并且找出 延迟周期 125,000 并删除该行代码。 第 6 步,我们需要 添加一个函数 来配置计时器。 那么,在代码的顶部 已经存在的配置 ADC10 的 声明下方 为新函数添加 一个声明。 该声明应该显示为 “void config timer A2 void”。 事实上,现在 2553 上的计时器是计时器 A3, 但这对我们正尝试执行的操作 没有什么影响。 完成此操作后, 在配置 ADC10 的 调用下方 添加一个 函数的调用,显示为 “config timer A2 with no parameters”。 接下来我们要为这个函数 添加一个模板, 就在您的 程序的最下方。 这是一个失效 配置计时器 A2 void -- 我们将不会 以左右括号形式 来回传递任何参数。 请进入第 7 步。 我们需要填充 配置计时器 A2 初始化功能,使用 代码来配置计时器。 我们可以从示例代码中 获取到这一代码, 但这很简单。 所以让我们尝试自己来完成这一步, 先看一下它的工作机制。 添加下列代码, 将其作为第一行。 这行代码是 CCTL0 等于 CCIE。 它将会启用 CCTL 0 捕捉比较 控制寄存器 中的计数器 比较寄存器 0 中断。 与先前的实验 练习不同, 这个练习将要使用中断。 之后,添加下面 两行 -- CCR 0 equals 12,000, 然后是 timer A control equals timer A select and MC2。 我们想要设置计时器 以在连续计数模式中 运行,使用 ACLK 作为源,并且每秒 生成一个中断。 参考用户指南 和报头文件, 注意以下 几点 -- TACTL 代表 计时器 A 控制 寄存器,TASSEL 1 代表 选择 ACLK 作为 输入,以及 MC 2 将运行设置为 连续模式。 当计时器达到 CCR 0, 即捕捉比较寄存器 0 中的值时, 将生成一个中断。 因为 ACLK 以 12 kHz 的 频率运行, 如果我们希望它每秒都关闭, 其中的值需要达到 12,000 周期。 第 8 步,我们已启用了 CCR 0 中断, 但需要打开全局中断 以便 CPU 识别这个 单独的中断。 在 main 中的 while 环路之前, 添加以下代码 -- 下划线 bis,下划线 SR,GIE。 GIE 表示 Global Interrupt Enable(全局中断启用)。 现在我们 已启用了计时器, 启用了中断, 现在我们 需要使 中断服务 例程能够实际运行起来。 那么我们来设置它们。 我们需要创建中断 服务例程,它可以在 计时器中断触发时运行。 将下列代码模板 添加到 main.c 的最下方。 这是一段代码。 这几行代码识别 作为计时器 ISR 代码, 并且使编译器 能够将 代码开始处的 地址,也就是 计时器 A -- 插入到 中断矢量表中的 正确位置 -- Timer0_A0_vector。 因此这两段 代码的目的是 获取地址, 计时器 A,然后将其插入 矢量表中的 正确位置。 您可以在《C 编译器用户指南》中 进行查询。 实验练习 1 中 已下载了该用户指南。 那么第 10 步, 剪切 main 中 while 环路 中的所有代码, 并将其粘贴 到 ISR 模板中。 这一步将使 while 环路 保留为空。 现在几乎所有使 第一个中断发生的事项 都已到位。 为了使 第二个、第三个、第四个等 中断以 一秒的间隔发生, 还需要满足两个条件。 必须清除 中断标记。 这是一种自动操作。 以后必须将 CCR 0 设置为 12,000 周期。 将以下代码 添加为中断 服务例程的最后 一行 -- CCR 0 plus equals 12,000。 第 12 步,我们需要 中断某些 正在运行的代码。 实际上,我们没有这样做过。 您可以就将其中没有 任何内容的 while 环路 放在那里,它也可以运行。 但我认为让 某些内容实际运行起来 会更有趣。 那么我们接下来要做的 就是添加带有一些闪烁 LED 的 小型 while 环路。 获取第 12 步中 显示的四行代码 并将它们粘贴到 您的 while 环路中。 此例程不使用 任何固有函数, 因此当我们 调试中断时, 它们会以正常的 C 语言显示, 而不是让您在 汇编语言中来回重复。 对了,不要 忘记在 main.c 的 开头声明 I -- volatile unsigned int I。 当我们通过实验练习 进行处理时,我们尝试 让您稍稍远离 十六进制代码, 而更多地使用一些 更具可读性的代码。 所以为了提高可读性 并改善 LED 功能,让我们 对代码做些改变。 看一下 您的故障例程, 您会看到 P1 out equals 0x1。 我们可以将其 改为 P1 out equals bit 0。 这样的可读性更强一些。 在 config LED 功能中,您会 看到 方向寄存器 P1 dir equals 0x41。 可以将其改为 P1 dir equals bit 6 and bit 0。 在计时器 ISR 中,您将会 看到 P1 out equals 0x40。 可以将其改为 P1 out or bit 6。 最后找到 P1 out equals 0,可以将其改为 P1 out and equals the not of bit 6。 此时,您的代码 应该就和您 将在工作薄下两页 看到的代码相似了。 我们已添加了注释, 便于您更好地阅读和理解。 接下来单击菜单栏上的“Save”按钮 保存文件。 然后我们继续操作, 缓慢地逐页浏览代码。 我们回到 顶部,能看到 代码的最上面一部分。 您将有机会 查看一下该代码。 然后我们单击下一个代码。 您将有机会 查看一下该代码。 您应当记下 这些以作参考, 可以在“Files”文件夹中的 Lab5_Finished.txt 文件中 找到此代码。 第 15 步, 单击“Debug”按钮。 “CCS Debug”视图将打开, 程序会自动加载, 您应该 位于主代码的开始位置。 继续运行该代码, 并观察 LED。 如果一切正常, 红色 LED -- 由 while 环路中代码所控制 -- 应每秒 约闪烁两次。 这就是计时器 要中断的 while 环路。 绿色 LED 应 约每秒闪烁一次。 这就是我们 采对温度传感器采样的 速率。 看一下板, 看起来非常不错。 继续操作,单击 “Suspend”按钮来停止代码运行。 在第 17 步中,确保 “temp raw”(温度原始)变量 仍在 “Expressions”窗口中。 如果不在,您可以双击 代码中的“temp raw”, 就像我们之前所做的那样。 如有需要,单击 “Expressions”选项卡, 您就可以在此处的 “Watch”窗口中查看变量了。 第 18 步,在计时器 A2 ISR 中,找出 P1 out and equals the not of B6 那行, 并在那里放置一个断点。 右击 断点符号, 并且选择 Breakpoint Properties 或 Breakpoint。 好了。 同样,我们仍有一些 与捕捉系统相关的 困难。 确保您将 断点属性 操作从 Stop 改为 Refresh All Windows,如第 18 步中所示。 继续操作,单击“OK”。 接下来运行代码。 “Debug”窗口应当 在断点处快速停止, 并且 temp raw 数值 将更新。 查看“Watch”窗口, 并且像您在之前的 实验练习中所做的那样 测试温度传感器。 我将手指 放在此处, 希望温度会像 之前那样上升。 确实上升了。 使用“Terminate” 按钮来终止 处于工作状态的调试环节。 关闭调试器, 回到“Edit”视图。 第 21 步,右击 “Project Explorer”窗格中的 Lab 5,然后选择“Close Project” 来关闭您的项目。
Description
March 11, 2015
Using the interrupts and timer. Not only is the timer an important part of most microcontroller designs, it's also an easy way to generate interrupts when we want to experiment with them.