STM32 Timer (2) 定时器中断代码框架

3. 代码框架

3.1 分频系数的计算

         x1/x2                /N(预分频)
APB1时钟------->F(CK_PSC)--------------->CK_CNT

如果APB1的分频系数为1, CK_INT的倍频系数就是x1
如果APB1的分频系数不为1, CK_INT的倍频系数就是x2
 
STM32F1(MHz)
STM32F4(MHz)
STM32F7(MHz)
SYSCLK 72 168 216
AHB 72 168 216
APB1 (AHB/4) 18 42 54
CK_INT(x1/x2) 36 84 108
PSC预分频      
举例:实现 0.5s 的led闪烁
当前使用F7 所以 

CK_INT = 108MHz
PSC预分频:Prescaler
自动重装载寄存器: Period

time =  (Period)(Prescaler)/CK_INT

0.5 = (Period)(Prescaler)/108000000

预分频 Prescaler 方便计算 设置为 108000(整除),
自动重装载 Period 设置为 500
计算: 500*108000/108000000 = 0.5

但是,因为受到16位寄存器的约束, 108000 超过的65535(2的16次方)
所以稍微调整:
5000 * 10800 同样满足要求。 

所以配置:
Prescaler = 10800
Period = 5000

根据定时需求调整
time =  (Period)(Prescaler)/CK_INT

3.2 代码细讲

从 int main()
{

}开始了解定时器的实现
// 1.使能定时器时钟
__HAL_RCC_TIM3_CLK_ENABLE();

//2. 初始话定时器,配置Prescaler,Period
HAL_TIM_Base_Init();

// 3. 开启定时器/中断
HAL_TIM_Base_Start();
HAL_TIM_Base_Start_IT();

// 4. 设置中断优先级
HAL_NVIC_SetPriority(); HAL_NVIC_EnableIRQ();

// 5. 编写中断服务函数
TIMx_IRQHandler();    //中断服务函数
HAL_TIM_IRQHandler(); //中断处理入口函数
HAL_TIM_PeriodElapsedCallback();//定时器更新中断回调函数
//正式开始
// 1. 自定义一个TIM初始化函数
void TIM3_Init()
{
    //...

}

int main()
{
    TIM3_Init();
}
//Tim3_Init()做些什么事?
void TIM3_Init()
{
    //1. 定时器初始化函数
    HAL_TIM_Base_Init(); //需要一个参数
}

//函数原型: HAL_StatusTypeDef HAL_TIM_Base_Init(TIM_HandleTypeDef *htim)
//所以设置TIM句柄
TIM_HandleTypeDef htim3;

//设置了句柄,就要对其中的参数进行初始化
htim3.Instance = TIM3;
htim3.Init.Prescaler = 10800-1;                     //预分频系数
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;        //计数模式
htim3.Init.Period = 5000-1;                         //自动装载值
//结果:

TIM_HandleTypeDef htim3;
void TIM3_Init()
{
    htim3.Instance = TIM3;
    htim3.Init.Prescaler = 10800-1;                     //预分频系数
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;        //计数模式
    htim3.Init.Period = 5000-1;                         //自动装载值
    HAL_TIM_Base_Init(htim3);
}
//2. 然后嘞就要使能时钟定时器
//在HAL_TIM_Base_Init(htim3) 函数中有:
HAL_TIM_Base_MspInit(htim);

//这个函数Msp 表示回调函数, 一般在文件stm32f4xx_hal_msp.c文件中,如果没有,自己实现也是一样
// 这个函数主要实现 时钟的开启, GPIO的配置, 中断优先级的配置
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
    if(htim_base->Instance==TIM3)
    {
        __HAL_RCC_TIM3_CLK_ENABLE();
    }
}

//因为HAL_TIM_Base_Init 这个函数不仅仅针对与TIM3, 所以在Msp函数中, 要进行if判断
htim_base->Instance==TIM3
//在这个函数中, 进行 TIM时钟的开启
__HAL_RCC_TIM3_CLK_ENABLE();
// 3.开启Tim3且中断
void TIM3_Init()
{
    htim3.Instance = TIM3;
    htim3.Init.Prescaler = 10800-1;                     //预分频系数
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;        //计数模式
    htim3.Init.Period = 5000-1;                         //自动装载值
    HAL_TIM_Base_Init(htim3);

    //new
    HAL_TIM_Base_Start_IT(&htim3);                         //开启定时器中断
}
//4 .开启了中断后,就要设置中断优先级
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
    if(htim_base->Instance==TIM3)
    {
        __HAL_RCC_TIM3_CLK_ENABLE();

        //中断优先级
        HAL_NVIC_EnableIRQ(TIM3_IRQn);
        HAL_NVIC_SetPriority(TIM3_IRQn,1,3);

    }
}
// 5. 编写中断服务函数
//在start.s文件中,有中断触发函数列表,查找之。
void TIM3_IRQHandler(void)
{
    //待编写
}
//写什么呢,TIM的api中,有中断触发函数
HAL_TIM_IRQHandler(&htim3);

--->
void TIM3_IRQHandler(void)
{
   HAL_TIM_IRQHandler(&htim3);
} 

//继续跟踪  HAL_TIM_IRQHandler(&htim3);
 /* TIM Update event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->PeriodElapsedCallback(htim);
#else
      HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }

//有各种各样的中断,这里实现更新中断, 调用了 HAL_TIM_PeriodElapsedCallback(htim);
//所以重写回调函数HAL_TIM_PeriodElapsedCallback(htim);
//time更新回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    //LED 反转
}

3.3 全代码

其中LED的初始化基于RT-thread, 若非RTOS自行替换,跟框架无关。

main.c

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#define LED0    GET_PIN(B,0)
#define LED1    GET_PIN(B,1)

static rt_uint8_t flag = 0;
TIM_HandleTypeDef htim3;
void TIM3_Init()
{
    htim3.Instance = TIM3;
    htim3.Init.Prescaler = 10800-1;                    //预分频系数
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;        //计数模式
    htim3.Init.Period = 5000-1;                         //自动装载值

    HAL_TIM_Base_Init(&htim3);

    HAL_TIM_Base_Start_IT(&htim3);                      //开启tim3中断

    //因为开启了中断,所以要设置中断优先级
    //本来要自己实现中断函数HAL_TIM_Base_MspInit 的,但是在
    //stm32f7xx_hal_msp.c文件中已经写了,所以去这个文件编写中断优先级
}
//中断配置后,实现中断服务函数
//中断服务函数
void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim3);
}

//time更新回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(flag == 0)
    {
        rt_pin_write(LED0,PIN_LOW);
        flag = 1;
        return;
    }

    if(flag == 1)
    {
        rt_pin_write(LED0,PIN_HIGH);
        flag = 0;
        return;
    }
}

void LED_Init(void)
{
    rt_pin_mode(LED0,PIN_MODE_OUTPUT);
}

int main(void)
{
    LED_Init();
    TIM3_Init();

    return 0;
}

htm32f7xx_hal_msp.c

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
    if(htim_base->Instance==TIM3)
    {
        __HAL_RCC_TIM3_CLK_ENABLE();

        //中断优先级
        HAL_NVIC_EnableIRQ(TIM3_IRQn);
        HAL_NVIC_SetPriority(TIM3_IRQn,1,3);

    }
 }

原文地址:https://www.cnblogs.com/kmist/p/11669262.html

时间: 2024-10-11 11:22:45

STM32 Timer (2) 定时器中断代码框架的相关文章

STM32 Timer (1) 定时器分类和框图

1.定时器简单分类 1. 高级控制定时器 TIM1 TIM8 2. 通用定时器 TIM2 TIM3 TIM4 TIM5 3. 基本定时器 TIM6 TIM7 定时器: 1. 16/32位 向上 向下 上下 计数模式, 自动重装载计数器 TIMx_CNT 2. 16位可编程(实时修改) 预分频器(TIMx_PSC) 3. 4个独立通道(TIMx_CH1 ~ 4) 输入捕获 输出比较 PWM生成 单脉冲模式 4. 可以和外部定时器集联 2. 定时器结构图 定时器结构框图分为5部分 时钟产生部分 定时

stm32通用定时器中断问题

在使用stm32的通用定时器定时中断的时候,发现定时器在完成初始化配置后,定时器UIF位会立刻置位,导致在使能中断后,程序会立刻进入定时器中断. 如果设计代码时不希望定时器配置完成后,立刻进入中断,可以在定时器配置完成后,立刻清除UIF标志位(TIMx->SR &= 0xFFFE) ,再使能定时器更新中断.比如用库函数这么写: TIM_ClearITPendingBit(TIM4, TIM_IT_Update  ); TIM_ITConfig(TIM4,TIM_IT_Update,ENABL

79.ZYNQ内部私有定时器中断

上篇文章实现了了PS接受来自PL的中断,本片文章将在ZYNQ的纯PS里实现私有定时器中断.每个一秒中断一次,在中断函数里计数加1,通过串口打印输出. *本文所使用的开发板是Miz702(兼容zedboard) PC 开发环境版本:Vivado 2015.2 Xilinx SDK 2015.2* 中断原理 中断对于保证任务的实时性非常必要,在ZYNQ里集成了中断控制器GIC(Generic Interrupt Controller).GIC可以接受I/O外设中断IOP和PL中断,将这些中断发给CP

cortex_m3_stm32嵌入式学习笔记(八):定时器中断实验

STM32 的定时器功能十分强大,有 TIME1 和 TIME8 等高级定时器,也有 TIME2~TIME5 等通用定时器,还有 TIME6 和TIME7 等基本定时器. 本节学习通用定时器 TIM3 STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等. STM3 的通用 TIMx (TIM2. TIM3. TIM4 和 TIM5)定时器功能包括: 1)16 位向上.向下.向上/向下自动装载计数器( TIMx_CNT). 2)16 位可

定时器中断各个寄存器含义

中断寄存器,定时器/计数器相关寄存器本身或者相关位用来做初始化,中断函数的内容主要是体现发生中断后所需要的操作(在中断函数内写代码). 1.中断允许寄存器IE 图1.中断寄存器IE 中断寄存器用来设定各个中断源的打开和关闭,IE在特殊功能寄存器中,字节地址为A8H,位地址(由低位到高位)分别是A8H~AFH,该寄存器运行位寻址,即可对该寄存器的每一位进行单独操作.单片机复位时IE全部被清零.下面列举各位的在不同状态下的具体含义: EA-------全局中断允许位 EA = 1,打开全局中断控制,

[stm32] STM32的通用定时器TIMx系统了解

通用定时器(TIMx) 一.TIMx简介 二.TIMx主要功能 三.TIMx功能描述 3.1 时基单元 3.2 计数器模式 3.3 时钟选择 3.4 捕获/比较通道 3.5 输入捕获模式 3.6 PWM输入模式 3.7 强置输出模式 3.8 输出比较模式 3.9 PWM 模式 3.10 单脉冲模式 四.简单例子理解TIMx 4.1 使得PB5-TIM3通道2产生频率为12.5Hz的方波,该方波控制LED1的闪烁 4.2 周期控制通用定时器3的2通道,实现1KHz的不同占空比波形,控制LED实现呼

AVR单片机教程——定时器中断

本文隶属于AVR单片机教程系列. ? 中断,是单片机的精华. 中断基础 当一个事件发生时,CPU会停止当前执行的代码,转而处理这个事件,这就是一个中断.触发中断的事件成为中断源,处理事件的函数称为中断服务程序(ISR). 中断在单片机开发中有着举足轻重的地位--没有中断,很多功能就无法实现.比如,在程序干别的事时接受UART总线上的输入,而uart_scan_char等函数只会接收调用该函数后的输入,先前的则会被忽略.利用中断,我们可以在每次接受到一个字节输入时把数据存放到缓冲区中,程序可以从缓

使用EA生成多层次的代码框架

最近工作期间发现了一个非常棒的UML软件[Enterprise Architect UML 建模工具]简称EA,在该软件上绘制框架层面的类之间关系后,可以自动生成相关语言的代码. EA上目前支持的语言有 下面我们将演示,如何生成多层次的python代码框架,EA软件默认的代码是Java,我们需要定制成python,而这个定制在项目内有效,即是对项目属性进行定制. 这里我们建立一个python_hello的项目.顺序是:新建项目=====> 新建增图=====>添加图A=====>添加包=

轮询算法设计及其代码框架

在实际的软件开发项目中,经常会遇到某模块需要向其它模块发消息的情况.为了减轻消息接收者的负担,我们会采用一种叫做轮询的机制来发送消息.本文介绍轮询算法的流程及其代码框架. 1.算法流程 假设消息发送模块为模块A,消息接收模块为模块B.模块A安装了一个,模块B安装了N个.所有模块都同时启动. 算法流程如图1所示: 图1 轮询算法流程 2.代码框架 static int g_iSendIdx = 0; for (iLoopFlag = 0; iLoopFlag < N; iLoopFlag ++)