平台:
Code Composer Studio 6.2.0 + Grace 2.2.0
MSP430G2553 LaunchPad™ Development Kit (MSP-EXP430G2ET)


_  以下大部分内容摘自《LaunchPad口袋实验平台 —— MSP-EXP430G2篇》傅强、杨艳 编著(TI大学计划嵌入式微控制器技术丛书)_

概述

  定时器在任何单片机中都具有极其重要的作用。我们都知道单片机是顺序执行指令,我们把CPU看成是人,一个每次只能干一件事的人。没有定时器的帮助,人就会像在监狱服刑一样,早上起床,吃早饭,干苦力、放风、吃晚饭、睡觉、早上起床…偶尔有的变数就是有人探监(外部中断)。可怕的是,如果吃饭时“耳背”,狱警喊停没听见,那作为犯人就必须一直吃下去,干苦力时出了岔子就更悲催了。
  定时器是什么呢?实际就是能够对时钟进行计数的计数器,类似我们的闹钟。定时器的出现才使单片机成为几乎无所不能的完整的自由人。一个自由主人的一天是这样的:

  1. 起床:相当于main循环的起始。
  2. 刷牙:相当于执行各种inital操作,此task主人(CPU)必须亲力亲为,并且不能被其他事打扰。
  3. 烧水:代表不需要人(CPU)一直干的task,主人灌好烧水壶后,只需打开灶台火焰即可。不巧的是烧水壶并没有水烧好的鸣响器(外设中断),怎么办?最傻的办法是主人得一直盯着看烧水的全过程。但是有定时器,主人就不必要这么做了。因为烧好一壶水的时间基本是知道的,主人设定好闹钟就可以去看报纸(其他任务)或者打瞌睡了(休眠)。待闹钟响起,人去关火,泡咖啡…
  4. 敲门:有访客敲门相当于突发事件event。假设主人住在大庄园里,又恰巧没有门铃(外部中断)怎么办?难道要主人成天蹲在大门口吗?不用,有定时器呢。假定访客敲门都最少会敲5分钟,主人将定时器设定为5分钟响一次,每5分钟去门口看一次,这样就不会错过客人来访了。其他时间,主人可以打dota或者发呆。
  5. 吃药:假如主人每隔1小时需要吃药一次,这相当于对时间要求严格的task,按理说这不就是用个闹钟就完了吗。憋屈的是,主人只有1个闹钟,已经用在“接客”上了,怎么办?没关系,主人可以数定时5分钟的闹钟响了多少次,数够12次就吃药。类似的方法,主人可以数着闹钟的“节拍”处理其他对时间要求严格的task。
  6. 有人来访:好了,5分钟去大门口看一次,真有访客了。访客分两种情况,送快递的(只需标记下,可以后续处理的event)或是上门拜访的(需要立刻接待处理的event)。因为对于快递包裹,主人验货收下即可(写全局变量标志位),以后有时间再研究包裹内的物品。而上门拜访的客人,主人立刻亲自接待(中断子函数,占用CPU)。
  7. 客人赖着不走:客人脑子进水了说个没完没了(程序跑飞或外设错误),影响主人正常生活了,怎么办?没事,幸好有看门狗定时器在,每隔设定时间,必须喂狗(重置看门狗定时器),否则设定时间一到,看门狗该咬人了(重启单片机)。主人的一天要重新开始了。

  总结一下主人的一天,一个住着大庄园的主人,却没有仆人(有的话成双CPU了)。还非常憋屈的没有自动报警的烧水壶,庄园大门没有门铃,吃药都没有专人伺候。但是依靠闹钟(定时器),主人还是可以惬意的生活,有时间打dota,有时间打盹。甚至当“天下大乱”的时候,还有看门狗可以让一天重来。
  定时器作为单片机中最有用的片内外设,就是为弥补CPU顺序执行程序这个“死脑经”缺陷而量身定做的。学会使用定时器的思想,才算真正是单片机入了门。

Timer_A 模块

  除了概述中最基本的定时器功能外,定时器还有很多种不同的构造(辅助功能),以更方便的为人所利用,比如一个倒计时方式的闹钟可能更有用。
  MSP430单片机中Timer_A定时器就是一种辅助功能强大的定时器,具备捕获和PWM输出等极其有用功能。Timer_A定时器的构造原理与其他高性能单片机定时器的原理非常类似,具备“普适价值”。所以我们有必要从原理上理解这一定时神器。
  MSP430x2xx系列单片机的Timer_A模块的整体构造如下图所示,包括1个16位定时器(TimerBlock)和3个捕获/比较模块(CCRx)。

  1. 16 位定时器的最大定时值 65535,当前计数值被存放在 TAR 寄存器中。
  2. CCRx 的捕获模块 Caputre 由 1 个输入 IO 口(CCIx)控制,输入上升沿或下降沿均能
    触发比较模块动作,捕获发生后的瞬间,TAR 值被存入 TACCRx 寄存器。
  3. CCRx 的比较模块 Comparator 控制 1 个输出 IO 口(TAx)去生成各种脉冲波形。当TAR 计数值与预存入 TACCRx 寄存器的值相等时,比较模块动作,以某种预设规则控制 IO 电平,生成波形。其中 CCR0 的 TA0 只能生成 50%占空比方波,原因稍后会叙述。
  4. 由于捕获模块 Caputre 和比较模块 Comparator 共用了 TACCRx 寄存器,捕获 Capture的功能是写 TACCRx,而比较Comparator 的功能是读 TACCRx 模块,所以捕获和比较不能同时使用。

在这里插入图片描述

16 位主定时器

  Timer_A 的核心单元是一个 16 位的主定时器,其实也就是个 16 位计数器,如果计数脉冲的频率精确稳定的话,计数的同时就是计时。
  主定时器的工作模式 MCx 寄存器可配置 4 种模式,其中 MCx=00 为停止,无需解释。剩下 3 种,连续计数模式、增计数模式、增减计数模式,就算是初学者也必须知道得一清二楚!

连续计数模式

  设置 MCx=10,主定时器将工作在连续计数模式下。

  1. 如下图左侧所示,主定时器犹如 1 个表盘,TAR 寄存器最大值 65535,计满则清零,指针沿表盘 360°工作。
  2. 如下图右侧所示,时钟的周期仅由时钟源的频率决定,频率越高则越快计数至65535,TA 周期越短。

在这里插入图片描述

增计数模式

  设置 MCx=01,主定时器将工作在增计数模式下。与连续计数不同的是,CCR0 模块可以提前将 TAR 寄存器清零。

  1. 如下图左侧所示,当 TAR 的值与 TACCR0 预设值(图中设定为 40959)相等时,TAR被强迫清零。时钟表盘只能在灰色区域活动。
  2. 如下图右侧所示,定时器的实际周期不再仅由时钟源决定,还与 TACCR0 设定值有关。

在这里插入图片描述

增减计数模式

  设置 MCx=11,主定时器将工作在增减计数模式下。与增计数不同的是,CCR0 模块不是提前将 TAR 寄存器清零,而是将主定时器转变为减法器(俗称逆袭)。

  1. 如下图左侧所示,当 TAR 的值与 TACCR0 预设值(图中设定为 40959)相等时,TAR减法计数。时钟表盘同样只能在灰色区域活动。当 TAR 减到 0 以后,主定时器自动变回加法器。
  2. 如下图右侧所示,定时器的实际周期同样与 TACCR0 设定值有关,并且是增计数模式的两倍。

在这里插入图片描述

主定时器的一般设置

  使用时,我们需要对 16 位定时器做一些什么设置呢?

  1. 确定计数脉冲的来源寄存器 TASSELx 及分频值寄存器 IDx,反正翻来覆去就那么几种来源,用到再说。
  2. 确定定时器的工作模式寄存器 MCx,如下表所示。






定时器工作模式



定时器工作模式


定时器工作模式

MCx 模式 描述
00 停止Stop 停止计数
01 增计数Up 重复从 0 计数到 TACCR0
10 连续计数Continuous 重复从0计数到0xFFFF
11 增减计数 Up/down 重复的从0增计数到TACCR0又减计数到0

  1. 各种计数模式何时触发中断 TAIFG(Timer_A Interrupt Flag)呢?如下图所示,连续计数在 0xFFFF→0 时刻;增计数在 TACCR0→0 时刻;增减计数模式是在减计数的0x0001→0x0000 时刻。
  2. 任何时候,都可以软件直接读取当前的定时器值寄存器 TAR,也可以人为设定 TAR的“初值”(这不太常用)。
  3. 此外,还有定时器“复位键”TACLR,用于重新开始一次计时。TACLR 对分频器也有效,是彻底的复位。

在这里插入图片描述

捕获/比较模块 CCRx

  Timer_A 的有捕获/比较模块 CCRx 并不是独立的功能模块,它们都必须依靠 16 位主定时器工才能工作。

  1. 捕获模块 Capture:可以判断输入信号的边沿,并瞬间用 TACCRx 寄存器记录下边沿时刻(TAR 值),用于精确测定脉宽或频率。
  2. 比较模块 Comparator:通过将 TAR 寄存器值与 TACCRx 中预设值比较,自动按“预设方案”反转 IO 电平,可以自动生成各种波形。
  3. 捕获/比较共用了 TACCRx 寄存器,所以不能同时使用,CAP 寄存器位用于选择捕获/比较工作模式。CAP=0 为比较,CAP=1 为捕获。

捕获模块

  将 CAP 设置为 1,CCRx 工作于捕获模式。主定时器一般设置为连续计数模式,当CCRx 检测到 CCIx(某带捕获功能的 IO 口)的电平边沿时,瞬间读取 TAR 寄存器的值并写入 TACCRx。

在这里插入图片描述
  CCRx可以选择检测上升沿或下降沿,或者都检测。CCRx用于测定信号脉宽时,只需要分别记录信号上升沿时刻和下降沿时刻,两时刻相减就是脉宽;而测量频率时,连续记录两次上升沿时刻,相减就是周期。
  如果大家用过 51 单片机测脉宽和频率,初一看这和外部中断的方法不是差不多吗?两者大不一样。

  1. 外部中断法:边沿被检测→触发中断→进中断子函数→读取定时器值,这时读取的定时器值和实际边沿的时刻有较大的误差。
  2. 捕获法:边沿被检测→立刻读取定时器值 TAR 锁存到 CCRx 模块内 TACCRx 寄存器→触发中断→爱什么时候读什么时候去读 TACCRx。这样的误差延迟就仅有十纳秒级。

  使用捕获模块的一般步骤:

  1. 把主定时器设为连续计数模式,这样就有最长的“刻度尺”可用。当“尺子”长度 还不够的时候,可以设定尺子每溢出1次,中断服务给全局变量Count+1,这样就能测量任意时间长度了。
  2. 把CCRx模块对应的寄存器CAP设为1,捕获模式。
  3. 选择CCRx 模块的捕获源寄存器CCISx,也就是具体单片机哪个管脚作为捕获输入口CClx。
  4. 设定CMx寄存器,决定是上升沿捕获还是下降沿,还是上升下降都捕获。
  5. 设定SCS寄存器,决定是同步捕获还是异步捕获。咋一看起来,异步捕获响应要快,但是捕获后的有效数据是来自定时器的计数值,响应再快也超不过时钟的分辨率。所以一般均设为同步捕获,这样可以减小电路毛刺,避免竞争冒险。
  6. 标志位COV为1代表上次TACCRx的数据没被取走,而又新来数据覆盖了TACCRx的异常情况。前面提到的“爱什么时候读什么时候去读TACCRx” 说的有些夸张,不能等下次捕获来临还不读取上次的捕获数据。

比较模块

  当 CAP=0 时,CCRx 工作于比较模式。CCR0 在比较模式中,将用于设定定时器的周期,所以我们暂时当 CCR0“牺牲”了,只讨论 CCR1 和 CCR2 的工作情况。
  如下图所示,当 CCR1/2 发现 TAR 的值与 TACCR0 或它们自己的 TACCRx 相等时,便会自动改变输出 IO 口 TAx 的输出电平,从而生成波形。改变的规则由 OUTMODx 寄存器决定,共有 8 种规则。
在这里插入图片描述
  这 8 种规则配合主定时器 TAR 的 3 种模式(连续计数、增计数、增减计数),可以无需CPU 干预生成各种波形。这样的排列组合将有 24 种,但是只有几种组合是“有用的”,用于生成以下 4 种特定波形:

  1. 单稳态波形。

在这里插入图片描述
2. 普通PWM,CCR1和CCR2各可生成1路。普通PWM的占空比可调范围0~100%。
在这里插入图片描述
3. 带死区控制的双路对称PWM。死区PWM的占空比可调范围必须小于50%,具体留多少余量,由死区时间决定。
在这里插入图片描述
4. 3路50%占空比方波,相位可调。
在这里插入图片描述
  下面我们将结合下表的 8 种模式,阐述如何得到上述 4 类波形。
在这里插入图片描述

  如图 6.12-图 6.15 所示,展示了如何通过设定主定时器的模式 MCx 和 CCRx 的输出模式OUTMODx 的组合,得到的各种“高价值”波形。
  每个图的最下面都有中断事件的时间轴,当主定时器被 CCR0 清零,每个比较模块CCRx 的 TACCRx 与 TAR 相等时都会引发中断。标明了主定时器中断 TAIFG 位置,以及CCR0 的中断 EQU0 位置,CCR1 的中断 EQU1 位置,CCR2 的中断 EQU2 位置。
  OUTMODx 的功能就是决定在发生了 TAIFG 中断或 EQUx 中断时,自动按哪种方式改变 IO 的电平,在下面的各个波形图中“→”位置标明了控制 IO 改变的规则。

  1. 模式 0:通过 CCRx 模块各自的 OUT 控制位控制 TAx 输出,像操作普通 IO 口那样。一般用于程序预设定 TAx 的电平。
  2. 模式 1 和模式 5:用于生成单稳态脉冲。如图 6.12 所示,主定时器(计数器)设置
    为增计数模式,使用 OUT 控制位预先置 0/置 1 后,就可以得到正/负单稳态脉冲,单稳态脉宽由 TACCRx 决定(图中是 TACCR1)。

在这里插入图片描述

  1. 模式 3 和模式 7:用于产生 PWM 信号(有关 PWM 的知识请自行科普)。如图 6.13所示,主定时器(计数器)设置为增计数模式。PWM 的频率由 CCR0 的 TACCR0 决定,PWM 的占空比由 TACCRx 与 TACCR0 的比值决定。通过 CPU 改写 TACCRx 的值即可改变 PWM 的脉宽,同样,CPU 所要做的工作仅限于此,输出 PWM 仍然是“全自动”的,这一功能经常应用于自动反馈控制中。注:虽然每个 Timer_A 模块有 3 个捕获/比较模块 CCR0/1/2,但是 CCR0 的寄存器TACCR0 已被用于设定 PWM 频率,因此用 CCR1 和 CCR2 最多能生成 2 路独立的PWM 信号。

在这里插入图片描述

  1. 模式 2 和模式 6:用于产生带死区时间控制的互补 PWM。如图 6.14 所示,两信号均为 0 的时间为 Tall-zero,Tall-zero必须大于死区时间 TDEAD。将主定时器(计数器)设置为增减计数模式,同样由 CCR0 的 TACCR0 决定 PWM 频率。CCR1 和 CCR2 分别设定为模式 6 和模式 2,只要 TACCR1-TACCR2 > TDEAD,就可保证安全工作。同样 TACCR1 和TARRC2 与 TACCR0 的比值决定占空比
      _注:死区时间是什么?在控制半桥和全桥驱动器的应用中,我们有这么一种特殊需求,两路信号不能同时为 1,并且当一路信号变 0 以后,另一路信号最少要过一段时间 TDEAD 才允许从 0 变 1,否者将会引起电路短路。TDEAD 与全桥/半桥电路的器件参数有关,一般为微秒数量级。_
    在这里插入图片描述

  2. 模式 4:用于生成最多 3 路移相波形。前面我们提到 PWM 波形最多能生成 2 路,在不需要控制占空比时(50%占空比的方波),通过模式 4 可得 3 路频率相位均可改变的输出波形。如图 6.15,将主定时器(计数器)设置为增计数模式,CCR0 的TACCR0 决定信号输出频率。CCR1/2 的 TACCR1/2 值决定了 TA1/2 超前 TA0 的相位

在这里插入图片描述

小结

  1. 定时器极其有用,一个仅有闹钟功能的定时器都可以使单片机化腐朽为神奇。
  2. Timer_A 定时器是一种有辅助功能的 16 位定时器,其辅助功能的结构具备“普适价值”,绝对不白学。
  3. 捕获模块 Caputure 就是一个能把待测信号边沿时刻瞬间“自动”记录的装置,能精确记录边沿时刻。区别于 IO 口中断后,由 CPU 进中断子函数再去记录“当前时刻”的方式。
  4. 比较模块 Comparator 可以自动的基于主时钟去产生各种信号,而不需要 CPU 操心。这区别于用 CPU 去翻转 IO 口电平而产生信号的方式。

Grace中配置Timer_A

  如图所示,Grace可配置Timer0_A3与Timer1_A3:
在这里插入图片描述
  进入后勾选Enable Timerx_A3 in my configuration即可启用:

在这里插入图片描述
在这里插入图片描述

Timer0_A3 - Overview

  _(Timer1_A3与之相同)该页部分内容机翻如下:_

介绍

  Timer0_A3是一个16位的定时器/计数器,有三个捕获/比较块。Timer_A可以支持多个捕获/比较、PWM输出和间隔计时。Timer_A还具有广泛的中断能力。中断可以从计数器的溢出条件和每个捕获/比较寄存器中产生。

用例:定时器的启动/停止

  通过配置TA0CTL寄存器中的MCx位>0,可以启动或重新启动定时器。MCx位代表定时器的计数模式,MCx=00意味着定时器的计数器被停止。
  用户代码:

// Start Timer_A
TA0CTL |= MC_1; // Start timer in up mode

// Stop Timer_A
TA0CTL &= ~(MC1 + MC0); // Clear MCx bits to stop timer

用例:使用定时器比较模式产生周期性间隔

  定时器被配置为比较模式,以产生定期中断。在等待定时器中断被设置的同时,器件被置于适当的低功率模式下,GIE被启用。当选定的定时器周期过后,定时器中断被设置,设备从LPM中唤醒,为定时器ISR服务。用例还显示了手动中断切换的实现,以在LPM和活动模式之间切换。
  Grace配置

  1. 启用Timer_A并选择Basic User视图
  2. 选择间隔定时器模式,TA0输出关闭,输入所需的定时器周期
  3. 启用捕获比较中断。你可以在 src/grace/InterruptVectors_init.c 中的 TIMER0_A0_ISR_HOOK 内插入你的自定义 ISR 代码。

  用户代码:

// Enter LPM with global interrupt enabled
__bis_SR_register(LPM0_bits + GIE);

// On every timer period interrupt, device wakes up to service Timer ISR
// Execute the following after exit from LPM from within Timer ISR
// >>>>>>>> Fill-in user code here <<<<<<<<

   导航到InterruptVectors_init.c文件,在TIMER0_A0 ISR的用户代码部分之间添加以下代码。

/* USER CODE START (section: TIMER0_A0_ISR_HOOK) */
    // "Selected Timer Period" elapsed
    // >>>>>>>> Fill-in user code here <<<<<<<<

    __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 on exiting ISR. Remove this line to remain in LPM.
    /* USER CODE END (section: TIMER0_A0_ISR_HOOK) */

用例:定时器PWM模式

  定时器比较模式也可用于产生PWM输出信号。根据Grace配置中选择的定时器计数模式、选择的定时器周期和PWM占空比,可以产生适当的PWM输出信号。除非需要改变定时器的PWM周期/占空比,否则不需要额外的用户代码。

  Grace配置

  1. 启用Timer_A并选择Basic User视图
  2. 选择PWM定时器模式,TA0输出关闭,输入所需的PWM周期
  3. 为定时器捕获/比较块#1选择 “PWM Duty Cycle”,并从提供的列表中选择一个输出引脚
  4. 输入所需的PWM占空比

用例:使用定时器溢出产生周期性间隔

  定时器被配置为使用溢出中断产生周期性间隔。定时器计数器被配置为连续模式,溢出中断被启用,在每次定时器计数器溢出时触发定时器溢出中断。在等待定时器溢出中断被设置的过程中,器件被置于适当的低功耗模式,并启用GIE。当选定的定时器计数器溢出时,定时器溢出中断被设置,器件从LPM唤醒,为定时器ISR服务。

  Grace配置

  1. 启用Timer_A并选择Power User - CCR0视图
  2. 选择连续计数模式以及定义16位定时器溢出周期的适当时钟和分频器设置
  3. 启用定时器溢出中断。你可以在 src/grace/InterruptVectors_init.c 中的 TIMER0_A1_ISR_HOOK 内插入你的自定义 ISR 代码。

  用户代码:

// Enter LPM with global interrupt enabled
__bis_SR_register(LPM0_bits + GIE);

// On every timer period interrupt, device wakes up to service Timer ISR
// Execute the following after exit from LPM from within Timer ISR
// >>>>>>>> Fill-in user code here <<<<<<<<

   导航到InterruptVectors_init.c文件,在TIMER0_A1 ISR的用户代码部分之间添加以下代码。

    /* USER CODE START (section: TIMER0_A1_ISR_HOOK) */
    // >>>>>>>> Fill-in user code here <<<<<<<<
    /* USER CODE END (section: TIMER0_A1_ISR_HOOK) */

用例:计时器捕获模式

 

  定时器被配置为在启用定时器捕获中断的情况下在捕获输入引脚上捕获上升/下降/上升和下降边缘事件。在等待输入信号上的选定边沿以触发捕获中断的同时,该器件被置于适当的低功率模式下,GIE被启用。当检测到捕获输入信号上的选定边沿时,TACCR1中断被设置,器件被唤醒以服务定时器_A中断服务例程。

 

  Grace配置

 

  1. 启用Timer_A并选择Power User - CCR0视图
  2. 选择连续计数模式和适当的时钟和分频器设置,定义16位定时器的周期
  3. 在Timer Capture/Compare Block #0下,选择Timer OFF
  4. 选择Power User - CCR1视图
  5. 在适当的Timer_A.CCIA/B输入引脚上选择输入捕捉模式
  6. 选择上升沿或下降沿或两个沿的捕获模式选项
  7. 启用捕获/比较中断。你可以在 src/grace/InterruptVectors_init.c 中的 TIMER0_A1_ISR_HOOK 内插入你的自定义 ISR 代码。

 

  用户代码:

// Enter LPM with global interrupt enabled
__bis_SR_register(LPM0_bits + GIE);

// On input capture interrupt, device wakes up to service Timer ISR
// Execute the following after exit from LPM from within Timer ISR
// >>>>>>>> Fill-in user code here <<<<<<<<

  导航到InterruptVectors_init.c文件,在TIMER0_A1 ISR的用户代码部分之间添加以下代码。

    /* USER CODE START (section: TIMER0_A1_ISR_HOOK) */
    switch (__even_in_range(TA0IV, 10))         // Efficient switch-implementation
    {
        case TA0IV_TACCR1:                      // TA0CCR1
          // >>>>>>>> Fill-in user code here <<<<<<<<
          break;
        case TA0IV_TACCR2:                      // TA0CCR2
          // >>>>>>>> Fill-in user code here <<<<<<<<
          break;
        case TA0IV_TAIFG:                       // Overflow
          // >>>>>>>> Fill-in user code here <<<<<<<<
          break;
        default:
          break;
    }
    /* USER CODE END (section: TIMER0_A1_ISR_HOOK) */

上机实战

 

500ms的中断

 

Grace配置

 

  启用Timer0_A3:
在这里插入图片描述
  设定时间,启用中断:
在这里插入图片描述
  此处可以配置时钟源和分频系数等,默认使用12k的ACLK(比较不准)
在这里插入图片描述
  参考【MSP430G2553】图形化开发笔记(3) GPIO配置P1.6为输出。

 

main.c

/*
 * ======== Standard MSP430 includes ========
 */
#include <msp430.h>

/*
 * ======== Grace related includes ========
 */
#include <ti/mcu/msp430/Grace.h>

/*
 *  ======== main ========
 */
int main(void)
{
    Grace_init();                   // Activate Grace-generated configuration
    
    // >>>>> Fill-in user code here <<<<<
    __bis_SR_register(LPM3_bits + GIE);
    return (0);
}

InterruptVectors_init.c

在这里插入图片描述

/*
 *  ======== Timer0_A3 Interrupt Service Routine ======== 
 */
#pragma vector=TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR_HOOK(void)
{
    /* USER CODE START (section: TIMER0_A0_ISR_HOOK) */
    /* replace this comment with your code */
	if(P1OUT & BIT6)
		P1OUT &= ~BIT6;
	else
		P1OUT |= BIT6;
    /* USER CODE END (section: TIMER0_A0_ISR_HOOK) */
}

现象

  可在P1.6上观测到约1Hz的脉冲:
请添加图片描述
  产生误差的原因是作为时钟源的12kHz ACLK不准,设置ACLK输出后,我这片实测为12.5kHz:

在这里插入图片描述
  重新设定计数周期数即可:
在这里插入图片描述

在这里插入图片描述

50Hz PWM

Grace配置

  设定时钟源和周期:
在这里插入图片描述
  配置占空比、输出引脚和模式:
在这里插入图片描述

main.c

/*
 * ======== Standard MSP430 includes ========
 */
#include <msp430.h>

/*
 * ======== Grace related includes ========
 */
#include <ti/mcu/msp430/Grace.h>

/*
 *  ======== main ========
 */
int main(void)
{
    Grace_init();                   // Activate Grace-generated configuration
    
    // >>>>> Fill-in user code here <<<<<
    while(1)
    {
    	;
    }
//    return (0);
}

现象

请添加图片描述

改变占空比

main.c

/*
 * ======== Standard MSP430 includes ========
 */
#include <msp430.h>

/*
 * ======== Grace related includes ========
 */
#include <ti/mcu/msp430/Grace.h>


#define MCLK_IN_HZ      16000000

#define delay_us(x)     __delay_cycles((MCLK_IN_HZ/1000000*(x)))
#define delay_ms(x)     __delay_cycles((MCLK_IN_HZ/1000*(x)))

/*
 *  ======== main ========
 */
int main(void)
{
	char i = 0;
    Grace_init();                   // Activate Grace-generated configuration
    
    // >>>>> Fill-in user code here <<<<<
    while(1)
    {
    	TA0CCR1 = (TA0CCR0 + 1) * (i/100.) - 1;
    	delay_ms(10);
    	if (++i > 100)
    		i = 0;
    }
//    return (0);
}

现象

在这里插入图片描述