切换到宽版
  • 1129阅读
  • 14回复

[ARM]STM32 ARDUINO HALMX  应用(七) 基本定时器库 [复制链接]

上一主题 下一主题
离线huaweiwx
 

发帖
1235
M币
2784
专家
53
粉丝
232
序 :
      在帖子 STM32 ARDUINO HALMX 应用集锦(一):systic  http://bbs.mydigit.cn/read.php?tid=2316400  中介绍了系统时钟systic的一个应用,这里再介绍一个库 :基本定时器库(HardwareBaseTimer lib);


一、STM32 通常都有以下5个类型定时器:
1  基本定时器(basic timers);
2  通用定时器(General-purpose timers);
3  高级定时器(Advanced-control timers);
4  系统嘀嗒定时器(systick) 1个;
5  看门狗定时器(独立看门狗和窗口看门狗) 2个;
另外在一些低功耗芯片系列还包含有低功耗定时器的类型;

二、定时器的用途:

1  系统嘀嗒定时器在arduino中作为系统计数计时用,将系统时钟分频成1ms的最小单位进行计数,HAL 库还提供了一个获取计数值的函数:
HAL_GetTick() 来获取开机至当前时间的Tick数,即ms数;顺便在这里说一下,HAL 库内部对Tick(ms)数计数是一个32位整数 uint32_t , 因此最大可以记录时间长度为:
   0xffffffff/1000ms/86400 = 49 天;
   注意:尽管我们业余玩家不会碰到连续开机超过49天的情形,但如果设计产品,使用者可能不关机超过 49 天的情形,需要在应用程序中处理计数器溢出;

arduino 应用该定时器还扩充了以下四个有用的函数:

delay(ms);  /*延时 ms 毫秒*/
millis();/*arduino 兼容函数 直接调用 HAL_GetTick() 来获取开机至当前时间的ms数*/
micros();/*根据当前毫秒数和 systick 寄存器的计数值计算当前微秒值*/
delayMicroseconds(us) ; /*微秒级别延时*/
delay_us(us); /*arduino 兼容函数,直接通过宏定义用delayMicroseconds(us)来置换 */

另外 HAL 还提供了一个接口,让系统能够每个Tick(毫秒)做一次用户指定的任务,这就是SYSTICK的回调函数:
void HAL_SYSTICK_Callback(void);
只要用户自己写了该回调函数,系统就会自动调用该函数(这部分详见我的一个示例:\libraries\BoardExamples\examples\Official\systic_callback\systic_callback.ino)

2 看门狗定时,以后详细介绍;

3 基本定时器、通用和高级定时器,该帖开始将分别介绍 ;

三、基本定时器库:
1 在stm32 通常有两个基本定时器 TIM6/7,和 systick 非常类似,都是以系统时钟分频计数并产生中断,区别是 systick 内部是24位计数器,而基本定时器是16位计数器,另外基本定时器可以触发dim中断;另外 SYSTICK 是M0/M3/M4/M7 内核的一部份,
而,TIM6/7 则属于集成在芯片上的外设;systick的中断优先级别也高于TIM 中断的优先级;
STM32 ARDUINO 内核 没有使用到基本定时器TIM6/7, 这一资源留给了用户根据需要来应用,但有一个例外:就是FreeRTOS;
FreeRTOS和HAL结合得非常好,ST 发行的HAL驱动库就包含了这个第三方组件;
简单说一下实时多任务操作系统FreeRTOS,根据任务的优先级别,高级别的任务可以打断低级的任务的运行抢占mcu资源,否则按时间片轮流分配时间,任务间可以协同工作;为了充分发挥操作系统的分配资源,调度任务的功能,ARDUINO STM32 可以用两个FreeRTOS库,一个是原生于基于maple库 ARDUINO中; 在 danieleff/STM32GENERIC 的arduino版本中也已经移植过来了,在我的最初HAL版本中也照搬了这个库,但现在我已经抛弃了该库(你仍然可以使用该库, 但需要去danieleff/STM32GENERIC 下载),现在包中的FreeRTOS是用最新HAL库组件重新写了FreeRTOS库,这是因为前者是基于SYSTICK中断来调度,而ST强烈推荐使用一个定时器来做系统时钟,这是在FreeRTOS中会调整定时器中断的优先级,来实现任务优先级的调度,而不会中断关键处理中断;这个FreeRTOS版本中使用定时器 TIM7;

简单总结一下就是:如果你用了FreeRTOS,就不要再使用TIM7,可以使用TIM6,如果没有用到FreeRTOS,可以使用TIM6/7;

四、何时用到基本定时器?
上面说到 TIM6/7和 systick,也是计数计时,定时中断做一些用户指定的事,除触发dma外,基本功能差不多;
区别在于:
1 我们使用TIM6/7 可以设定我们需要的定时时间间隔,而不是systick的毫秒单位,尽管我们可以按我们的需要来设置systick,但这样弄乱了系统时间,这不是我们希望的,而通过设置计数标志的方法,增加了检查该标志的麻烦和时间;
2 精确度,不另行设置而借用系统 systick,只能精确到毫秒级,而我们直接使用TIM6/7中断可以精确到us级甚至ns级;
3 基本定时器使用简单;

五、应用实例:HardwareTimerInterrupt.ino
  1. /*
  2. * STM32 基本定时器 TIM6/7 库lib
  3. * STM32 basic timers TIM6/7 lib: HardwareBaseTimer by huaweiwx<huaweiwx@sina.com>
  4. *
  5. * This example sets basic timers(TIM6 and TIM7) software interrupt
  6. *
  7. * note: if  used freeRTOS, Timer7 is undefined
  8. * 注:即使芯片有TIM7 , 如果运行了 freeRTOS ,该库 Timer7 就不会定义,因为freeRTOS优先使用TIM7作为系统时钟;
  9. *
  10. * Advanced-control timers and General-purpose timers you can use the HardwareTimer lib.
  11. * 要使用到其他普通定时器和高级定时器TIM1~5/8~17/21~22(视所选板载芯片)的定时、PWM或脉冲捕捉等高级用途 ,可用HardwareTimer lib。
  12. *
  13. * 2018.5.28 huaweiwx<huaweiwx@sina.com>
  14. */
  15. #include "HardwareBaseTimer.h"
  16. #define Timerx Timer6
  17. void interrupt() {
  18.     digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
  19. }
  20. void setup() {
  21.     Serial.begin(115200);
  22.     pinMode(LED_BUILTIN, OUTPUT);
  23.     Timerx.setPeriod(1000000); // in microseconds = 1 second
  24.     Timerx.attachInterrupt(interrupt);
  25.     Timerx.resume();
  26. }
  27. void loop() {
  28.     delay(5000);
  29.     Serial.println("----");
  30.     Serial.print("PCLK1Freq: ");
  31.     Serial.println(HAL_RCC_GetPCLK1Freq());
  32.     
  33.     Serial.print("Timer base frequency:");
  34.     Serial.println(Timerx.getBaseFrequency());
  35.     Serial.print("Timer prescaler:");
  36.     Serial.println(Timerx.getPrescaleFactor());
  37.     Serial.print("Timer period:");
  38.     Serial.println(Timerx.getOverflow());
  39. }

这个库 的使用非常容易,简单说明如下:
16  装入库头文件;
18  定义个宏 Timerx , Timer6 为库中已预定义的TIM6 实例;

20~22 定义一个中断处理函数,这里简单的翻转LED_BUILTIN(板子缺省led)电平;

29 设置定时器计数值为 1000000,即 1秒 = 1000000 微秒;
31 将 20~22 定义的中断处理函数,链接到定时器中断上;
32 按上述参数重置定时器(启动)

其实,最基本的应用就是上面这些,loop 弄个空函数就可以达到,1秒间隔亮灭led,下面36~50 行只是我们在测试时可以用到的,显示不同的总线时钟值,应为stm32系列芯片种类繁多,而不同的定时器可能挂在不同的总线上,让我们能够检查外部和库内部设置值(如分频系数,溢出值,挂接总线频率等)是否正确;

源程序、库代码、实例等,请查询  https://github.com/huaweiwx/STM32GENERIC的最新版本;

下次将介绍 TIM1~TIM22(具体芯片只有部分)除 TIM6/7 外的通用和高级定时器库,敬请期待;

补充:关于TIMER 和RTC:
1 前者是高速定时器,后者是低速定时器;
2 前者可响应到us甚至ns级,而后者是ms 到 天的级别(F1),除F1 外,RTC是完整时钟,可响应的时间长达 年这个级别;
3 RTC在有后备电池和外置低速晶振时,即使断电关机,时钟部分仍可低功耗继续工作着;而且不会在上电和reset时被初始化而丢失数据;

[ 此帖被huaweiwx在2018-06-15 14:15重新编辑 ]
本帖最近打赏记录:共3条打赏M币+59
liqi5230 M币 +30 優秀文章 06-18
温力口 M币 +9 谢谢分享。。。。收藏备用。。。。 06-15
2545889167 M币 +20 很好的教程,赞 06-15
离线xktx09

发帖
4925
M币
3298
专家
2
粉丝
123
只看该作者 1楼 发表于: 06-15
好吧,第六集呢
本帖最近打赏记录:共1条打赏M币+20
huaweiwx M币 +20 确实自己给自己挖了个坑。 06-15
离线huaweiwx

发帖
1235
M币
2784
专家
53
粉丝
232
只看该作者 2楼 发表于: 06-15
确实自己给自己挖了个坑。
在线2545889167

发帖
12048
M币
9006
专家
274
粉丝
4624
只看该作者 3楼 发表于: 06-15
很好的教程,赞
离线温力口

发帖
54063
M币
160400
专家
412
粉丝
794
只看该作者 4楼 发表于: 06-15
谢谢分享。。。。收藏备用。。。。
离线cao57508

发帖
2190
M币
4137
专家
9
粉丝
74
只看该作者 5楼 发表于: 06-16
赞👍👍赞👍赞👍
离线ynymwtb

发帖
627
M币
3243
专家
10
粉丝
29
只看该作者 6楼 发表于: 06-16
自已可能用不到,赞一个
离线liqi5230

发帖
161
M币
27
专家
0
粉丝
6
只看该作者 7楼 发表于: 06-18
支持 很棒的教程 谢谢分享
离线nan77240

发帖
283
M币
24
专家
2
粉丝
16
只看该作者 8楼 发表于: 06-22
用原版IDE可以编译 用stm32arduino版 老是报错缺少文件 io.h  eeprom.h等等 把文件从原版复制过来也不行

本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
离线huaweiwx

发帖
1235
M币
2784
专家
53
粉丝
232
只看该作者 9楼 发表于: 06-22
1  这个正对 AVR系列的,avr芯片有内置eeprom,但stm32 大部分芯片是不带内置eeprom的,所以没有eeprom.h,这个头文件, 即使有,也是用内部flash模拟的,如果板子上有i2c eeprom,建议使用,如容量不够,可以换个大一点的。

2 库调用了io,这是和硬件有关的,也需要修改;avr 和arm 芯片的指令是不样的。

我在 https://github.com/avandalen/Spotwelder-SMD 看到这个包,涉及太多的与硬件有关的指令,移植工作量太大了。
快速回复
限80 字节
温馨提示:所有技术区严禁灌水,“沙发”“顶”字样;禁止广告贴;以免被删除
 
上一个 下一个