打印

定时器点灯

[复制链接]
1374|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
610u|  楼主 | 2024-3-31 12:30 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
定时器基本知识
1、什么是定时器
定时器是单片机内部集成,可以通过编程控制。单片机的定时功能是通过计数来实现的,当单 片机每一个机器周期产生一个脉冲时,计数器就加一。定时器的主要功能是用来计时,时间到达之 后可以产生中断,提醒计时时间到,然后可以在中断函数中去执行功能。

2、GD32定时器
GD32F450ZGT6 一共有 14 个定时器,可以分为五种类型,高级定时器 0/7、通用定时器(L0)1-4、 通用定时器(L1)8/11、通用定时器(L2)9/10/12/13 和基本定时器 5/6。
高级定时器(TIMER0 和 TIMER7):是四通道定时器,支持输入捕获和输出比较。可以产生 PWM 信号控制电机和电源管理。高级定时器包含了一个死区时间插入模块,非常适合电机控制。
通用定时器(L0)(TIMER0 和 TIMER7):是四通道定时器,支持输入捕获和输出比较。可以产生 PWM 信号控制电机和电源管理。高级定时器包含了一个死区时间插入模块,非常适合电机控制。
通用定时器(L1)(TIMER8 和 TIMER11):是两通道定时器,支持输入捕获和输出比较,可以产生 PWM 信号控制电机和电源管理。
通用定时器 (L2)(TIMER9、TIMER10、TIMER12 和 TIMER13):是单通道定时器,支持输入捕获,输 出比较,产生 PWM 信号控制电机和电源管理。
基本定时器(TIMER5 和 TIMER6):包含一个无符号的 16 位计数器。可以被用作通用定时器和为 DAC(数字到模拟转换器)提供时钟。基本定时器可以配置产生 DMA 请求,TRGO 触发连接到 DAC。

2、定时器基本参数
预分频
预分频器可以将定时器的时钟(TIMER_CK)频率按 1 到 65536 之间的任意值分频,分频后的时钟 PSC_CLK 驱动计数器计数。分频系数受预分频器 TIMERx_PSC 控制。这个控制寄存器带有缓冲器,它 能够在运行时被改变。新的预分频器的参数在下一次更新事件到来时被采用。 分频器的分频公式为:PSC_CLK = TIMER_CK/ (TIMERx_PSC +1)
向上计数模式
计数器从 0 开始向上连续计数到自动加载值(定义在 TIMERx_CAR 寄存器中),一旦计数器计 数到自动加载值,会重新从 0 开始向上计数并产生上溢事件。
更新事件
更新事件是当计数器上溢或者下溢而开始新的计数周期时触发的。更新事件可以触发 DMA 请 求,以用于在下一个计数周期开始时及时更新定时器的运行参数,特别适合用于实时控制。

使用特权

评论回复
沙发
610u|  楼主 | 2024-3-31 12:31 | 只看该作者
定时器实现LED灯闪烁
配置流程
1、 开启时钟(定时器时钟)
2、 配置定时器参数
3、使能中断事件和定时器
4、编写中断服务函数

1、开启时钟

从图 可以看到 14 个定时器的时钟来源主要分为两部分,第一部分来源于 CK_APB1,第二 部分来源于 CK_APB2。然后经过时钟配置寄存器(RCU_CFG1)决定是 APB 频率的 2 倍还是 4 倍,但 这个频率不能超过 AHB(max = 200MHZ)。 这里使用 TIMER5,就要先使能 TIMER5 的时钟,又因为 TIMER5 时钟来源于 CK_APB1,CK_APB1的时钟在 system_gd32f4xx.c 中定义。

rcu_periph_clock_enable(RCU_TIMER5);//开启定时器时钟
1
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);//配置定时器时钟预分频系数 200M

使用特权

评论回复
板凳
610u|  楼主 | 2024-3-31 12:31 | 只看该作者
配置定时器参数
复位定时器
timer_deinit(RCU_TIMER5); // 复位定时器
1
定时器初始化
定时器初始化需要用到void timer_init(uint32_t timer_periph, timer_parameter_struct* initpara);这个函数。有两个参数,第一个参数就是定时器外设,第二个参数 就是一个定时器参数结构体,


使用特权

评论回复
地板
610u|  楼主 | 2024-3-31 12:32 | 只看该作者

    timer_parameter_struct timer_initpara;
    timer_initpara.prescaler=pre - 1;// 决定一个计数周期的时间 PSC_CLK=TIMER_CK / (pre + 1)                 
    timer_initpara.alignedmode= TIMER_COUNTER_EDGE;//   边沿对齐模式                       
    timer_initpara.counterdirection= TIMER_COUNTER_UP;//向上计数  计数模式,基本定时器只有向上计数模式,所以配置为 TIMER_COUNTER_UP。           
    timer_initpara.clockdivision=TIMER_CKDIV_DIV1; //:时钟分频,在输入捕获的时候使用,定时器时钟频率与死区发生器和数字滤波器使 用的采样频率之间的分频比。               
    timer_initpara.period=per - 1; //周期值,是一个 16 位的计数器,最大值为 65535,当计数器达到设置的周期数值(自动 重装载寄存器)时数值清零,配合计数器时钟频率可以计算中断时间。
    timer_initpara.repetitioncounter=0;  //重复计数器(只有高级定时器有),取值范围为 0-255,配置为 x,就重复 x+1 次才进入中断。
    //time = pre / 200 000 000 * per
    timer_init(BSP_TIMER5, &timer_initpara);//初始化定时器
    nvic_irq_enable(TIMER5_DAC_IRQn, 3, 2);//使能nvic定时器
    timer_interrupt_enable(TIMER5, TIMER_INT_UP);//使能定时器更新中断
    timer_enable(TIMER5);//使能定时器

设置中断优先级
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);//设置中断响应优先级分组2 子优先级2

使用特权

评论回复
5
610u|  楼主 | 2024-3-31 12:33 | 只看该作者
编写定时器中断服务函数
与按键中断一样,定时器中断也有固定的中断函数名称。
void TIMER5_DAC_IRQHandler(void)
{
  if(timer_interrupt_flag_get(BSP_TIMER5, TIMER_INT_FLAG_UP)==SET)获取定时器更新中断标志
  {
    timer_interrupt_flag_clear(BSP_TIMER5, TIMER_INT_FLAG_UP);//清除定时器更新中断标志
    gpio_bit_toggle(GPIOD,GPIO_PIN_7);
    printf("BSP_TIMER_IRQHANDLER!\r\n");
  }
}
//注意中断函数最后要清除中断标志位,否则会一直进入中断函数

使用特权

评论回复
6
610u|  楼主 | 2024-3-31 12:33 | 只看该作者
源代码
/*
*  Author: carpe diem  2116815480@qq.com
*  Date: 2023-04-04 20:39:02
*  LastEditTime: 2023-04-06 20:58:04
*  FilePath: \Projectf:\Desktop\file\KEIL CODE\梁山派开发板\008定时器点灯\Hardware\timer\bsp_basic_timer.c
*  Description: bsp_basic_timer.c 定时器点灯
*
* Copyright (c) 2023 by carpe diem, All Rights Reserved.
*/

#include "bsp_basic_timer.h"
#include <stdio.h>
/**
*  description: 定时器中断初始化
*  param {uint16_t} pre 预分频值
*  param {uint16_t} per 周期值
*  return {*}
*/
void basic_timer_config(uint16_t pre, uint16_t per)
{
    timer_parameter_struct timer_initpara;
    rcu_periph_clock_enable(BSP_TIMER_RCU);//开启定时器时钟
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);//配置定时器时钟为 200M
    timer_deinit(BSP_TIMER5);//复位定时器
    timer_initpara.prescaler=pre - 1;//预分频值   :这个参数是时钟的预分频值,是 16 位的,取值范围为 1-65535。
    //TIMER_CK 经过预分频之后得到 PSC_CLK。每经过一个 PSC_CLK 都会产生一个计数周期,prescaler 参数将决定一个计数周期的时间。
    //设预分频值为 pre,则计数器时钟频率 PSC_CLK=TIMER_CK / (pre + 1)。               
    timer_initpara.alignedmode= TIMER_COUNTER_EDGE;//   边沿对齐模式                       
    timer_initpara.counterdirection= TIMER_COUNTER_UP;//向上计数  计数模式,基本定时器只有向上计数模式,所以配置为 TIMER_COUNTER_UP。           
    timer_initpara.clockdivision=TIMER_CKDIV_DIV1; //时钟分频因子为1   :时钟分频,在输入捕获的时候使用,定时器时钟频率与死区发生器和数字滤波器使 用的采样频率之间的分频比。               
    timer_initpara.period=per - 1; //自动重装载值 周期值,是一个 16 位的计数器,最大值为 65535,当计数器达到设置的周期数值(自动 重装载寄存器)时数值清零,配合计数器时钟频率可以计算中断时间。
    timer_initpara.repetitioncounter=0;  //重复计数器 重复计数器(只有高级定时器有),取值范围为 0-255,配置为 x,就重复 x+1 次才进入中断。
   
    //time = pre / 200 000 000 * per

    timer_init(BSP_TIMER5, &timer_initpara);//初始化定时器
    nvic_irq_enable(BSP_TIMER5_IRQn, 3, 2);//使能nvic定时器中断
    timer_interrupt_enable(BSP_TIMER5, TIMER_INT_UP);//使能定时器更新中断
    timer_enable(BSP_TIMER5);//使能定时器
}
/**
*  description: 定时器中断服务函数
*  return {*}
*/
void BSP_TIMER5_IRQHandler(void)
{
  if(timer_interrupt_flag_get(BSP_TIMER5, TIMER_INT_FLAG_UP)==SET)//获取定时器更新中断标志
  {
    timer_interrupt_flag_clear(BSP_TIMER5, TIMER_INT_FLAG_UP);//清除定时器更新中断标志
    gpio_bit_toggle(GPIOD,GPIO_PIN_7);//翻转PD7
    printf("BSP_TIMER_IRQHANDLER!\r\n");//打印信息
  }
}
//注意中断函数最后要清除中断标志位,否则会一直进入中断函数

使用特权

评论回复
7
610u|  楼主 | 2024-3-31 12:33 | 只看该作者
/*
*  Author: carpe diem  2116815480@qq.com
*  Date: 2023-04-04 20:39:38
*  LastEditTime: 2023-04-06 20:58:32
*  FilePath: \Projectf:\Desktop\file\KEIL CODE\梁山派开发板\008定时器点灯\Hardware\timer\bsp_basic_timer.h
*  Description: bsp_basic_timer.h 定时器点灯
*
* Copyright (c) 2023 by carpe diem, All Rights Reserved.
*/

#ifndef _BSP_BASIC_TIMER_H_
#define _BSP_BASIC_TIMER_H_

#include "gd32f4xx.h"
#include "systick.h"
#define BSP_TIMER_RCU RCU_TIMER5
#define BSP_TIMER5 TIMER5
#define BSP_TIMER5_IRQn TIMER5_DAC_IRQn
#define BSP_TIMER5_IRQHandler TIMER5_DAC_IRQHandler


void basic_timer_config(uint16_t pre, uint16_t per);//定时器中断初始化
void BSP_TIMER5_IRQHandler(void);//定时器中断服务函数


#endif

使用特权

评论回复
8
610u|  楼主 | 2024-3-31 12:33 | 只看该作者
/*!
    \file    main.c
    \brief   led spark with systick

    \version 2016-08-15, V1.0.0, firmware for GD32F4xx
    \version 2018-12-12, V2.0.0, firmware for GD32F4xx
    \version 2020-09-30, V2.1.0, firmware for GD32F4xx
    \version 2022-03-09, V3.0.0, firmware for GD32F4xx
*/

/*
    Copyright (c) 2022, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors
       may be used to endorse or promote products derived from this software without
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "bsp_led.h"
#include "sys.h"
#include "bsp_usart.h"
#include "bsp_key.h"
#include "bsp_basic_timer.h"

/*!
    \brief    main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{

    systick_config();
        nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);//设置中断响应优先级分组2 子优先级2
        led_gpio_config();//led的初始化
    key_gpio_config();//按键的初始化
        //gpio_bit_set(GPIOD,GPIO_PIN_7);
    usart_gpio_config(9600);//串口的初始化
    basic_timer_config(20000,10000);//定时器的初始化
   
   
  

    while(1)
   {
       
   
   }
}

使用特权

评论回复
9
shenxiaolin| | 2024-4-30 16:12 | 只看该作者
定时器实现LED灯闪烁
配置流程
1、 开启时钟(定时器时钟)
2、 配置定时器参数
3、使能中断事件和定时器
4、编写中断服务函数

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

373

帖子

0

粉丝