谷动谷力

 找回密码
 立即注册
查看: 4408|回复: 1
打印 上一主题 下一主题
收起左侧

STM32F103RCT6开发板M3单片机教程06--定时器中断

[复制链接]
跳转到指定楼层
楼主
发表于 2021-12-21 23:57:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sunsili 于 2022-1-5 15:27 编辑

STM32F103RCT6开发板M3单片机教程06--定时器中断

除非特别说明,本章节描述的模块应用于整个STM32F103xx微控制器系列,因为我们使用是STM32F103RCT6开发板是mini最小系统板。
本教程使用是(光明谷SUN_STM32mini开发板



首先了解一下是STM32F10X定时器(Timer)


注:

小容量产品是指闪存存储器容量在16K32K字节之间的STM32F101xxSTM32F102xxSTM32F103xx微控制器。
中容量产品是指闪存存储器容量在
64K128K字节之间的STM32F101xxSTM32F102xxSTM32F103xx微控制器。
大容量产品是指闪存存储器容量在
256K512K字节之间的STM32F101xxSTM32F103xx微控制器。


大容量的STM32F103xx增强型系列产品包含最多2个高级控制定时器、 4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。
下表比较了高级控制定时器、普通定时器和基本定时器的功能:



高级控制定时器(TIM1和TIM8)
两个高级控制定时器(TIM1TIM8)可以被看成是分配到6个通道的三相PWM发生器,它具有带死区插入的互补PWM输出,还可以被当成完整的通用定时器。四个独立的通道可以用于:
● 输入捕获
● 输出比较
● 产生
PWM(边缘或中心对齐模式)
● 单脉冲输出
配置为
16位标准定时器时,它与TIMx定时器具有相同的功能。配置为16PWM发生器时,它具有全调制能力(0~100%)
在调试模式下,计数器可以被冻结,同时
PWM输出被禁止,从而切断由这些输出所控制的开关。
很多功能都与标准的
TIM定时器相同,内部结构也相同,因此高级控制定时器可以通过定时器链接功能与TIM定时器协同操作,提供同步或事件链接功能。

通用定时器(TIMx)
STM32F103xCSTM32F103xDSTM32F103xE增强型系列产品中,内置了多达4个可同步运行的标准定时器(TIM2TIM3TIM4TIM5)。每个定时器都有一个16位的自动加载递加/递减计数器、一个16位的预分频器和4个独立的通道,每个通道都可用于输入捕获、输出比较、 PWM和单脉冲模式输出,在最大的封装配置中可提供最多16个输入捕获、输出比较或PWM通道。
它们还能通过定时器链接功能与高级控制定时器共同工作,提供同步或事件链接功能。在调试模式下,计数器可以被冻结。任一标准定时器都能用于产生
PWM输出。每个定时器都有独立的DMA请求机制。
这些定时器还能够处理增量编码器的信号,也能处理
13个霍尔传感器的数字输出。

基本定时器-TIM6和TIM7
2个定时器主要是用于产生DAC触发信号,也可当成通用的16位时基计数器。

独立看门狗
独立的看门狗是基于一个12位的递减计数器和一个8位的预分频器,它由一个内部独立的40kHzRC振荡器提供时钟;因为这个RC振荡器独立于主时钟,所以它可运行于停机和待机模式。它可以被当成看门狗用于在发生问题时复位整个系统,或作为一个自由定时器为应用程序提供超时管理。通过选项字节可以配置成是软件或硬件启动看门狗。在调试模式下,计数器可以被冻结。

窗口看门狗
窗口看门狗内有一个7位的递减计数器,并可以设置成自由运行。它可以被当成看门狗用于在发生问题时复位整个系统。它由主时钟驱动,具有早期预警中断功能;在调试模式下,计数器可以被冻结。

系统时基定时器
这个定时器是专用于实时操作系统,也可当成一个标准的递减计数器。它具有下述特性:
24位的递减计数器
● 自动重加载功能
● 当计数器为
0时能产生一个可屏蔽系统中断
● 可编程时钟源



高级控制定时器框图



了解基本概念后,今天用通用定时器(TIM2), 写一个定时中断的程序


复制上节工程文件夹打开(这个方法比较方便)

  • 新建源文件,编辑代码
    编辑main.c, 在上节基础上增加TIM配置及中断服务函数。
    1. /**********************************************************************************
    2. * Sun STM32 mini Demo

    3. *   Description
    4.    
    5.     TIM2 Interrupt Demo

    6.    
    7. * Version    Date       Auther      Reversed History
    8.   ----------------------------------------------------------------------------
    9.   V1.0.0    2021-11-07  Lojam Fan  Fisrt Created
    10.   
    11. * (C) Sunshine Silicon Corporation
    12. *  Website: http://www.sunsili.com  http://sunsili.taobao.com http://bbs.sunsili.com
    13. *  E-Mail : fan@sunsili.com

    14. **********************************************************************************/

    15. #include "stm32f10x.h"
    16. #include "usart.h"
    17. #include "SysTick.h"
    18. #include "led.h"
    19. #include "key.h"
    20. #include <stdio.h>

    21. static u8 flag;
    22. static u8 tim2_tick;

    23. void Timer2_Init_Config(void);
    24. void RCC_Configuration(void);



    25. /*******************************************************************************
    26. * 函数名  : main
    27. * 描述    : 主函数,用户程序从main函数开始运行
    28. * 输入    : 无
    29. * 输出    : 无
    30. * 返回值  : int:返回值为一个16位整形数
    31. * 说明    : 无
    32. *******************************************************************************/
    33. int main(void)
    34. {
    35.     u8 keyVal;
    36.     RCC_Configuration();
    37.     SysTick_Init_Config();
    38.         USART1_Init_Config(115200);//USART1初始化配置
    39.     LED_GPIO_Config();
    40.     Key_GPIO_Config();
    41.     Timer2_Init_Config();        //Timer2初始化配置
    42.     printf ("*===================================================*\n");
    43.     printf ("*  *  Name: Sun STM32 mini Demo Code.    *************\n");
    44.     printf ("*  * (C) Sunshine Silicon Corporation    *************\n");
    45.     printf ("*  *  Website: http://www.sunsili.com    *************\n");
    46.     printf ("*  *   E-Mail : fan@sunsili.com          *************\n");
    47.     printf ("*===================================================*\n");
    48.     printf ("* Sun STM32 mini TIM2 Interrupt Demo code .*\n");
    49.    
    50.         while (1)
    51.         {
    52.         if(tim2_tick)
    53.         {
    54.             tim2_tick = 0;
    55.             if(flag)
    56.             {
    57.                 printf("LED ON\n");
    58.                
    59.             }
    60.             else
    61.             {
    62.                 printf("LED OFF\n");
    63.             }
    64.         }
    65.         }
    66. }

    67. /*******************************************************************************
    68. * 函数名  : Timer2_Init_Config
    69. * 描述    : Timer2初始化配置
    70. * 输入    : 无
    71. * 输出    : 无
    72. * 返回    : 无
    73. * 说明    : 无
    74. *******************************************************************************/
    75. void Timer2_Init_Config(void)
    76. {
    77.         TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    78.         NVIC_InitTypeDef NVIC_InitStructure;
    79.         
    80.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);                //使能Timer2时钟
    81.         
    82.         TIM_TimeBaseStructure.TIM_Period = 4999;                                        //设置在下一个更新事件装入活动的自动重装载寄存器周期的值(计数到5000为500ms)
    83.         TIM_TimeBaseStructure.TIM_Prescaler = 7199;                                        //设置用来作为TIMx时钟频率除数的预分频值(10KHz的计数频率)
    84.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;                //设置时钟分割:TDTS = TIM_CKD_DIV1
    85.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;        //TIM向上计数模式
    86.         TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);                                //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

    87.         /*中断优先级NVIC设置*/
    88.         NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;                                //TIM2中断
    89.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;        //先占优先级1级
    90.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                        //从优先级1级
    91.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                //使能IRQ通道
    92.         NVIC_Init(&NVIC_InitStructure);                                                         //初始化NVIC寄存器
    93.          
    94.         TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE );                                 //使能TIM2指定的中断
    95.         
    96.         TIM_Cmd(TIM2, ENABLE);                                                                          //使能TIMx外设
    97. }         

    98. /*******************************************************************************
    99. * 函数名  : TIM2_IRQHandler
    100. * 描述    : 定时器2中断服务函数
    101. * 输入    : 无
    102. * 输出    : 无
    103. * 返回    : 无
    104. * 说明    : 无
    105. *******************************************************************************/
    106. void TIM2_IRQHandler(void)   //TIM2中断服务函数
    107. {
    108.     tim2_tick = 1;
    109.         if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
    110.         {
    111.                 TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIMx更新中断标志
    112.                 if(flag)
    113.                 {
    114.                         LED4_ON();
    115.                         flag=0;
    116.                 }
    117.                 else
    118.                 {
    119.                         LED4_OFF();
    120.                         flag=1;
    121.                 }
    122.         }
    123. }

    124. /*******************************************************************************
    125. * 函数名  : RCC_Configuration
    126. * 描述    : 设置系统时钟为72MHZ(这个可以根据需要改)
    127. * 输入    : 无
    128. * 输出    : 无
    129. * 返回值  : 无
    130. * 说明    : STM32F107x和STM32F105x系列MCU与STM32F103x系列MCU时钟配置有所不同
    131. *******************************************************************************/
    132. void RCC_Configuration(void)
    133. {
    134.   ErrorStatus HSEStartUpStatus;               //外部高速时钟(HSE)的工作状态变量
    135.   
    136.   RCC_DeInit();                               //将所有与时钟相关的寄存器设置为默认值
    137.   RCC_HSEConfig(RCC_HSE_ON);                  //启动外部高速时钟HSE
    138.   HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部高速时钟(HSE)稳定

    139.   if(SUCCESS == HSEStartUpStatus)             //如果外部高速时钟已经稳定
    140.   {
    141.     /* Enable Prefetch Buffer */
    142.     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Flash设置
    143.     /* Flash 2 wait state */
    144.     FLASH_SetLatency(FLASH_Latency_2);
    145.    
    146.   
    147.     RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB时钟等于系统时钟(1分频)/72MHZ
    148.     RCC_PCLK2Config(RCC_HCLK_Div1);  //设置APB2时钟和HCLK时钟相等/72MHz(最大为72MHz)
    149.     RCC_PCLK1Config(RCC_HCLK_Div2);  //设置APB1时钟是HCLK时钟的2分频/36MHz(最大为36MHz)
    150.    
    151.     RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MHz


    152.     RCC_PLLCmd(ENABLE); //使能PLL
    153.     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //等待PLL稳定

    154.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);          //设置系统时钟的时钟源为PLL

    155.     while(RCC_GetSYSCLKSource() != 0x08);               //检查系统的时钟源是否是PLL
    156.     RCC_ClockSecuritySystemCmd(ENABLE);                 //使能系统安全时钟
    157.    
    158.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO,ENABLE);
    159.   }
    160. }



    161. /******************* (C) COPYRIGHT SUNSHINE SILICON  **************************
    162. ********************        END OF FILE main.c        *******************/
    复制代码

  • 编译调试
    保存直接编译,发现编译出错, 因为未添加tim库。解决方法添加库文件stm32f10x_tim.c
    重新编译,通过。
  • 调试
    方法不再重复,经过前两节练习,大家应该是会了.
    看到效果是, LED 1s闪烁一次,  uart1 定时打印LED状态
  • 总结课后作业
    改变TIM定时中断频率

工程源码

06STM32F103RCT6_TIM2_INT.zip (318.44 KB, 下载次数: 2)

关注谷动谷力公众号:






TIMER.png (154.55 KB, 下载次数: 125)

TIMER.png
+10

本帖被以下淘专辑推荐:

回复

使用道具 举报

沙发
发表于 2022-4-22 00:11:24 | 只看该作者

新建函数void LED_Task(void), 把LED 相关代码,整合在一起,这就慢慢,向多任务靠近了

  1. void LED_Task(void)
  2. {
  3.     if(flag)
  4.     {
  5.         LED4_ON();
  6.         flag=0;
  7.     }
  8.     else
  9.     {
  10.         LED4_OFF();
  11.         flag=1;
  12.     }
  13.     if(flag)
  14.     {
  15.         printf("LED ON\n");
  16.         
  17.     }
  18.     else
  19.     {
  20.         printf("LED OFF\n");
  21.     }
  22. }
复制代码


main函数精减, 就精减主我循环里的内容.

  1. .....
  2. while (1)
  3.         {
  4.         if(tim2_tick)
  5.         {
  6.             tim2_tick = 0;
  7.             LED_Task();
  8.         }
  9.         }
  10. .....
复制代码




TIM2中断服务函数精减,一般写程序原则:
中断服务函数尽量少指令,尽快跳出/TIM2中断服务函数,以便其他任务执行到


精减如下:

  1. void TIM2_IRQHandler(void)   //TIM2中断服务函数
  2. {
  3.     tim2_tick = 1;
  4.         if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
  5.         {
  6.                 TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIMx更新中断标志
  7.                
  8.         }
  9. }
复制代码




+10
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|深圳市光明谷科技有限公司|光明谷商城|Sunshine Silicon Corpporation ( 粤ICP备14060730号|Sitemap

GMT+8, 2024-12-26 21:17 , Processed in 0.097371 second(s), 44 queries .

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表