历史上的今天
返回首页

历史上的今天

今天是:2024年08月26日(星期一)

正在发生

2019年08月26日 | 【STM32H7教程】第22章 STM32H7的SysTick实现多组软件定时器

2019-08-26 来源:eefocus

22.1 初学者重要提示


比通用定时器要容易掌握很多,因为嘀嗒定时器的功能比较的单一,根据ARM的说法,此定时器就是专门为RTOS的系统时钟节拍而设计。


本章节为大家讲解的多组软件定时器实现方案非常实用,建议初学者熟练掌握。


22.2 Systick基础知识


关于滴答定时器,初学者仅需了解到以下几点知识就够了。



Systick是Cortex-M7内核自带的组件,其它几个常用的硬件异常HardFault,SVC和PendSV也都是是内核自带的,其中Systick,SVC和PendSV的中断优先级是可编程的,跟SPI中断、ADC中断、UART中断等一样,都在同一个NVIC下配置的。而HardFault是不可编程的,且优先级要比可编程的都要高。


Systick是一个24位的递减计数器,用户仅需掌握ARM的CMSIS软件提供的一个函数SysTick_Config即可,原代码如下:

1. /**

2.   brief   System Tick Configuration

3.   details Initializes the System Timer and its interrupt, and starts the System Tick Timer.

4.            Counter is in free running mode to generate periodic interrupts.

5.   param [in]  ticks  Number of ticks between two interrupts.

6.   return          0  Function succeeded.

7.   return          1  Function failed.

8.   note    When the variable __Vendor_SysTickConfig is set to 1, then the

9.            function SysTick_Config is not included. In this case, the file device.h

10.            must contain a vendor-specific implementation of this function.

11. */

12. __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)

13. {

14.   if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)

15.   {

16.     return (1UL);                                            /* Reload value impossible */

17.   }

18.

19.   SysTick->LOAD  = (uint32_t)(ticks - 1UL);                  /* set reload register */

20.   NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL)/*set Priority for Systick Interrupt */

21.   SysTick->VAL   = 0UL;                                      /* Load the SysTick Counter Value */

22.   SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |

23.                    SysTick_CTRL_TICKINT_Msk   |

24.                    SysTick_CTRL_ENABLE_Msk;                 /* Enable SysTick IRQ and SysTick Timer */

25.   return (0UL);                                             /* Function successful */

26. }

  第12行,函数的形参用于配置滴答定时器LOAD寄存器的数值,由于滴答定时器是一个递减计数器,启动后是将LOAD寄存器的数值赋给VAL寄存器,然后VAL寄存器做递减操作,等递减到0的时候重新加载LOAD寄存器的数值继续做递减操作。

函数的形参表示内核时钟多少个周期后触发一次Systick定时中断,比如形参配置为如下数值。


-- SystemCoreClock / 1000  表示定时频率为 1000Hz, 也就是定时周期为  1ms。


-- SystemCoreClock / 500   表示定时频率为 500Hz,  也就是定时周期为  2ms。


-- SystemCoreClock / 2000  表示定时频率为 2000Hz, 也就是定时周期为  500us。


注:SystemCoreClock是STM32H7的系统主频400MHz。


  第20行,此函数设置滴答定时器为最低优先级。

  第22行,配置滴答定时器的控制寄存器,使能滴答定时器中断。滴答定时器的中断服务程序实现比较简单,没有清除中断标志这样的操作,仅需填写用户要实现的功能即可。

控制及其状态寄存器的位定义:


重装寄存器定义,最大值2^24 – 1 = 16777215,配置的时候注意别超出范围了。


22.3 多组软定时器驱动设计

22.3.1 软件定时器框架

为了方便大家理解,先来看下软件定时器的实现框图:



1、  第1阶段,初始化:


通过函数bsp_InitTimer初始化滴答定时器和实现软件定时器所需的结构体。


2、  第2阶段,软件定时器初始化:


  可以通过函数bsp_StartTimer做单次定时器初始化,单次定时器执行一次就结束。下次还想使用,需要重新创建。

  可以通过函数bsp_StartAutoTimer做周期性定时器初始化,可以周期性的一直运行下去。

3、 第3阶段,滴答定时器中断里面更新每个软件定时器的计数:


在滴答定时器中断里面通过调用函数bsp_SoftTimerDec实现每个软件定时器的计数更新。


4、  第4阶段,检测时间到和停止运行


  通过函数bsp_CheckTimer可以检测单次或者周期定时器的时间是否到。时间到后就可以执行用户任务。

  如果不想某个单次或者周期性定时器执行,直接调用函数bsp_StopTimer停止即可。

22.3.2 程序分析之相关的变量定义

在bsp_timer.h 中定义了结构体类型SOFT_TMR。


#define TMR_COUNT 4      /* 软件定时器的个数 (定时器ID范围 0 - 3) */

 

typedef enum

{

TMR_ONCE_MODE = 0, /* 一次工作模式 */

TMR_AUTO_MODE = 1 /* 自动定时工作模式 */

}TMR_MODE_E;

 

/* 定时器结构体,成员变量必须增加__IO 即 volatile,因为这个变量在中断和主程序中同时被访问,

有可能造成编译器错误优化。

*/

typedef struct

{

volatile uint8_t Mode; /* 计数器模式,1次性 */

volatile uint8_t Flag; /* 定时到达标志  */

volatile uint32_t Count; /* 计数器 */

volatile uint32_t PreLoad; /* 计数器预装值 */

}SOFT_TMR;

在bsp_timer.c 中定义SOFT_TMR结构体数组变量。


/* 定于软件定时器结构体变量 */ 

static SOFT_TMR s_tTmr[TMR_COUNT];

每个软件定时器对象都分配一个结构体变量,这些结构体变量以数组的形式存在将便于我们简化程序代码行数。


22.3.3 程序分析之初始化

初始化函数如下:


1. /*

2. *****************************************************************************************************

3. * 函 数 名: bsp_InitTimer

4. * 功能说明: 配置systick中断,并初始化软件定时器变量

5. * 形    参:  无

6. * 返 回 值: 无

7. *****************************************************************************************************

8. */

9. void bsp_InitTimer(void)

10. {

11. uint8_t i;

12.

13. /* 清零所有的软件定时器 */

14. for (i = 0; i < TMR_COUNT; i++)

15. {

16. s_tTmr[i].Count = 0;

17. s_tTmr[i].PreLoad = 0;

18. s_tTmr[i].Flag = 0;

19. s_tTmr[i].Mode = TMR_ONCE_MODE; /* 缺省是1次性工作模式 */

20. }

21.

22. /*

23. 配置systic中断周期为1ms,并启动systick中断。

24.

25.     SystemCoreClock 是固件中定义的系统内核时钟,对于STM32H7,一般为 400MHz

26.

27.     SysTick_Config() 函数的形参表示内核时钟多少个周期后触发一次Systick定时中断.

28.     -- SystemCoreClock / 1000  表示定时频率为 1000Hz, 也就是定时周期为  1ms

29.     -- SystemCoreClock / 500   表示定时频率为 500Hz,  也就是定时周期为  2ms

30.     -- SystemCoreClock / 2000  表示定时频率为 2000Hz, 也就是定时周期为  500us

31.

32.     对于常规的应用,我们一般取定时周期1ms。对于低速CPU或者低功耗应用,可以设置定时周期为 10ms

33.     */

34. SysTick_Config(SystemCoreClock / 1000);

35. }

  第14-20行是软件定时器结构体的初始化部分,设置初始值。实际创建软件定时器会重新做初始化。

  第32行是本章22.2小节已经讲解。

22.3.4 程序分析之单次定时器创建

单次定时器创建函数bsp_StartTime。


1. /*

2. ******************************************************************************************************

3. * 函 数 名: bsp_StartTimer

4. * 功能说明: 启动一个定时器,并设置定时周期。

5. * 形    参:  _id  : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。

6. * _period : 定时周期,单位1ms

7. * 返 回 值: 无

8. ******************************************************************************************************

9. */

10. void bsp_StartTimer(uint8_t _id, uint32_t _period)

11. {

12. if (_id >= TMR_COUNT)

13. {

14. /* 打印出错的源代码文件名、函数名称 */

15. BSP_Printf("Error: file %s, function %s()rn", __FILE__, __FUNCTION__);

16. while(1); /* 参数异常,死机等待看门狗复位 */

17. }

18.

19. DISABLE_INT();  /* 关中断 */

20.

21. s_tTmr[_id].Count = _period; /* 实时计数器初值 */

22. s_tTmr[_id].PreLoad = _period; /* 计数器自动重装值,仅自动模式起作用 */

23. s_tTmr[_id].Flag = 0; /* 定时时间到标志 */

24. s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 1次性工作模式 */

25.

26. ENABLE_INT();  /* 开中断 */

27. }

  第12-17行是为了防止用户设置的ID参数超过范围。

其中BSP_Printf是在bsp.h文件定义的,用于调试阶段排错。


#define BSP_Printf    printf   /* 使用这个宏定义的话,正常执行printf */


#define BSP_Printf(...)        /* 如果使用这个宏定义的话,什么都不执行 */


  第19-26行是临界段,结构体变量赋值前后做了开关中断操作。因为此结构体变量在滴答定时器中断里面也要调用,防止变量赋值出问题。

开关中断函数也是在bsp.h文件里面定义的。


#define ENABLE_INT()     __set_PRIMASK(0)      /* 使能全局中断 */


#define DISABLE_INT()    __set_PRIMASK(1)      /* 禁止全局中断 */


22.3.5 程序分析之周期性定时器创建

周期性定时器创建函数bsp_StartAutoTimer。


1. /*

2. ******************************************************************************************************

3. * 函 数 名: bsp_StartAutoTimer

4. * 功能说明: 启动一个自动定时器,并设置定时周期。

5. * 形    参:  _id   : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。

6. * _period : 定时周期,单位10ms

7. * 返 回 值: 无

8. ******************************************************************************************************

9. */

10. void bsp_StartAutoTimer(uint8_t _id, uint32_t _period)

11. {

12. if (_id >= TMR_COUNT)

13. {

14. /* 打印出错的源代码文件名、函数名称 */

15. BSP_Printf("Error: file %s, function %s()rn", __FILE__, __FUNCTION__);

16. while(1); /* 参数异常,死机等待看门狗复位 */

17. }

18.

19. DISABLE_INT();  /* 关中断 */

20.

21. s_tTmr[_id].Count = _period;      /* 实时计数器初值 */

22. s_tTmr[_id].PreLoad = _period; /* 计数器自动重装值,仅自动模式起作用 */

23. s_tTmr[_id].Flag = 0; /* 定时时间到标志 */

24. s_tTmr[_id].Mode = TMR_AUTO_MODE; /* 自动工作模式 */

25.

26. ENABLE_INT();  /* 开中断 */

27. }

 这个函数跟前面22.3.4小节中讲的单次定时器是一样的,仅第24行的赋值不同,这个函数是周期性的,而22.3.4小节里面的是单次定时器。

22.3.6 程序分析之停止定时器运行

定时器停止运行函数是bsp_StopTimer。


1. /*

2. ******************************************************************************************************

3. * 函 数 名: bsp_StopTimer

4. * 功能说明: 停止一个定时器

5. * 形    参: _id   : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。

6. * 返 回 值: 无

7. ******************************************************************************************************

8. */

9. void bsp_StopTimer(uint8_t _id)

10. {

11. if (_id >= TMR_COUNT)

12. {

13. /* 打印出错的源代码文件名、函数名称 */

14. BSP_Printf("Error: file %s, function %s()rn", __FILE__, __FUNCTION__);

15. while(1); /* 参数异常,死机等待看门狗复位 */

16. }

17.

18. DISABLE_INT();  /* 关中断 */

19.

20. s_tTmr[_id].Count = 0; /* 实时计数器初值 */

21. s_tTmr[_id].Flag = 0; /* 定时时间到标志 */

22. s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 自动工作模式 */

23.

24. ENABLE_INT();  /* 开中断 */

25. }

  这个函数跟前面22.3.4和22.3.5小节中的函数框架一样,仅是把结构体变量中的计数器和时间到标志都置位成0,从而让软件定时器停止运行。

22.3.7 程序分析之检测定时器时间到

检测定时器时间到的函数是bsp_CheckTimer。


1. /*

2. ******************************************************************************************************

3. * 函 数 名: bsp_CheckTimer

4. * 功能说明: 检测定时器是否超时

5. * 形    参:  _id  : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。

6. *     _period : 定时周期,单位1ms

7. * 返 回 值: 返回 0 表示定时未到, 1表示定时到

8. ******************************************************************************************************

9. */

10. uint8_t bsp_CheckTimer(uint8_t _id)

11. {

12. if (_id >= TMR_COUNT)

13. {

14. return 0;

15. }

16.

17. if (s_tTmr[_id].Flag == 1)

18. {

19. s_tTmr[_id].Flag = 0;

20. return 1;

21. }

22. else

23. {

24. return 0;

25. }

26. }

  第12到15行是检查ID是否有效。

  第17到25行是判断时间到标志值Flag是否置位,如果置位表示时间已经到,如果为0,表示时间还没有到。

22.3.8 程序分析之滴答定时器中断的处理

软件定时器的主要功能是通过滴答定时器中断实现的,函数的调用关系是滴答定时器中断函数SysTick_Handler调用SysTick_ISR,而SysTick_ISR调用bsp_SoftTimerDec。

推荐阅读

史海拾趣

AIC [Analog Intergrations Corporation]公司的发展小趣事
  1. 公司成立与初期发展:Analog Integrations Corporation(AIC)是一家总部位于台湾的半导体公司,专注于设计、制造和销售高性能模拟集成电路(IC)产品。公司成立于1996年,由一群拥有丰富经验的工程师共同创立。最初,AIC致力于为广泛的应用领域提供稳定可靠的模拟芯片解决方案,如消费电子、通信、工业控制等。

  2. 技术创新与产品发展:AIC在技术创新和产品研发方面投入了大量资源,不断推出具有竞争力的新产品。公司的产品涵盖了各种模拟IC产品系列,包括功率管理IC、放大器、比较器、数据转换器等。这些产品具有高性能、低功耗、小尺寸等特点,得到了广大客户的青睐。

  3. 全球市场拓展:随着公司技术和产品的不断成熟,AIC开始着眼于国际市场的拓展。公司积极参与国际电子展览和行业会议,与全球客户建立合作关系,拓展海外市场份额。通过建立销售代理商、设立海外办事处等方式,AIC在北美、欧洲、亚太等地区建立了稳固的销售网络。

  4. 质量管理与认证:AIC始终将产品质量视为企业发展的关键。公司严格遵循国际质量管理体系标准,建立了完善的质量管理体系。AIC的生产工艺和产品测试流程经过精心设计和严格监控,确保产品质量的稳定性和可靠性。此外,公司的产品经过了多项国际认证,包括ISO 9001质量管理体系认证、ISO 14001环境管理体系认证等。

  5. 社会责任与可持续发展:作为一家负责任的企业,AIC积极履行社会责任,关注环境保护和可持续发展。公司致力于降低能源消耗和减少废物排放,推动绿色生产和循环利用。此外,AIC积极参与社会公益活动,支持教育、健康、环保等多个领域的项目,为社会发展做出积极贡献。

Displaytech公司的发展小趣事

2008年,Displaytech推出了HDP Power,这是一项创新的电力解决方案,旨在支持公司客户的电力需求。这一举措不仅体现了Displaytech对客户需求的深刻洞察,也展示了公司在电源领域的技术实力。

ACCUTEK公司的发展小趣事

ACCUTEK公司深知人才是企业发展的核心力量。因此,公司始终注重人才培养和团队建设。公司建立了完善的人才培养和激励机制,鼓励员工不断学习和创新。同时,公司还注重营造良好的工作氛围和团队文化,让员工能够在轻松愉快的环境中工作。这些举措不仅提升了员工的归属感和忠诚度,也为公司的持续发展提供了有力的人才保障。

这些故事基于电子行业的一般发展规律和可能的企业发展路径构建,并不代表ACCUTEK公司的真实历史。如需了解该公司的真实发展情况,建议查阅相关资料或访问其官方网站。

Hsuan Mao Technology Co公司的发展小趣事

随着产品质量的不断提升和市场份额的逐步扩大,ACCUTEK公司开始将目光投向国际市场。公司积极参加国际电子展会和技术交流活动,与全球多家知名企业建立了合作关系。同时,公司还在海外设立了多个分支机构,以便更好地服务当地客户。这些举措不仅提升了公司的国际影响力,也为公司的长远发展注入了新的活力。

Aeroflex Metelics / Hi-Rel Components公司的发展小趣事

ACCUTEK公司深知人才是企业发展的核心力量。因此,公司始终注重人才培养和团队建设。公司建立了完善的人才培养和激励机制,鼓励员工不断学习和创新。同时,公司还注重营造良好的工作氛围和团队文化,让员工能够在轻松愉快的环境中工作。这些举措不仅提升了员工的归属感和忠诚度,也为公司的持续发展提供了有力的人才保障。

这些故事基于电子行业的一般发展规律和可能的企业发展路径构建,并不代表ACCUTEK公司的真实历史。如需了解该公司的真实发展情况,建议查阅相关资料或访问其官方网站。

Analog Microwave Design公司的发展小趣事

随着通信技术的不断进步,对微波器件的性能要求也越来越高。Analog Microwave Design公司敏锐地捕捉到了这一市场变化,开始致力于研发更高性能的微波器件。经过多次试验和改进,公司成功开发出了一款具有低损耗、高稳定性的微波放大器,这一创新产品在市场上引起了热烈反响。公司凭借这一技术突破,迅速扩大了市场份额,并树立了行业内的技术领先地位。

问答坊 | AI 解惑

LIUNX系统移植

LIUNX系统移植 很好的啊…

查看全部问答>

wince5.0如何实现USB虚拟串口?

要实现wince5.0的无线上网功能,用的是中兴的AT2736无线上网卡,是电信的CDMA2000。接口是USB的,目前的想法是将USB虚拟成串口,然后对串口发送AT指令操作上网卡。 如何将USB虚拟成COM呢,以前没有接触过,没思路,有研究的大侠帮忙给个框架和思路 ...…

查看全部问答>

LoadBitmap问题

switch (wMsg)           {           case   WM_CREATE:    hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;           &nb ...…

查看全部问答>

关于加速计和陀螺仪的测试

各位高手有没有测试过加速计和陀螺仪这两颗的功能阿,三轴加速计有X,Y,Z三个电压输出,都是经过其内部的AD转换后输出的,不知道这三个方向上的电压是怎么变化的,是有加速度的时候变化呢,还是位置改变了变化啊? 陀螺仪有X,Y两个电压输出,也是 ...…

查看全部问答>

关于MTD驱动的问题

很多MTD驱动都有调用simple_map_init()函数来初始化read,write等函数,不知道这个函数的用法,请大虾帮忙讲一讲啊,如果我需要改变这些read,write函数,该怎么办啦?…

查看全部问答>

XILINX CPLD求助

各位高手,高手,高高手们:新手使用XILINX的 XC95288,有个问题求助:我从一块XC95288上readback后,保存成.jed文件,然后再烧入到另外一个片子后,另外这个片子就不能readback了,然后我擦除写入的这个文件后,就又能readback了,这是为什么呢? ...…

查看全部问答>

STM32的独立看门狗好像没什么用

                                 现在我的产品已经用了独立看门狗,也测试过正常是能起作用(在主程序里面喂狗,超时不喂的确是可以复位,可以防止 ...…

查看全部问答>

准备用lm3s做一个项目,有点问题,喜欢Stellaris的进来

在论坛潜伏了很长时间,终于有机会用到lm3s了,由于刚从8位单片机转过来,还有很多问题想和大家探讨。 先说说选择lm3s的原因,毕竟cm3定位是低价位,从硬件功能和价格上来说,替换8位/16位的单片机还是有优势的。加上stellaris的api库确实不错,连 ...…

查看全部问答>

關於LMF232H5QD的UART問題

各位高手大家好,小妹我用此板子的UART出了一點問題,大家可以幫幫我嗎? 感激不盡 問題是這樣的,我開啟了八個UART,為了使輸入資料可以做辨識,個別在UART4跟UART5的地方 加了三個#字號跟一個通道編號 例如:UART4是  ###Edata 這樣 ...…

查看全部问答>

今年会出功率放大类的吗?

本帖最后由 paulhyde 于 2014-9-15 03:16 编辑 今年会出功率放大类的吗    …

查看全部问答>