你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【初学】中断控制STM32硬件timer

[复制链接]
swang93 发布时间:2015-3-21 21:37
本帖最后由 swang93 于 2015-3-21 21:37 编辑

虽然作为嵌入式方向的大学生,但是并没有接触多少硬件。平时只学习了各种语言,忽略了硬件的学习。之前也只是在Arduino上做了一些开发,自己做了个小东西。前不久决定学习stm32,看了一些资料,算是刚入门,有些地方说的不严谨,大家尽管提出来,一起学习。想和大家分享的就是如何控制stm32的硬件Timer,大神轻喷。

1、  硬件timer是一个独立的计时器,在计时时以一个给定的速度在0和最大值之间计时,同时产生各种事件。它独立于你的C/C++程序,而且它的值遵循下面的规律:
01-timer.png

2、我通过一个简单的程序高明白了这个timer。我设置timer的周期为500,当timer的值达到400时让LED灯亮,当值达到500时再关闭LED。Timer每次达到500时就会自动重置为0。
02-timer.png

3、注意,在我们对timer进行任何动作的之前,需通过调用RCC_APB1PeriphClockCmd()来启动它:
  1. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  2. TIM_TimeBaseInitTypeDef timerInitStructure;
  3. timerInitStructure.TIM_Prescaler = 40000;
  4. timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  5. timerInitStructure.TIM_Period = 500;
  6. timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  7. timerInitStructure.TIM_RepetitionCounter = 0;
  8. TIM_TimeBaseInit(TIM2, &timerInitStructure);
  9. TIM_Cmd(TIM2, ENABLE);
复制代码

4、在main函数里,我们只简单地检查timer的值,并通过这个值来控制LED。第一版的完整程序如下,下面还会修改代码。

  1. #include <stm32f4xx_gpio.h>
  2. #include <stm32f4xx_tim.h>
  3. #include <stm32f4xx_rcc.h>
  4. #include <misc.h>

  5. void InitializeLEDs()
  6. {
  7.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  8.     GPIO_InitTypeDef gpioStructure;
  9.     gpioStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;
  10.     gpioStructure.GPIO_Mode = GPIO_Mode_OUT;
  11.     gpioStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12.     GPIO_Init(GPIOD, &gpioStructure);

  13.     GPIO_WriteBit(GPIOD, GPIO_Pin_12 | GPIO_Pin_13, Bit_RESET);
  14. }

  15. void InitializeTimer()
  16. {
  17.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  18.     TIM_TimeBaseInitTypeDef timerInitStructure;
  19.     timerInitStructure.TIM_Prescaler = 40000;
  20.     timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  21.     timerInitStructure.TIM_Period = 500;
  22.     timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  23.     timerInitStructure.TIM_RepetitionCounter = 0;
  24.     TIM_TimeBaseInit(TIM2, &timerInitStructure);
  25.     TIM_Cmd(TIM2, ENABLE);
  26. }

  27. int main()
  28. {
  29.     InitializeLEDs();
  30.     InitializeTimer();

  31.     for (;;)
  32.     {
  33.         int timerValue = TIM_GetCounter(TIM2);
  34.         if (timerValue == 400)
  35.             GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);
  36.         else if (timerValue == 500)
  37.             GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_RESET);
  38.     }
  39. }
复制代码

5、如果像下面那样设置一个断点,我们就可以观察到,每次执行到这里,timerValue的值都会在0-500之间。这就和我们设置的TIM_Period是符合的。
03-timer.png

6、  每次STM32timers达到周期值是,就可以自动的产生”update”事件。在TIM_Cmd(TIM2,ENABLE)下添加如下代码:
  1. TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
复制代码
就可以产生update事件。这里需要注意一下,由于我们没有设置中断控制器,所以这个中断不会影响代码的执行,我们需要手动的检查。

7、 如果用如下代码替换main函数的代码:
  1. InitializeLEDs();
  2. InitializeTimer();
  3. for (;;)
  4. {
  5.     if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  6.     {
  7.         TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  8.         GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
  9.     }
  10. }
复制代码
运行代码,我们就可以发现LED的闪烁模式已经改变了。

8、硬件timer真正强大的地方是,他们可以向CPU发送中断,这样就可以不用手动检查这些状态。在代码里添加下面这个函数,然后在main函数里在调用IntializeTimer()之后再调用它。
  1. void EnableTimerInterrupt()
  2. {
  3.     NVIC_InitTypeDef nvicStructure;
  4.     nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
  5.     nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
  6.     nvicStructure.NVIC_IRQChannelSubPriority = 1;
  7.     nvicStructure.NVIC_IRQChannelCmd = ENABLE;
  8.     NVIC_Init(&nvicStructure);
  9. }
复制代码

9、 最后去掉main函数里for循环里的代码,然后把这些代码添加到TIM_IRQHandler()函数里:
  1. extern "C" void TIM2_IRQHandler()
  2. {
  3.     if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  4.     {
  5.         TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
  6.         GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
  7.     }
  8. }
复制代码
注意,如果你创建的是C++文件,就需要extern “C”


10、把代码跑起,观察LED闪烁的情况。设置断点,观察寄存器的值:
04-timer.png

11、注意,链接寄存器(lr)通常包含函数的返回地址0xfffffff9,这是个特别的值,和ARMCortex CPU文档里说的EXC_RETURN一样,表明当前函数是被CPU自动调用用于处理中断的。


12、 用下面的代码代替main函数里for循环的代码:
  1. for (;;)
  2.     {
  3.         for (int i = 0; i < 1000000; i++)
  4.             asm("nop");
  5.         GPIO_ToggleBits(GPIOD, GPIO_Pin_13);
  6.     }
复制代码


13、跑起代码,我们就可以看到LED灯以不同的频率闪烁,互不影响。

最后把代码贴出来,一起学习! demo.zip (758 Bytes, 下载次数: 12)
收藏 1 评论38 发布时间:2015-3-21 21:37

举报

38个回答
zfz0122 回答时间:2015-3-22 00:38:03
学习了 3.gif
nocoyou 回答时间:2015-3-22 03:07:07
vs2015?
_ilikerome_ 回答时间:2015-3-22 10:01:28
感觉LZ写的挺好的,我这几天在搞高级定时器,驱动电机。

感觉你的这个教程写的不错

还有你用VS编辑??可以吗?
swang93 回答时间:2015-3-22 12:03:44
_ilikerome_ 发表于 2015-3-22 10:01
感觉LZ写的挺好的,我这几天在搞高级定时器,驱动电机。

感觉你的这个教程写的不错

谢谢!细看一下跑的其实是elf,用keil当然是更方便了
swang93 回答时间:2015-3-22 12:06:19
wambob 回答时间:2015-3-22 12:29:22

好像是mbed
coloree 回答时间:2015-3-22 15:05:47
支持一下
foxglove 回答时间:2015-3-22 16:32:47
教程写的不错
拼命三郎 回答时间:2015-3-22 19:19:50
xxxxxxxxxx.jpg
1234下一页

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版