[蓝桥杯物联网从0开始]第15届蓝桥杯物联网省赛备赛笔记,TIM定时器的认识与使用,简单定时器控制继电器开关LED灯代码详解

//需要C语言基础

定时器理论

定时器就像是闹钟,当计时达到你设定的时间后执行你写的功能代码,在单片机中,一般我是将定时器当作第二线程来看的,因为他与主循环可以看作是同时运行又互不影响。注意,在定时器中不可写循环。

什么是定时器?

定时器通常是由计数器和一组控制寄存器组成,计数器通常用来计数,控制寄存器用来配置计数器的工作模式、计数范围、时钟源等参数。工作原理:设置一个值,计数器计数值不断累加,当达到预先设定的计数值时,就会触发中断或者输出一个脉冲信号。定时器的功能很强大,可以用来定时、计数、PWM产生、输入捕获或定时器中断等。
STM32L071KBUx定时的组成:低功耗定时器(LPTIM)、一个基本定时器、两个看门狗定时器和SysTick定时器。

下图4个可同步的通用计数器,

计数器分辨率:决定计数的范围,比如:16-bit(0-65535)

计数器类型:向上计数、向下计数、向上计数/向下计数

预分频系数:1-65536

捕捉/比较通道:PWM等。

定时器功能

要查看定时器是否有用,就要有明显的效果呈现,LED在之前的实验中已经做过了,查看原理图发现,板载继电器K1-LED与K2-LED分别对应PA11、PA12引脚,使用定时器1来控制这两个继电器的反转。

代码工程

创建工程

同理,我们先使用CubeMx创建工程,配置我们所需要模块。PA11与PA12配置为输出模式,在Timers中配置LPTIM1低功耗定时器,别忘了打开NVIC中断,工程创建过程中,我们需要配置系统时钟,我这里配置为24MHz。

代码

前面说我们将系统时钟配置为24MHz,定时器分频系数为128,那么计数器的时钟应该是24/128=187500hz,这时候将程序中的计数器值设置为18750,计数十次,那么刚好为1s。

在main中声明一个常量,计数器值为18750。

#define PERIOD 17850

在主函数初始化部分编写代码的启动函数。第一个参数是一个结构体,在lptim.c中有帮我们声明并初始化,第二个参数就是我们定义的终值,这个定时器以中断模式启动,从0x0001~0x493E(18750)反复执行,每到终值一次进入一次定时器中断。

/**
  * @brief  Start the Counter mode in interrupt mode.
  * @param  hlptim LPTIM handle
  * @param  Period Specifies the Autoreload value.
  *         This parameter must be a value between 0x0001 and 0xFFFF.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_LPTIM_Counter_Start_IT(LPTIM_HandleTypeDef *hlptim, uint32_t Period);

HAL_LPTIM_Counter_Start_IT(&hlptim1,PERIOD);

在启动文件中找到用week声明的中断函数入口,将其重新声明在main.c中,在实际操作中,我们发现他已经在stm32l0xx_it.c中声明过了,使用go to可以找到其位置,如果你想写在main.c中可以和我一样,将其注释并重申。

将.c与.h文件中的相关代码注释,也可以直接把功能写在这里。

在main.c中重写该函数并使用

每一次定时器溢出为0.1s,这里c=3,每0.3s切换一次继电器状态


int c=0;
void LPTIM1_IRQHandler(void)
{
  /* USER CODE BEGIN LPTIM1_IRQn 0 */
	if(++c>3)
	{
		c=0;
		HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_12);
	}
  /* USER CODE END LPTIM1_IRQn 0 */
  HAL_LPTIM_IRQHandler(&hlptim1);
  /* USER CODE BEGIN LPTIM1_IRQn 1 */

  /* USER CODE END LPTIM1_IRQn 1 */
}

最后

如果你是新手,不知道这些函数怎么来的,那么久按照我图片里的代码将其函数名完整敲出来,再使用Ctrl+F查找或者goto功能找,找得多了后面自然就知道了。

这个简单的实验就做完了,由于是用CubeMx直接创建的工程,跳过了代码初始化步骤,这对于不想了解代码意思的人很友好,会用就行,但是我还是要了解一下的。

代码详解

gpio.c

在工程创建时,我们直接用鼠标配置了引脚为输出模式,最后生成的初始化函数如下,

首先实例化结构体,在结构体中有pin、mode、pull、speed4个需要配置。

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_RESET);

  /*Configure GPIO pins : PA11 PA12 */
  GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

顾名思义:

Pin:引脚,代表你要配置的具体引脚,多个引脚用|分割,整组引脚可使用all来选择。

GPIO_PIN_All

Mode:一般理解为模式,引脚可配置模式如下,常用的有GPIO_MODE_INPUT输入模式,GPIO_MODE_OUTPUT_PP推挽输出模式,(MODE_INPUT | EXTI_IT | TRIGGER_RISING | TRIGGER_FALLING)外部中断的上升沿、下降沿、浮空模式。

/** @defgroup GPIO_mode_define Mode definition
  * @brief GPIO Configuration Mode
  *        Elements values convention: 0x00WX00YZ
  *           - W  : EXTI trigger detection on 3 bits
  *           - X  : EXTI mode (IT or Event) on 2 bits
  *           - Y  : Output type (Push Pull or Open Drain) on 1 bit
  *           - Z  : GPIO mode (Input, Output, Alternate or Analog) on 2 bits
  * @{
  */ 
#define  GPIO_MODE_INPUT                        MODE_INPUT                                                  /*!< Input Floating Mode                   */
#define  GPIO_MODE_OUTPUT_PP                    (MODE_OUTPUT | OUTPUT_PP)                                   /*!< Output Push Pull Mode                 */
#define  GPIO_MODE_OUTPUT_OD                    (MODE_OUTPUT | OUTPUT_OD)                                   /*!< Output Open Drain Mode                */
#define  GPIO_MODE_AF_PP                        (MODE_AF | OUTPUT_PP)                                       /*!< Alternate Function Push Pull Mode     */
#define  GPIO_MODE_AF_OD                        (MODE_AF | OUTPUT_OD)                                       /*!< Alternate Function Open Drain Mode    */

#define  GPIO_MODE_ANALOG                       MODE_ANALOG                                                 /*!< Analog Mode  */
    
#define  GPIO_MODE_IT_RISING                    (MODE_INPUT | EXTI_IT | TRIGGER_RISING)                     /*!< External Interrupt Mode with Rising edge trigger detection          */
#define  GPIO_MODE_IT_FALLING                   (MODE_INPUT | EXTI_IT | TRIGGER_FALLING)                    /*!< External Interrupt Mode with Falling edge trigger detection         */
#define  GPIO_MODE_IT_RISING_FALLING            (MODE_INPUT | EXTI_IT | TRIGGER_RISING | TRIGGER_FALLING)   /*!< External Interrupt Mode with Rising/Falling edge trigger detection  */
 
#define  GPIO_MODE_EVT_RISING                   (MODE_INPUT | EXTI_EVT | TRIGGER_RISING)                     /*!< External Event Mode with Rising edge trigger detection             */
#define  GPIO_MODE_EVT_FALLING                  (MODE_INPUT | EXTI_EVT | TRIGGER_FALLING)                    /*!< External Event Mode with Falling edge trigger detection            */
#define  GPIO_MODE_EVT_RISING_FALLING           (MODE_INPUT | EXTI_EVT | TRIGGER_RISING | TRIGGER_FALLING)   /*!< External Event Mode with Rising/Falling edge trigger detection     */

Pull:上拉、下拉、不上也不下,理解为浮空。

/** @defgroup GPIO_pull_define Pull definition
  * @brief GPIO Pull-Up or Pull-Down Activation
  * @{
  */
#define  GPIO_NOPULL        (0x00000000U)   /*!< No Pull-up or Pull-down activation  */
#define  GPIO_PULLUP        (0x00000001U)   /*!< Pull-up activation                  */
#define  GPIO_PULLDOWN      (0x00000002U)   /*!< Pull-down activation                */

Speed:速度。GPIO的输入输出速度,看注释的xMHz大小就好了,一般默认选择HIGH,

/** @defgroup GPIO_speed_define Speed definition
  * @brief GPIO Output Maximum frequency
  * @{
  */
#define  GPIO_SPEED_FREQ_LOW              (0x00000000U)  /*!< range up to 0.4 MHz, please refer to the product datasheet */
#define  GPIO_SPEED_FREQ_MEDIUM           (0x00000001U)  /*!< range 0.4 MHz to 2 MHz, please refer to the product datasheet */
#define  GPIO_SPEED_FREQ_HIGH             (0x00000002U)  /*!< range   2 MHz to 10 MHz, please refer to the product datasheet */
#define  GPIO_SPEED_FREQ_VERY_HIGH        (0x00000003U)  /*!< range  10 MHz to 35 MHz, please refer to the product datasheet */

lptim.c

再来看低功耗定时器,初始化函数如下。同样的,第一行我们理解为实例化结构体,再对结构体里的内容进行一一配置。在下方逐行解释,由于这部分源代码太多,感兴趣的可以使用goto去查看源代码与注释,配合手册效果更佳。


LPTIM_HandleTypeDef hlptim1;
void MX_LPTIM1_Init(void)
{

  hlptim1.Instance = LPTIM1;
  hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
  hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV128;
  hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
  hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
  hlptim1.Init.UpdateMode = LPTIM_UPDATE_ENDOFPERIOD;
  hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
  if (HAL_LPTIM_Init(&hlptim1) != HAL_OK)
  {
    Error_Handler();
  }

}
  • hlptim1.Instance = LPTIM1;:指定使用的定时器实例为LPTIM1。。

  • hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;:设置定时器时钟源为APB时钟和LPOSC(低功耗振荡器)。

  • hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV128;:设置时钟预分频器为128,这意味着输入到定时器的时钟信号将被分频为原始频率的1/128。

  • hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;:设置定时器触发源为软件触发,也就是通过软件命令来触发定时器开始计数。

  • hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;:设置定时器输出极性为高电平。

  • hlptim1.Init.UpdateMode = LPTIM_UPDATE_ENDOFPERIOD;:设置定时器更新模式为在计时周期结束时更新。

  • hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;:设置定时器计数源为内部计数器。

  • 15
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Azhuo9527

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值