您的位置 首页 技术

SAM4E单片机之旅——3、LED闪耀之定时器中止

让一个LED灯闪烁不过瘾,我们应该让这块开发板完成一点更高难度的任务:比如让两个LED灯闪烁。……当然了,以我们的现在使用的空循环技术,还是可以实现这点的。但是这样显得略为低端。所以我们使

  让一个LED灯闪耀不过瘾,咱们应该让这块开发板完结一点更高难度的使命:比方让两个LED灯闪耀。

  ……

  当然了,以咱们的现在运用的空循环技能,仍是能够完成这点的。可是这样显得略为低端。所以咱们运用一个高端点的技能:中止。还有便是会介绍一下在CMSIS里怎样运用中止。

  一、电路

    

 

  二、完成思路

  第一个LED的闪耀仍是用之前运用的空循环吧,别把国际弄得太杂乱了。

  第二个LED的闪耀就略微自动化一点了:运用一个定时器,让它在到了需求切换引脚电平的时分告诉咱们一下。这样做的优点便是咱们只需在定时器告诉时重视第二个LED灯,而在其他的时分就能够忙其他事了。(比方让第一个LED闪耀。)

  运用的中止源仍是之前用到的RTT。RTT能够在计数器到达特定值时产生中止,这个特定的值(Alarm Value)能够经过拜访RTT报警寄存器(RTT_AR)设定。然后在RTT的中止处理函数中切换LED引脚的电平,一起设定好下一次中止的条件就好了。

  三、中止

  在中止时,处理器会依据中止号在中止向量表查询中止服务函数(ISR)相关的信息。为此,咱们需求知道RTT的中端号(3),还有中止向量表的方位,然后修正中止向量表。体系控制块(SCB)中有个“向量表偏移寄存器”(SCB_VTOR),在这个地址指向的区域里贮存着一系列的向量,包含外部中止向量表。然后咱们需求知道ISR相关信息在这个向量表的方位。接着修正中止向量表时需求知道它贮存的只要ISR的地址,仍是直接跳转至ISR的指令……(先别忙着着手)

  四、main函数之前产生的事

  实际上,进口点——即整个程序开端运转的进口,并不是main函数。这个进口是链接器指定的,默许情况下是_start函数。而在Atmel Studio生成的项目中,默许情况下链接器的参数有“–entry=Reset_Handler”的这么一项,意思便是指定程序进口为Reset_Handler。

  这个函数的完成在以下文件中:

  src\ASF\sam\utils\cmsis\sam4e\source\templates\gcc\startup_sam4e.c

  这个是函数也是重置时的中止处理函数。在这个函数中,进行了一系列的初始化作业,其间包含中止向量表的装备。然后在初始化C库之后,就调用main函数了。最终在main函数回来后履行一个死循环。

  五、界说中止处理函数

  CMSIS现已为界说好了各种ISR的函数原型,一起做好了默许的函数完成。这些函数在以下文件中完成:

  src\ASF\sam\utils\cmsis\sam4e\source\templates\exceptions.c

  不过默许的函数完成是“弱界说”为Dummy_Handler的别号,这个函数的完成仅仅一个简略的死循环。弱界说意味着咱们能够很方便地在链接时掩盖默许的完成。办法便是从头界说一个具有相同签名的函数。由于默许情况下是“强界说”的,所以就会掩盖掉默许的完成。

  六、准备作业

  现在程序现已略为杂乱了,需求做些准备作业。

  宏界说:

/* LED 运用的GPIO引脚 */

  #define LED0_GPIO PIO_PA0

  #define LED1_GPIO PIO_PD20

  /* LED 闪耀的周期 */

  #define LED0_OFF_MS 500

  #define LED0_ON_MS 1000

  #define LED1_OFF_MS 500

  #define LED1_ON_MS 200

  辅佐函数CalcRTTNeedInc。之前为了核算经过指定时刻后RTT记数器添加的值,写了几行代码。由于有多个当地要用到这个核算,所以把它笼统出来了:

  inline uint32_t CalcRTTNeedInc(unsigned int ms)

  {

  /* 计数器加一的频率 */

  const uint32_t freq = CHIP_FREQ_SLCK_RC / PRESCALE;

  /* 核算推迟后,计数器需求添加的值

  * need_inc = ms /1000 / (1/freq) */

  return (ms * freq / 1000);

  }

  六、RTT的中止处理

  在理论上,本程序在RTT中止时切换第二个LED的引脚电平,并设置下一次中止的条件。

  在文件sam4e16e.h中,现已界说好了RTT中止处理函数的原型了,只需完成即可。

  需求留意的是,在中止处理函数中,需求经过读取一次RTT_SR以铲除RTT的Alarm情况,不然该中止一向会被触发。

  void RTT_Handler(void)

  {

  /* 经过读取情况寄存器铲除Alarm */

  uint32_t _ = RTT->RTT_SR;

  uint32_t begin_rttv = ReadRTT_CRTV();

  uint32_t int_gap_ms ;

  uint32_t need_inc;

  if ((PIOD->PIO_ODSR & LED1_GPIO) == 0)

  {

  /* 现在引脚电平为低,LED是亮的 */

  /* 灭灯 */

  PIOD->PIO_SODR = LED1_GPIO;

  /* 设置下次中止唤醒距离的时刻 */

  int_gap_ms = LED1_OFF_MS;

  }

  else

  {

  /* 现在引脚电平为高,LED是灭的 */

  /* 亮灯 */

  PIOD->PIO_CODR = LED1_GPIO;

  /* 设置下次中止唤醒距离的时刻 */

  int_gap_ms = LED1_ON_MS;

  }

  /* 核算并设置下一次中止的条件 */

  need_inc = CalcRTTNeedInc(int_gap_ms);

  RTT->RTT_AR = RTT_AR_ALMV(begin_rttv + need_inc – 1);

  return;

  }

  七、RTT初始化中止启用

  假如需求启用中止,需求装备NVIC_ISERx寄存器,并且需求进行必定的核算。而CMSIS也做了相应的作业:

  /* 启用中止 */

  NVIC_ClearPendingIRQ(RTT_IRQn);

  NVIC_EnableIRQ(RTT_IRQn);

  关于RTT,装备时只需使能中止,一起设置第一次中止的条件即可。

  /* 初始化 RTT */

  RTT->RTT_MR = RTT_MR_RTPRES(PRESCALE)

  | RTT_MR_RTTRST

  | RTT_MR_ALMIEN

  ;

  /* 核算第一次中止的时刻

  * 现在灯是亮的,第一次中止即在需求灯灭时

  */

  RTT->RTT_AR = RTT_AR_ALMV(

  ReadRTT_CRTV() + CalcRTTNeedInc(LED1_ON_MS) -1);

  八、禁用看门狗

  程序在运转若干秒之后,可能会看到一些不和谐的情况,比方某个LED灯不依照咱们的想象快速闪烁一两下。这是由于看门狗默许是敞开的,而咱们却从来没有“喂狗”,然后导致体系重置。现在我只需禁用看门狗即可:

  WDT->WDT_MR = WDT_MR_WDDIS;

  PS,完好程序代码:

  这一部分完好代码放在下面,今后大约不会再在这个基础上修正了吧。

  + View Code

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/jishu/114979.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部