PY32F003F18之输入捕获

输入捕获是定时器的功能之一,配合外部引脚,捕获脉宽时间或采集周期。

CPU中的定时器最基本的功能就是计数功能,其次是输入捕获(IC),再次就是比较输出(OC),还有就是使用引脚对外部时钟进行计数,触发信号捕捉等。

1、输入捕获功能图:

2、测试程序

#include "TIM1_EdgeAligned_InputCapture.h"
#include "LED.h"

/*
将PA3复用为TIM1_CH1,用作捕获信号输入引脚,
PA4为TIM3中断时输出的信号,将这两个脚短接,使用示波器跟踪PA0的信号,就可以测试。
*/

void TIM1_COUNTERMODE_UP_IC1_Init(uint16_t arr,uint16_t psc);
void TIM3_COUNTERMODE_UP_Init(uint16_t arr,uint16_t psc);

void HAL_TIM_IC_MspInit1(TIM_HandleTypeDef *htim)
{
	GPIO_InitTypeDef   GPIO_InitStructure;

	if(htim->Instance == TIM1)//初始化TIM1
	{
    __HAL_RCC_TIM1_CLK_ENABLE();  //使能TIM1时钟
	  __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟

	  GPIO_InitStructure.Pin = GPIO_PIN_3;       //选择第3脚,PA3是为TIM1_CH1
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; //复用功能推挽模式
    GPIO_InitStructure.Pull = GPIO_PULLUP;     //引脚上拉被激活
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //引脚速度为最高速
    GPIO_InitStructure.Alternate = GPIO_AF13_TIM1;//选择AF13,将PA3引脚复用为TIM1_CH1
    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
	  //根据GPIO_InitStructureure结构变量指定的参数初始化GPIOA的外设寄存器
	  //将PA3初始化为TIM1_CH1功能,用作IC11输入捕获引脚

    HAL_NVIC_SetPriority(TIM1_CC_IRQn,1, 0); //设置"捕获/比较"的中断优先级为1
    HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);        //开启"捕获/比较"总中断
	}
	if(htim->Instance == TIM3)//初始化TIM3
	{
	}
}

//函数功能:TIM1中基本计数功能,并使能了更新中断,每次重装ARR值时会产生一次更新中断
//arr:自动重装值。
//psc:时钟预分频数
//TIM1_COUNTERMODE_UP_IC1_Init(20000,240);//若使用HSE,当arr=20000,psc=240时,则为200ms,误差为10us;
//TIM1_COUNTERMODE_UP_IC1_Init(20000,80);//若使用HSI,当arr=20000,psc=80时,则为200ms,误差为10us;
void TIM1_COUNTERMODE_UP_IC1_Init(uint16_t arr,uint16_t psc)
{
	GPIO_InitTypeDef   GPIO_InitStructure;
	TIM_HandleTypeDef  TIM1_HandleStructure;
	TIM_IC_InitTypeDef TIM1_IC_InitStructure;

//HAL_TIM_IC_MspInit开始/
  __HAL_RCC_TIM1_CLK_ENABLE();  //使能TIM1时钟
	__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟

	GPIO_InitStructure.Pin = GPIO_PIN_3;       //选择第3脚,PA3是为TIM1_CH1
  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; //复用功能推挽模式
  GPIO_InitStructure.Pull = GPIO_PULLUP;     //引脚上拉被激活
  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //引脚速度为最高速
  GPIO_InitStructure.Alternate = GPIO_AF13_TIM1;//选择AF13,将PA3引脚复用为TIM1_CH1
  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
	//根据GPIO_InitStructureure结构变量指定的参数初始化GPIOA的外设寄存器
	//将PA3初始化为TIM1_CH1功能,用作IC11输入捕获引脚

  HAL_NVIC_SetPriority(TIM1_CC_IRQn,1, 0); //设置"捕获/比较"的中断优先级为1
  HAL_NVIC_EnableIRQ(TIM1_CC_IRQn);        //开启"捕获/比较"总中断
//HAL_TIM_IC_MspInit结束/

  TIM1_HandleStructure.Instance = TIM1;   //选择TIM1
  TIM1_HandleStructure.Init.Period            = arr-1;
	//设置在下一个更新事件产生时,装入"自动重载入寄存器TIMx_ARR"的值
	//将(arr-1)写入"自动重载入寄存器TIMx_ARR",设置自动重装载值
  TIM1_HandleStructure.Init.Prescaler         = psc-1;
	//设置用来作为TIMx时钟频率除数的预分频值
	//将(psc-1)写入"预装载寄存器TIMx_PSC",的PSC[15:0],设置预分频值
	//计数器的时钟频率CK_CNT=fCK_PSC/(PSC[15:0]+1)
  TIM1_HandleStructure.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;//时钟不分频,则tDTS=tCK_INT
	//若使用HSE,计算公式:arr*psc/24000000/1,当arr=20000,psc=240时,则为200ms,误差为10us;
	//若使用HSI,计算公式:arr*psc/8000000/1,当arr=20000,psc=80时,则为200ms,误差为100us;
  TIM1_HandleStructure.Init.CounterMode       = TIM_COUNTERMODE_UP;//向上计数
  TIM1_HandleStructure.Init.RepetitionCounter = 1 - 1;
	//不重复计数
	//将(1-1)写入"重复计数寄存器TIMx_RCR"中的REP[7:0],设置"重复计数器值"
  TIM1_HandleStructure.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
	//"自动重装载寄存器"没有缓冲
	//不允许将"TIMx自动重新加载寄存器TIMx_ARR"的值被装入缓冲区;
	HAL_TIM_Base_Init(&TIM1_HandleStructure);    //TIM1初始化
	//选择计数器模式:向上计数
	//设置时钟分频因子:时钟不分频,则tDTS=tCK_INT
	//设置自动重装载:"自动重装载寄存器"没有缓冲
	//设置自动重装载值:TIM_Base_InitStructure.Period
	//设置预分频值:TIM_Base_InitStructure.Prescaler
	//设置"重复计数器值":TIM_Base_InitStructure.RepetitionCounter
  //启动更新事件:将TIMx_EGR中的UG位置1,由软件产生更新事件

  TIM1_IC_InitStructure.ICPolarity  = TIM_ICPOLARITY_RISING;   //上升沿捕获
  TIM1_IC_InitStructure.ICSelection = TIM_ICSELECTION_DIRECTTI;//CC1通道配置为输入
  TIM1_IC_InitStructure.ICPrescaler = TIM_ICPSC_DIV1;          //输入不分频
  TIM1_IC_InitStructure.ICFilter    = 0;                       //输入无滤波
	HAL_TIM_IC_ConfigChannel(&TIM1_HandleStructure, &TIM1_IC_InitStructure, TIM_CHANNEL_1);
	//配置通道1输入捕获

	HAL_TIM_IC_Start_IT(&TIM1_HandleStructure, TIM_CHANNEL_1);
	//使能输入捕获1中断,使能输入捕获1通道
}

//函数功能:TIM3中基本计数功能,并使能了更新中断,每次重装ARR值时会产生一次更新中断
//arr:自动重装值。
//psc:时钟预分频数
//TIM3_COUNTERMODE_UP_Init(20000,240);//若使用HSE,当arr=20000,psc=240时,则为200ms,误差为10us;
//TIM3_COUNTERMODE_UP_Init(20000,80);//若使用HSI,当arr=20000,psc=80时,则为200ms,误差为10us;
void TIM3_COUNTERMODE_UP_Init(uint16_t arr,uint16_t psc)
{
	TIM_HandleTypeDef  TIM3_HandleStructure;

//HAL_TIM_Base_MspInit开始/
  __HAL_RCC_TIM3_CLK_ENABLE();           //使能TIM3时钟
  HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0); //设置中断优先级
  HAL_NVIC_EnableIRQ(TIM3_IRQn);         //使能TIM3中断
//HAL_TIM_Base_MspInit开始/

  TIM3_HandleStructure.Instance = TIM3;   //选择TIM3
  TIM3_HandleStructure.Init.Period            = arr-1;
	//设置在下一个更新事件产生时,装入"自动重载入寄存器TIMx_ARR"的值
	//将(arr-1)写入"自动重载入寄存器TIMx_ARR",设置自动重装载值
  TIM3_HandleStructure.Init.Prescaler         = psc-1;
	//设置用来作为TIMx时钟频率除数的预分频值
	//将(psc-1)写入"预装载寄存器TIMx_PSC",的PSC[15:0],设置预分频值
	//计数器的时钟频率CK_CNT=fCK_PSC/(PSC[15:0]+1)
  TIM3_HandleStructure.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;//时钟不分频,则tDTS=tCK_INT
	//若使用HSE,计算公式:arr*psc/24000000/1,当arr=20000,psc=240时,则为200ms,误差为10us;
	//若使用HSI,计算公式:arr*psc/8000000/1,当arr=20000,psc=80时,则为200ms,误差为100us;
  TIM3_HandleStructure.Init.CounterMode       = TIM_COUNTERMODE_UP;//向上计数
  TIM3_HandleStructure.Init.RepetitionCounter = 1 - 1;
	//不重复计数
	//将(1-1)写入"重复计数寄存器TIMx_RCR"中的REP[7:0],设置"重复计数器值"
  TIM3_HandleStructure.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
	//"自动重装载寄存器"没有缓冲
	//不允许将"TIMx自动重新加载寄存器TIMx_ARR"的值被装入缓冲区;
	HAL_TIM_Base_Init(&TIM3_HandleStructure);    //TIM3初始化
	//选择计数器模式:向上计数
	//设置时钟分频因子:时钟不分频,则tDTS=tCK_INT
	//设置自动重装载:"自动重装载寄存器"没有缓冲
	//设置自动重装载值:TIM_Base_InitStructure.Period
	//设置预分频值:TIM_Base_InitStructure.Prescaler
	//设置"重复计数器值":TIM_Base_InitStructure.RepetitionCounter
  //启动更新事件:将TIMx_EGR中的UG位置1,由软件产生更新事件

	HAL_TIM_Base_Start_IT(&TIM3_HandleStructure);
  //允许计数器产生"更新中断";
  //如果计数器不是工作在触发模式中,则开始计数
}

//函数功能:TIM1输入捕获中断服务程序
//IC1为上升沿捕获,所以捕获周期是TIM3周期的2倍
void TIM1_CC_IRQHandler(void)
{
HAL_TIM_PeriodElapsedCallback开始/
  if (_HAL_TIM_GET_FLAG(TIM1,TIM_FLAG_CC1) != RESET)
  {//根据TIM_FLAG_CC1,读"TIMx状态寄存器(TIMx_SR)"中输入捕获中断标志位
    _HAL_TIM_CLEAR_IT(TIM1, TIM_IT_CC1);
		//TIM_IT_CC1,令CC1IF=0,清除输入捕获中断标志位
    TIM1_LED_Toggle();
  }
HAL_TIM_PeriodElapsedCallback结束/
}

//函数功能:TIM3中断服务程序
void TIM3_IRQHandler(void)
{
HAL_TIM_PeriodElapsedCallback开始/
  if (_HAL_TIM_GET_FLAG(TIM3,TIM_FLAG_UPDATE) != RESET)
  {//根据TIM_FLAG_UPDATE,读"TIMx状态寄存器(TIMx_SR)"中更新中断标志位
    _HAL_TIM_CLEAR_IT(TIM3, TIM_IT_UPDATE);
		//TIM_IT_UPDATE,令UIF=0,清除定时器更新中断标志位
    TIM3_LED_Toggle();
  }
HAL_TIM_PeriodElapsedCallback结束/
}

#ifndef __TIM1_EdgeAligned_InputCapture_H
#define __TIM1_EdgeAligned_InputCapture_H

#include "py32f0xx_hal.h"

#define _HAL_TIM_GET_FLAG(__INSTANCE__, __FLAG__)          (((__INSTANCE__)->SR &(__FLAG__)) == (__FLAG__))
//根据__FLAG__,读"TIMx状态寄存器(TIMx_SR)"中相应的中断标志位
//TIM_FLAG_UPDATE,若UIF=1,建立"更新事件"
//TIM_FLAG_CC1,若CC1IF=1,如果通道CC1配置为输出模式,则建立"CC1输出事件";
//TIM_FLAG_CC1,若CC1IF=1,如果通道CC1配置为输入模式,则建立"CC1捕获事件"
//TIM_FLAG_CC2,若CC2IF=1,如果通道CC2配置为输出模式,则建立"CC2输出事件";
//TIM_FLAG_CC2,若CC2IF=1,如果通道CC2配置为输入模式,则建立"CC2捕获事件"
//TIM_FLAG_CC3,若CC3IF=1,如果通道CC3配置为输出模式,则建立"CC3输出事件";
//TIM_FLAG_CC3,若CC3IF=1,如果通道CC3配置为输入模式,则建立"CC3捕获事件"
//TIM_FLAG_CC4,若CC4IF=1,如果通道CC4配置为输出模式,则建立"CC4输出事件";
//TIM_FLAG_CC4,若CC4IF=1,如果通道CC4配置为输入模式,则建立"CC4捕获事件";
//TIM_FLAG_COM,若COMIF=1,则建立"COM事件"
//TIM_FLAG_TRIGGER,若TIF=1,则建立"触发事件"
//TIM_FLAG_BREAK,若BIF=1,则建立"刹车事件"
//TIM_FLAG_CC1OF,若CC1OF=1,则表示"计数器x的值被捕获到TIMx_CCR1寄存器"
//TIM_FLAG_CC2OF,若CC2OF=1,则表示"计数器x的值被捕获到TIMx_CCR2寄存器"
//TIM_FLAG_CC3OF,若CC3OF=1,则表示"计数器x的值被捕获到TIMx_CCR3寄存器"
//TIM_FLAG_CC4OF,若CC4OF=1,则表示"计数器x的值被捕获到TIMx_CCR4寄存器"

#define _HAL_TIM_CLEAR_IT(__INSTANCE__, __INTERRUPT__)      ((__INSTANCE__)->SR = ~(__INTERRUPT__))
//根据__INTERRUPT__,将"TIMx状态寄存器(TIMx_SR)"中相应的中断标志位置0
//TIM_IT_UPDATE,令UIF=0,清除定时器更新中断标志位
//TIM_IT_CC1,令CC1IF=0,清除捕获/比较1中断标志位
//TIM_IT_CC2,令CC2IF=0,清除捕获/比较2中断标志位
//TIM_IT_CC3,令CC3IF=0,清除捕获/比较3中断标志位
//TIM_IT_CC4,令CC4IF=0,清除捕获/比较4中断标志位
//TIM_IT_COM,令COMIF=0,清除COM事件中断标志位
//TIM_IT_TRIGGER,令TIF=0,清除触发中断标志位
//TIM_IT_BREAK,令BIF=0,清除刹车中断标志位

extern void TIM1_COUNTERMODE_UP_IC1_Init(uint16_t arr,uint16_t psc);
extern void TIM3_COUNTERMODE_UP_Init(uint16_t arr,uint16_t psc);
#endif /* __TIM1_EdgeAligned_InputCapture_H */

#include "py32f0xx_hal.h"
#include "SystemClock.h"
#include "delay.h"
#include "LED.h"
#include "TIM1_EdgeAligned_InputCapture.h"

int main(void)
{
	HSE_Config();
//	HAL_Init();//systick初始化
  delay_init();
	HAL_Delay(1000);

	TIM1_LED_Init();
	TIM3_LED_Init();
	TIM1_COUNTERMODE_UP_IC1_Init(20000,240);//若使用HSE,当arr=20000,psc=240时,则为200ms,误差为10us;
	TIM3_COUNTERMODE_UP_Init(20000,240);//若使用HSE,当arr=20000,psc=240时,则为200ms,误差为10us;

  while (1)
  {
		delay_ms(100);
//		TIM1_LED_Toggle();
//		TIM3_LED_Toggle();
  }
}

#include "LED.h"

void TIM1_LED_Init(void);
void TIM3_LED_Init(void);

//函数功能:TIM1_LED灯引脚初始化,并配置为关灯
void TIM1_LED_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  __HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA时钟

  //初始化PA0
  GPIO_InitStructure.Pin = GPIO_PIN_0;                  //选择第0脚
  GPIO_InitStructure.Pull = GPIO_PULLUP;                //引脚上拉被激活
  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //配置GPIO速度为极高
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;        //设置引脚工作模式为推挽输出方式

  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
	//根据GPIO_InitStructure结构变量指定的参数初始化GPIOA的外设寄存器

	TIM1_LED_Off();
}

//函数功能:TIM3_LED灯引脚初始化,并配置为关灯
void TIM3_LED_Init(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  __HAL_RCC_GPIOA_CLK_ENABLE();//使能GPIOA时钟

  //初始化PB5
  GPIO_InitStructure.Pin = GPIO_PIN_4;                  //选择第4脚
  GPIO_InitStructure.Pull = GPIO_PULLUP;                //引脚上拉被激活
  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; //配置GPIO速度为极高
	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;        //设置引脚工作模式为推挽输出方式

  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
	//根据GPIO_InitStructure结构变量指定的参数初始化GPIOA的外设寄存器

	TIM3_LED_Off();
}

将PA3复用为TIM1_CH1,用作捕获信号输入引脚,PA4为TIM3中断时输出的信号,将这两个脚短接,使用示波器跟踪PA0的信号,就可以测试。

相关推荐
嵌入式大圣11 分钟前
单片机结合OpenCV
单片机·嵌入式硬件·opencv
布说在见1 小时前
个人实施工作的一天 —— 繁琐的数据输入与未来的句里录数据
经验分享·实习实施
梅见十柒2 小时前
wsl2中kali linux下的docker使用教程(教程总结)
linux·经验分享·docker·云原生
日晨难再2 小时前
嵌入式:STM32的启动(Startup)文件解析
stm32·单片机·嵌入式硬件
yufengxinpian2 小时前
集成了高性能ARM Cortex-M0+处理器的一款SimpleLink 2.4 GHz无线模块-RF-BM-2340B1
单片机·嵌入式硬件·音视频·智能硬件
管家婆客服中心3 小时前
提成制是什么?如何高效管理提成制?
经验分享·管家婆软件
__基本操作__3 小时前
历遍单片机下的IIC设备[ESP--0]
单片机·嵌入式硬件
网易独家音乐人Mike Zhou9 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
zy张起灵9 小时前
48v72v-100v转12v 10A大功率转换电源方案CSM3100SK
经验分享·嵌入式硬件·硬件工程
lantiandianzi17 小时前
基于单片机的多功能跑步机控制系统
单片机·嵌入式硬件