11:HAL--定时器代码总结

        下面文章没有提定时器的都默认为通用定时器,提了的为高级定时器

          如果没有使用HAL_TIM_ConfigClockSource()函数来配置时钟源的话默认为,使用内部时钟源来触发CNT计数器。

        通道1必须使用---TI1FP1;通道2必须使用TI2FP2,否则会出现未知错误。

一:外部时钟源模式一

A:外部时钟源模式1

功能:使用外部时钟源触发CNT,按键按下5次,溢出产生更新中断,在更新中断中关闭所有的LED。每按下一次按键产生一次触发中断,在触发中断中反转LED。

路线

        注意走这条路线的话,不用过滤波器和边沿检测器,直接TIF_ED提供时钟源。这个时钟源的边缘检测,不需要设置极性(因为没有过边沿检测器),上升沿和下降沿都会给你检测,也就是说按下一次给我们计2个数

        TRG1会触发,触发中断的产生。使用下面的代码使能触发事件;

        ED通道为双边沿触发

__HAL_TIM_ENABLE_IT(&PA0TIM2CH1Handleinit,TIM_IT_TRIGGER);

为什么要我们手动打开触发中断? 

在HAL_TIM_Base_Start_IT()函数的内部他只打开的更新事件(__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);),所以触发事件需要我们自己打开

使用PA0引脚, PAO---TIM2_CH1_ETR

TIM_HandleTypeDef PA0TIM2CH1Handleinit;

void IC_encoder_Init(uint16_t arr,uint16_t psc)
{
	TIM_ClockConfigTypeDef ConfigTypeDef={0};
	
	PA0TIM2CH1Handleinit.Instance=TIM2;
	PA0TIM2CH1Handleinit.Init.Period=arr;   //ARR自动重装载值
	PA0TIM2CH1Handleinit.Init.Prescaler=psc;    //预分频系数
	PA0TIM2CH1Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	
	HAL_TIM_Base_Init(&PA0TIM2CH1Handleinit);
	
	ConfigTypeDef.ClockSource=TIM_CLOCKSOURCE_TI1ED;   //选择时钟源
	//模式配置---外部通道1
	HAL_TIM_ConfigClockSource(&PA0TIM2CH1Handleinit,&ConfigTypeDef);
	//手动清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE);
	//以中断的方式打开定时器
	HAL_TIM_Base_Start_IT(&PA0TIM2CH1Handleinit);
	__HAL_TIM_ENABLE_IT(&PA0TIM2CH1Handleinit,TIM_IT_TRIGGER);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM2_CLK_ENABLE();
	
		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
		HAL_NVIC_SetPriority(TIM2_IRQn ,2,0);
		HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
		GPIO_InitTypeDef  GPIOTypeDefHandle;  
		GPIOTypeDefHandle.Mode=GPIO_MODE_INPUT;   /*输入模式*/   
		GPIOTypeDefHandle.Pin=GPIO_PIN_0;  
		GPIOTypeDefHandle.Pull=GPIO_PULLUP;        //上拉    
		GPIOTypeDefHandle.Speed=GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIOTypeDefHandle);

	}
}


void TIM2_IRQHandler()
{
	HAL_TIM_IRQHandler(&PA0TIM2CH1Handleinit);	
}
//更新中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{	
		if(htim->Instance==TIM2)
		{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
		}
}
//触发事件的回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
	
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
		
}
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC_encoder.h"


int main(void)
{
	
	
	uint16_t newnum;
  
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	IC_encoder_Init(6-1,1-1);
	OLED_ShowString(1, 1, "keystrokes:");
	

	 while (1)
	 {	
		 
			newnum=__HAL_TIM_GET_COUNTER(&PA0TIM2CH1Handleinit);//获取计数器的值
			OLED_ShowNum(2,1,newnum,1);		
					

	 }   
}

        注意:在HAL_TIM_Base_Init()中调用了TIM_Base_SetConfig()函数,TIM_Base_SetConfig()函数会把我们把更新中断标志位置1(  TIMx->EGR = TIM_EGR_UG;),所以我们载初始化的时候需要,手动清除一下。如果不清除,每次下载或者复位不管有没有更新中断的发生,程序会首先执行我们更新事件的回调函数,导致程序异常

手动清除更新中断标志位
__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE);

TIM_Base_SetConfig()函数
/* Generate an update event to reload the Prescaler
     and the repetition counter (only for advanced timer) value immediately */
  TIMx->EGR = TIM_EGR_UG;

重要函数:

HAL_StatusTypeDef HAL_TIM_ConfigClockSource(TIM_HandleTypeDef *htim, TIM_ClockConfigTypeDef *sClockSourceConfig)
typedef struct
{
  uint32_t ClockSource;        时钟源选择
  uint32_t ClockPolarity;      时钟极性选择
  uint32_t ClockPrescaler;     外部触发预分频ETR(ETR的专属寄存器)                       
  uint32_t ClockFilter;        时钟滤波器                   
} TIM_ClockConfigTypeDef;

        如果没有使用HAL_TIM_ConfigClockSource()函数来配置时钟源的话默认为,使用内部时钟源来触发CNT计数器

B:外部时钟源模式1

功能:使用外部时钟源触发CNT,按键按下5次,溢出产生更新中断,在更新中断中关闭所有的LED。每按下一次按键产生一次触发中断,在触发中断中反转LED。

路线

        这个和上面的那个不同的是我们需要过滤波器和边沿检测器,所以需要配置时钟极性和时时钟滤波器。TI1FP1提供时钟源信号

        TRG1会触发,触发中断的产生。使用下面的代码使能触发事件

__HAL_TIM_ENABLE_IT(&PA0TIM2CH1Handleinit,TIM_IT_TRIGGER);

使用PA0引脚, PAO---TIM2_CH1_ETR

#include "stm32f1xx_hal.h"
#include "rcc.h"

TIM_HandleTypeDef PA0TIM2CH1Handleinit;

void IC_encoder_Init(uint16_t arr,uint16_t psc)
{
	TIM_ClockConfigTypeDef ConfigTypeDef={0};
	
	PA0TIM2CH1Handleinit.Instance=TIM2;
	PA0TIM2CH1Handleinit.Init.Period=arr;   //ARR自动重装载值
	PA0TIM2CH1Handleinit.Init.Prescaler=psc;    //预分频系数
	PA0TIM2CH1Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	
	HAL_TIM_Base_Init(&PA0TIM2CH1Handleinit);
	
	ConfigTypeDef.ClockSource=TIM_CLOCKSOURCE_TI1;   //选择时钟源
	ConfigTypeDef.ClockPolarity=TIM_CLOCKPOLARITY_FALLING; //时钟极性  --下降
	ConfigTypeDef.ClockFilter=0x03;                        //时钟滤波器 00 11
	//模式配置---外部通道1
	HAL_TIM_ConfigClockSource(&PA0TIM2CH1Handleinit,&ConfigTypeDef);
	
	//手动清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE);
	//以中断的方式打开定时器
	HAL_TIM_Base_Start_IT(&PA0TIM2CH1Handleinit);
	//打开触发中断
	__HAL_TIM_ENABLE_IT(&PA0TIM2CH1Handleinit,TIM_IT_TRIGGER);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM2_CLK_ENABLE();
	
		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
		HAL_NVIC_SetPriority(TIM2_IRQn ,2,0);
		HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
		GPIO_InitTypeDef  GPIOTypeDefHandle;  
		GPIOTypeDefHandle.Mode=GPIO_MODE_INPUT;   /*输入模式*/   
		GPIOTypeDefHandle.Pin=GPIO_PIN_0;  
		GPIOTypeDefHandle.Pull=GPIO_PULLUP;        //上拉    
		GPIOTypeDefHandle.Speed=GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIOTypeDefHandle);

	}
}


void TIM2_IRQHandler()
{
	HAL_TIM_IRQHandler(&PA0TIM2CH1Handleinit);	
}
//更新中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{	
		if(htim->Instance==TIM2)
		{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
		}
}
//触发事件的回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
}

时钟滤波器:以某个采样频率,来采样N次,N次的电平一样(达到稳定)才认为是一个真正的变化(高低电平的选择需要我们的时钟极性来决定)。

INT:内部的时钟信号

0011 以内部时钟源为频率采样,每采样8次,电平结果相同就认为他真正发生了变化。

 DTS也就是我们下面的这个周期的倒数

PA0TIM2CH1Handleinit.Instance=TIM2;
PA0TIM2CH1Handleinit.Init.Period=arr;   //ARR自动重装载值
PA0TIM2CH1Handleinit.Init.Prescaler=psc;    //预分频系数
PA0TIM2CH1Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	
PA0TIM2CH1Handleinit.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&PA0TIM2CH1Handleinit);

 以72MHZ来采样,采样1次,电平发生变化的时候,认为电平发生真正的变化

 C:外部时钟源模式1

功能:使用外部时钟源触发CNT,按键按下5次,溢出产生更新中断,在更新中断中关闭所有的LED。每按下一次按键产生一次触发中断,在触发中断中反转LED。

路线

        这个和上面的那个不同的是我们需要过滤波器和边沿检测器,所以需要配置时钟极性和时时钟滤波器。TI1FP2提供时钟源信号

        TRG1会触发,触发中断的产生。使用下面的代码使能触发事件

__HAL_TIM_ENABLE_IT(&PA0TIM2CH1Handleinit,TIM_IT_TRIGGER);

上面的都使用的为CH1,我们这次使用CH2,不要忘记随着通道的改变,引脚也得发生改变,时钟源也发生改变

PA1----TIM2_CH2:需要改我们的引脚

 只需要把        B:外部时钟源模式1 改为

ConfigTypeDef.ClockSource=TIM_CLOCKSOURCE_TI2;   //选择时钟源
在回调函数中修改一条代码即可
GPIOTypeDefHandle.Pin=GPIO_PIN_1; 

E:自动重装载值验证

功能:使用外部时钟源触发CNT,按键按下5次,溢出产生更新中断,在更新中断中关闭所有的LED。每按下一次按键产生一次触发中断,在触发中断中反转LED。

路线:上面的随便一个都可以,我们只是在这里面验证缓冲区的打开和关闭。

06:HAL----定时器-------7:HAL函数总结:具体提到了

        自动重装载值(AutoReloadPreload):        X.Init.AutoReloadPreload,如果我们中间需要改变ARR的值需要写这个(默认为关闭状态,我们不设置的话):

关闭缓冲区,CNT=3是把ARR改变为8,ARR的值立即发生改变。 

#include "stm32f1xx_hal.h"
#include "rcc.h"

TIM_HandleTypeDef PA0TIM2ETRHandleinit;

void IC_encoder_Init(uint16_t arr,uint16_t psc)
{
	TIM_ClockConfigTypeDef ConfigTypeDef={0};
	
	PA0TIM2ETRHandleinit.Instance=TIM2;
	PA0TIM2ETRHandleinit.Init.Period=arr;   //ARR自动重装载值
	PA0TIM2ETRHandleinit.Init.Prescaler=psc;    //预分频系数
	PA0TIM2ETRHandleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	
	PA0TIM2ETRHandleinit.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	PA0TIM2ETRHandleinit.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE;//自动重装载值缓冲区
	HAL_TIM_Base_Init(&PA0TIM2ETRHandleinit);
	
	ConfigTypeDef.ClockSource=TIM_CLOCKSOURCE_ETRMODE1;   //选择时钟源
	ConfigTypeDef.ClockPolarity=TIM_CLOCKPOLARITY_INVERTED; //时钟极性  --下降    //TIM_CLOCKPOLARITY_INVERTED(低电平) TIM_CLOCKPOLARITY_NONINVERTED (高电平)    
	ConfigTypeDef.ClockPrescaler=TIM_CLOCKPRESCALER_DIV1;     //ETR的专属预分频器
	ConfigTypeDef.ClockFilter=0x03;                        //时钟滤波器 00 11
	//模式配置---外部通道1
	HAL_TIM_ConfigClockSource(&PA0TIM2ETRHandleinit,&ConfigTypeDef);
	
	//手动清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&PA0TIM2ETRHandleinit,TIM_FLAG_UPDATE);
	//以中断的方式打开定时器
	HAL_TIM_Base_Start_IT(&PA0TIM2ETRHandleinit);
	//打开触发中断
	__HAL_TIM_ENABLE_IT(&PA0TIM2ETRHandleinit,TIM_IT_TRIGGER);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM2_CLK_ENABLE();
	
		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
		HAL_NVIC_SetPriority(TIM2_IRQn ,2,0);
		HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
		GPIO_InitTypeDef  GPIOTypeDefHandle;  
		GPIOTypeDefHandle.Mode=GPIO_MODE_INPUT;   /*输入模式*/   
		GPIOTypeDefHandle.Pin=GPIO_PIN_0;  
		GPIOTypeDefHandle.Pull=GPIO_PULLUP;        //上拉    
		GPIOTypeDefHandle.Speed=GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIOTypeDefHandle);

	}
}


void TIM2_IRQHandler()
{
	HAL_TIM_IRQHandler(&PA0TIM2ETRHandleinit);	
}
//更新中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{	
		if(htim->Instance==TIM2)
		{
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
		}
}
//触发事件的回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
}
	 while (1)
	 {	
		 
			newnum=__HAL_TIM_GET_COUNTER(&PA0TIM2ETRHandleinit);//获取计数器的值
			OLED_ShowNum(2,1,newnum,1);	
			if(__HAL_TIM_GET_COUNTER(&PA0TIM2ETRHandleinit)==3)
			{
						__HAL_TIM_SET_AUTORELOAD(&PA0TIM2ETRHandleinit,8-1);	//更改ARR的值
			}
					

	 }   
}

 改:本次不生效,下次生效

PA0TIM2ETRHandleinit.Init.AutoReloadPreload=TIM_OCFAST_ENABLE;//自动重装载值缓冲区

二:外部时钟源模式二

 A:外部时钟源模式2

功能:按键按下5次,溢出产生更新中断,在更新中断中关闭反转一个LED的电平。

路线

            外部时钟源模式2不会产生触发事件,因为不会走TRGI这个。

        使用PA0引脚, PAO---TIM2_CH1_ETR,外部时钟源模式2,只有这个ETR通道

#include "stm32f1xx_hal.h"
#include "rcc.h"

TIM_HandleTypeDef PA0TIM2CH1Handleinit;

void IC_encoder_Init(uint16_t arr,uint16_t psc)
{
	TIM_ClockConfigTypeDef ConfigTypeDef={0};
	
	PA0TIM2CH1Handleinit.Instance=TIM2;
	PA0TIM2CH1Handleinit.Init.Period=arr;   //ARR自动重装载值
	PA0TIM2CH1Handleinit.Init.Prescaler=psc;    //预分频系数
	PA0TIM2CH1Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	
	PA0TIM2CH1Handleinit.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_Base_Init(&PA0TIM2CH1Handleinit);
	
	ConfigTypeDef.ClockSource=TIM_CLOCKSOURCE_ETRMODE2;   //选择时钟源
	ConfigTypeDef.ClockPolarity=TIM_CLOCKPOLARITY_NONINVERTED; //时钟极性  --下降
	ConfigTypeDef.ClockPrescaler=TIM_CLOCKPRESCALER_DIV1;   //
	ConfigTypeDef.ClockFilter=0x03;                        //时钟滤波器 00 11
	//模式配置---外部通道1
	HAL_TIM_ConfigClockSource(&PA0TIM2CH1Handleinit,&ConfigTypeDef);
	//手动清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&PA0TIM2CH1Handleinit,TIM_FLAG_UPDATE);
	//以中断的方式打开定时器
	HAL_TIM_Base_Start_IT(&PA0TIM2CH1Handleinit);
	
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM2_CLK_ENABLE();
	
		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
		HAL_NVIC_SetPriority(TIM2_IRQn ,2,0);
		HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
		GPIO_InitTypeDef  GPIOTypeDefHandle;  
		GPIOTypeDefHandle.Mode=GPIO_MODE_INPUT;   /*输入模式*/   
		GPIOTypeDefHandle.Pin=GPIO_PIN_0;  
		GPIOTypeDefHandle.Pull=GPIO_PULLUP;        //上拉    
		GPIOTypeDefHandle.Speed=GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIOTypeDefHandle);

	}
}

void TIM2_IRQHandler()
{
	HAL_TIM_IRQHandler(&PA0TIM2CH1Handleinit);	
}
//更新中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{	
		if(htim->Instance==TIM2)
		{
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
		}
}

 B:外部时钟源模式2

这个实际是外部时钟源模式1

功能:使用外部时钟源触发CNT,按键按下5次,溢出产生更新中断,在更新中断中关闭所有的LED。每按下一次按键产生一次触发中断,在触发中断中反转LED。

路线

        TRG1会触发,触发中断的产生。使用下面的代码使能触发事件

        ETR通道的外部时钟源模式1,走的是TRG1这个,(不走ETRF,ETRF是外部时钟源模式2的)

__HAL_TIM_ENABLE_IT(&PA0TIM2CH1Handleinit,TIM_IT_TRIGGER);

        使用PA0引脚, PAO---TIM2_CH1_ETR,这次我们使用ETR通道,(在我们STM32F1C8T6这个系列中,只有TIM1和TIM有ETR这个通道)

#include "stm32f1xx_hal.h"
#include "rcc.h"

TIM_HandleTypeDef PA0TIM2ETRHandleinit;

void IC_encoder_Init(uint16_t arr,uint16_t psc)
{
	TIM_ClockConfigTypeDef ConfigTypeDef={0};
	
	PA0TIM2ETRHandleinit.Instance=TIM2;
	PA0TIM2ETRHandleinit.Init.Period=arr;   //ARR自动重装载值
	PA0TIM2ETRHandleinit.Init.Prescaler=psc;    //预分频系数
	PA0TIM2ETRHandleinit.Init.CounterMode=TIM_COUNTERMODE_UP;  //向上计数	
	PA0TIM2ETRHandleinit.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
	HAL_TIM_Base_Init(&PA0TIM2ETRHandleinit);
	
	ConfigTypeDef.ClockSource=TIM_CLOCKSOURCE_ETRMODE1;   //选择时钟源
	ConfigTypeDef.ClockPolarity=TIM_CLOCKPOLARITY_INVERTED; //时钟极性  --下降    //TIM_CLOCKPOLARITY_INVERTED(低电平) TIM_CLOCKPOLARITY_NONINVERTED (高电平)    
	ConfigTypeDef.ClockPrescaler=TIM_CLOCKPRESCALER_DIV1;     //ETR的专属预分频器
	ConfigTypeDef.ClockFilter=0x03;                        //时钟滤波器 00 11
	//模式配置---外部通道1
	HAL_TIM_ConfigClockSource(&PA0TIM2ETRHandleinit,&ConfigTypeDef);
	
	//手动清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&PA0TIM2ETRHandleinit,TIM_FLAG_UPDATE);
	//以中断的方式打开定时器
	HAL_TIM_Base_Start_IT(&PA0TIM2ETRHandleinit);
	//打开触发中断
	__HAL_TIM_ENABLE_IT(&PA0TIM2ETRHandleinit,TIM_IT_TRIGGER);
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM2_CLK_ENABLE();
	
		HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
		HAL_NVIC_SetPriority(TIM2_IRQn ,2,0);
		HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
		GPIO_InitTypeDef  GPIOTypeDefHandle;  
		GPIOTypeDefHandle.Mode=GPIO_MODE_INPUT;   /*输入模式*/   
		GPIOTypeDefHandle.Pin=GPIO_PIN_0;  
		GPIOTypeDefHandle.Pull=GPIO_PULLUP;        //上拉    
		GPIOTypeDefHandle.Speed=GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIOTypeDefHandle);

	}
}


void TIM2_IRQHandler()
{
	HAL_TIM_IRQHandler(&PA0TIM2ETRHandleinit);	
}
//更新中断的回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{	
		if(htim->Instance==TIM2)
		{
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);
		}
}
//触发事件的回调函数
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
}

注意: 

ConfigTypeDef.ClockSource=TIM_CLOCKSOURCE_ETRMODE1;   //选择时钟源
ConfigTypeDef.ClockPolarity=TIM_CLOCKPOLARITY_INVERTED; //时钟极性  --下降    //TIM_CLOCKPOLARITY_INVERTED(低电平) TIM_CLOCKPOLARITY_NONINVERTED (高电平)    
ConfigTypeDef.ClockPrescaler=TIM_CLOCKPRESCALER_DIV1;     //ETR的专属预分频器
ConfigTypeDef.ClockFilter=0x03;                        //时钟滤波器 00 11
//模式配置---外部通道1
HAL_TIM_ConfigClockSource(&PA0TIM2ETRHandleinit,&ConfigTypeDef);

三:输入捕获

交叉问题:

        在STM32的HAL库中,HAL_TIM_IC_ConfigChannel 函数用于配置定时器的输入捕获通道。当您设置 ICSelection 为交叉(通常是 TIM_ICSELECTION_INDIRECTTI)时,您实际上是在告诉定时器从另一个定时器或内部源获取触发信号,而不是从外部引脚捕获信号。

        但是,重要的是要理解,即使您选择了交叉触发,您仍然需要指定一个物理通道来接收这个交叉信号。在HAL库中,您使用 HAL_TIM_IC_ConfigChannel 的第三个参数来指定这个物理通道。因此,即使您使用交叉触发,如果您想要配置TIM1的通道1来接收交叉信号,您仍然应该将第三个参数设置为 TIM_CHANNEL_1

        至于为什么 HAL_TIM_IC_ConfigChannel 不能配置通道为1,实际上这是一个误解。HAL_TIM_IC_ConfigChannel 函数本身并没有限制不能配置任何特定的通道。只要您的STM32硬件支持该定时器的该通道,并且您已经正确初始化了定时器和通道,您就可以使用 TIM_CHANNEL_1TIM_CHANNEL_2 等来配置任何支持的通道。

例如,如果您想要配置TIM1的通道1为交叉输入捕获,您应该这样做:

 

08:HAL---通用定时器功能(输入捕获功能)

CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/137085008

有4个不同的CCR寄存器,分别为:CCR1,CCR2,CCR3,CCR4

读取CCR的值:

HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1);

连接方式:x.IC1Selection

STM32F1C8T6的这个板子在输入捕获设置极性的时候能不能设置为双边沿触发输入捕获中断?

        不能,只能设置为上升沿或者下降沿触发,输入捕获中断。并不能双边沿触发输入捕获的中断。别的板子也许可以。

A:输入捕获直连

功能:使用内部时钟源触发CNT计数器,每过6.5秒触发一次,触发中断。在触发中断的回调函数中反转LED的电平。使用的是TIM2_CH1和TIM2_CH2,所以是2条路,按键按下获取我们计数器的值

时间计算

计数频率计算:Ft/(PSC+1)          Ft===>定时器频率(我们的为72MHZ)

周期(计一个数的时间):1/频率   或者  (PSC+1)/Ft 

频率:72000 000/7200=10 000HZ       周期:1/65536=0.000 1s =0.1ms

一共计65536个数,那么溢出时间=65536*0.1=6553.6ms=6.5536s

 路线

        捕获中断不会打开更新中断,HAL_TIM_IC_Start_IT()中不会打开更新中断,所以需要我们手动打开:    __HAL_TIM_ENABLE_IT(&HandleTIM4CH1,TIM_IT_UPDATE);    

 

#include "stm32f1xx_hal.h"
#include "pwm.h"

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

uint32_t num;
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_ICinit={0};
	TIM_IC_InitTypeDef TIM_IC={0};
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_IC_Init(&HandleTIM4CH1);
	
	//定时器2通道1的捕获
	TIM_ICinit.ICFilter=0x03;   //滤波器
	TIM_ICinit.ICPolarity=TIM_ICPOLARITY_FALLING;   //极性选择下升沿触发
	TIM_ICinit.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_ICinit.ICSelection=TIM_ICSELECTION_DIRECTTI;     /* 映射到TI1上 */
	
	/*配置输入映射通道*/
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_ICinit, TIM_CHANNEL_1);

	//定时器2通道2的捕获
	TIM_IC.ICFilter=0x03;   //滤波器
	TIM_IC.ICPolarity=TIM_ICPOLARITY_FALLING;   //极性选择上升沿触发
	TIM_IC.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_IC.ICSelection=TIM_ICSELECTION_DIRECTTI;     /* 直连 */
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_IC, TIM_CHANNEL_2);

	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_1);
	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_2);
	//使能定时器中断    开启输入捕获的事件中断
	__HAL_TIM_ENABLE_IT(&HandleTIM4CH1,TIM_IT_UPDATE);	
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
		
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3);              /* 抢占1,子优先级3 */
      HAL_NVIC_EnableIRQ(TIM2_IRQn);  

			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;   
			GPIO_InitType.Pin=GPIO_PIN_0;
			GPIO_InitType.Pull=GPIO_PULLUP;          
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);

			//TIM1_CH2
				
			GPIO_InitType.Mode=GPIO_MODE_INPUT;   
			GPIO_InitType.Pin=GPIO_PIN_1;
			GPIO_InitType.Pull=GPIO_PULLUP;          
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);	  		
		}
}

/* 定时器5中断服务函数 */
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1);  /* 定时器HAL库共用处理函数 */
	
}

//定时器更新中断回调函数  CNT==ARR产生的中断函数*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM2)
    {
			num++;
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
			if(num==65536-1)
			{
				num=0;
			}
				
		}
}

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"
#include "pwm.h"



int main(void)
{
	
	
	
		
	uint32_t time1 = 0;
  	uint32_t time2 = 0;

	
	
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	
	IC_TIM4_CH1_init(65536-1,7200-1);  //0.1ms  65536*0.1=6553.6ms=6.5536s
	
	OLED_ShowString(1,1,"Time1:");
	
	OLED_ShowString(2,1,"Time2:");
	 while (1)
    {
        {
					time1=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1);
					time1=time1+(num*65536);
				}
				{
					time2=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_2);
					time2=time2+(num*65536);
				}
				
				OLED_ShowNum(1, 7,time1,8);
				OLED_ShowNum(2, 7,time2,8);
      
    }
}

函数:HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_IC, TIM_CHANNEL_2);

typedef struct
{
  uint32_t ICPolarity;  输入捕获有效边沿
  uint32_t ICSelection; 输入对应方式   直连/交叉/TRC触发
  uint32_t ICPrescaler; 捕获预分频器
  uint32_t ICFilter;    输入捕获滤波器
} TIM_IC_InitTypeDef;

B:输入捕获交叉

功能:使用内部时钟源触发CNT计数器,每过6.5秒触发一次,触发中断。在触发中断的回调函数计算溢出的次数。使用的是TIM2_CH1和TIM2_CH2,所以是2条路,按键按下获取我们计数器的值

时间计算

计数频率计算:Ft/(PSC+1)          Ft===>定时器频率(我们的为72MHZ)

周期(计一个数的时间):1/频率   或者  (PSC+1)/Ft 

频率:72000 000/7200=10 000HZ       周期:1/65536=0.000 1s =0.1ms

一共计65536个数,那么溢出时间=65536*0.1=6553.6ms=6.5536s

 路线

      改变了:

现在按下PA0(TM2_CH1)捕获的是CCR2通道2的值。

现在按下PA1(TM2_CH2)捕获的是CCR1通道1的值。

TIM_ICinit.ICSelection=TIM_ICSELECTION_INDIRECTTI;     /* 交叉 */

        和上面不同的是我们使用的,交叉连接的方式:也就是说现在PA0控制的是CH2;PA1控制的是CH1

#include "stm32f1xx_hal.h"
#include "pwm.h"

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

uint32_t num;

uint32_t time1 = 0;
uint32_t time2 = 0;
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_ICinit={0};
	TIM_IC_InitTypeDef TIM_IC={0};
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_IC_Init(&HandleTIM4CH1);
	
	//定时器2通道1的捕获
	TIM_ICinit.ICFilter=0x03;   //滤波器
	TIM_ICinit.ICPolarity=TIM_ICPOLARITY_FALLING;   //极性选择下升沿触发
	TIM_ICinit.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_ICinit.ICSelection=TIM_ICSELECTION_INDIRECTTI;     /* 交叉 */
	
	/*配置输入映射通道*/
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_ICinit, TIM_CHANNEL_1);

	//定时器2通道2的捕获
	TIM_IC.ICFilter=0x03;   //滤波器
	TIM_IC.ICPolarity=TIM_ICPOLARITY_FALLING;   //极性选择上升沿触发
	TIM_IC.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_IC.ICSelection=TIM_ICSELECTION_INDIRECTTI;     /* 交叉*/
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_IC, TIM_CHANNEL_2);

	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_1);
	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_2);
	//使能定时器中断    开启输入捕获的事件中断
	__HAL_TIM_ENABLE_IT(&HandleTIM4CH1,TIM_IT_UPDATE);	
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
		
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3);              /* 抢占1,子优先级3 */
      HAL_NVIC_EnableIRQ(TIM2_IRQn);  

			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;   
			GPIO_InitType.Pin=GPIO_PIN_0;
			GPIO_InitType.Pull=GPIO_PULLUP;          
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);

			//TIM1_CH2
				
			GPIO_InitType.Mode=GPIO_MODE_INPUT;   
			GPIO_InitType.Pin=GPIO_PIN_1;
			GPIO_InitType.Pull=GPIO_PULLUP;          
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);	  		
		}
}

/* 定时器5中断服务函数 */
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1);  /* 定时器HAL库共用处理函数 */
	
}


//定时器更新中断回调函数  CNT==ARR产生的中断函数*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM2)
    {
			num++;
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
			if(num==65536-1)
			{
				num=0;
			}		
		}
}

//函数在定时器捕获到指定的输入事件(如上升沿或下降沿)时自动被触发。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
		
	if(htim->Instance==TIM2)
	{
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_1)
		{		
				time1=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1);
				time1=time1+(num*65536);
		}
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_2)
		{
			time2=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_2);
			time2=time2+(num*65536);
		}
	}
}

include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"
#include "pwm.h"



int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	
	IC_TIM4_CH1_init(65536-1,7200-1);  //0.1ms  65536*0.1=6553.6ms=6.5536s
	
	OLED_ShowString(1,1,"Time1:");
	
	OLED_ShowString(2,1,"Time2:");
	 while (1)
    {
        
				OLED_ShowNum(1, 7,time1,8);
				OLED_ShowNum(2, 7,time2,8); 
    }
}



C:输入捕获二对一

功能:使用内部时钟源触发CNT计数器,每过6.5秒触发一次,触发中断。按下触发捕获中断读取CCR1的值,松开触发捕获中断读取CCR2的值

 路线

        使用的是PA0 TIM2_CH1

#include "stm32f1xx_hal.h"
#include "pwm.h"

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

uint32_t num;

uint64_t time1 = 0;
uint64_t time2 = 0;
int64_t time=0;
uint8_t tim=0;
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_ICinit={0};
	TIM_IC_InitTypeDef TIM_IC={0};
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_IC_Init(&HandleTIM4CH1);
	
	//定时器2通道1的捕获  CCR1               
	TIM_ICinit.ICFilter=0x08;   //滤波器
	TIM_ICinit.ICPolarity=TIM_ICPOLARITY_FALLING;   //极性选择下升沿触发
	TIM_ICinit.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_ICinit.ICSelection=TIM_ICSELECTION_DIRECTTI;     /* 直连 */
	
	/*配置输入映射通道*/
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_ICinit, TIM_CHANNEL_1);

	//定时器2通道2交叉到了CH1的捕获   CCR2
	TIM_IC.ICFilter=0x08;   //滤波器
	TIM_IC.ICPolarity=TIM_ICPOLARITY_RISING;   //极性选择上升沿触发
	TIM_IC.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_IC.ICSelection=TIM_ICSELECTION_INDIRECTTI;     /* 交叉*/
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_IC, TIM_CHANNEL_2);

	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_1);
	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_2);
	//使能定时器中断    开启输入捕获的事件中断
	__HAL_TIM_ENABLE_IT(&HandleTIM4CH1,TIM_IT_UPDATE);	
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3);              /* 抢占1,子优先级3 */
      HAL_NVIC_EnableIRQ(TIM2_IRQn);  
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;   
			GPIO_InitType.Pin=GPIO_PIN_0;
			GPIO_InitType.Pull=GPIO_PULLUP;          
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
  		
		}
}

/* 定时器5中断服务函数 */
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1);  /* 定时器HAL库共用处理函数 */
	
}

//定时器更新中断回调函数  CNT==ARR产生的中断函数*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == TIM2)
    {
			num++;
			if(num==65536-1)num=0;	
		}
}
//函数在定时器捕获到指定的输入事件(如上升沿或下降沿)时自动被触发。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
		
	if(htim->Instance==TIM2)
	{
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_1)   //CCR1
		{		
				time1=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1);
				time1=time1+(num*65536);// TIM_ICinit
		}
		else if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_2)   //CCR2
		{
			time2=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_2);
			time2=time2+(num*65536);
		}
		
		time=__fabs(time2-time1);
		
		tim=(time*0.1)/1000;
	}
}
	 while (1)
    {
        
				OLED_ShowNum(1, 7,time1,8);
				OLED_ShowNum(2, 7,time2,8);
				OLED_ShowNum(3, 7,time,8);
				OLED_ShowNum(4, 7,tim,2);  			
    }
}

我们的按键一段接低电平,一段接IO口(IO口需要上拉);所以默认为高电平;

按下--低,松开--高。  按下触发捕获中断1,读取CCR1的值,更新time1

//定时器2通道1的捕获  CCR1               
	TIM_ICinit.ICFilter=0x08;   //滤波器
	TIM_ICinit.ICPolarity=TIM_ICPOLARITY_FALLING;   //极性选择下升沿触发
	TIM_ICinit.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_ICinit.ICSelection=TIM_ICSELECTION_DIRECTTI;     /* 直连 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
		
	if(htim->Instance==TIM2)
	{
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_1)   //CCR1
		{		
				time1=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1);
				time1=time1+(num*65536);// TIM_ICinit
		}
		
}

松开,读取CCR2的值,更新time2

//定时器2通道2交叉到了CH1的捕获   CCR2
	TIM_IC.ICFilter=0x08;   //滤波器
	TIM_IC.ICPolarity=TIM_ICPOLARITY_RISING;   //极性选择上升沿触发
	TIM_IC.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_IC.ICSelection=TIM_ICSELECTION_INDIRECTTI;     /* 交叉*/
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_IC, TIM_CHANNEL_2);
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
		
	if(htim->Instance==TIM2)
	{
		else if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_2)   //CCR2
		{
			time2=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_2);
			time2=time2+(num*65536);
		}
    }
}

        为了使我们的数据更加稳定,滤波器的值可以适当给大一点,经过调试0x08比较合适

D:3通道的异或霍尔传感器

 功能:使用内部时钟源触发CNT计数器。每按下和松开一次都会把我们当前计数器的值放入CCR1中然后读取。

 路线

        使用的为TIF_ED,所以上升沿和下降沿都会触发(只有发生边沿变化他就会捕获),捕获中断

        我们在这里只做3通道的异或,不做霍尔传感器,注意我们使用了从模式的复位模式。每次计数器的值捕获到CCR1的时候,计数器都会从0重新开始计数。

使用TIM2的CH1,CH2,CH3

#include "stm32f1xx_hal.h"
#include "pwm.h"

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;



uint64_t time1 = 0;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_ICinit={0};
	TIM_IC_InitTypeDef TIM_IC={0};
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_IC_Init(&HandleTIM4CH1);
	
	//定时器2通道1的捕获  CCR1               
	TIM_ICinit.ICFilter=0x08;   //滤波器
	TIM_ICinit.ICPolarity=TIM_ICPOLARITY_RISING;   //极性选上升沿触发,这个参数随便
	TIM_ICinit.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_ICinit.ICSelection=TIM_ICSELECTION_TRC;     /* 3通道的异或TRC */
	
	/*配置输入映射通道*/
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_ICinit, TIM_CHANNEL_1);
	//3通道的异或配置
	HAL_TIM_ConfigTI1Input(&HandleTIM4CH1,TIM_TI1SELECTION_XORCOMBINATION);
	//我们自己做的所以,配置从模式和ED
	HandleTIM4CH1.Instance->SMCR	&=~TIM_SMCR_TS;
	HandleTIM4CH1.Instance->SMCR	|=TIM_TS_TI1F_ED;
	
	HandleTIM4CH1.Instance->SMCR	&=~TIM_SMCR_SMS;
	HandleTIM4CH1.Instance->SMCR	|= TIM_SLAVEMODE_RESET;
	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_1);

		
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3);              /* 抢占1,子优先级3 */
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 
			
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;   
			GPIO_InitType.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
			GPIO_InitType.Pull=GPIO_PULLUP;          
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
  		
		}
}

/* 定时器5中断服务函数 */
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1);  /* 定时器HAL库共用处理函数 */
	
}


//函数在定时器捕获到指定的输入事件(如上升沿或下降沿)时自动被触发。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
		
	if(htim->Instance==TIM2)
	{
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_1)   //CCR1
		{		
				time1=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1);
		}	
	}
}

E:3通道的异或

 功能:使用内部时钟源触发CNT计数器,所以每次按下将计数器的值放入CCR1中。然后比较2次按下时间上的差值

 路线

        注意我们这次使用的不是TIF_ED,所以我们这次可以使用下降沿的捕获,也没有使用从模式的复位功能。每捕获计数器的值到CCR1时候,CCR1不会清零

     

使用TIM2的CH1,CH2,CH3

#include "stm32f1xx_hal.h"
#include "pwm.h"
#include "delay.h"

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;


uint32_t g_Overflow_flag=0;
uint32_t newnum =0xFFFFFFFF ;
uint32_t oid=0;
uint32_t difference=0;


void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_ICinit={0};
	TIM_IC_InitTypeDef TIM_IC={0};
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_IC_Init(&HandleTIM4CH1);
	
	//定时器2通道1的捕获  CCR1               
	TIM_ICinit.ICFilter=0x08;   //滤波器
	TIM_ICinit.ICPolarity=TIM_ICPOLARITY_FALLING;   //极性选下升沿触发
	TIM_ICinit.ICPrescaler=TIM_ICPSC_DIV1;    //分频1,就是每个上升沿我们都计一次数
	TIM_ICinit.ICSelection=TIM_ICSELECTION_DIRECTTI;     /* 直连 */
	
	/*配置输入映射通道*/
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_ICinit, TIM_CHANNEL_1);
	//3通道的异或配置
	HAL_TIM_ConfigTI1Input(&HandleTIM4CH1,TIM_TI1SELECTION_XORCOMBINATION);

	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_1);
	//使能更新事件
	__HAL_TIM_ENABLE_IT(&HandleTIM4CH1,TIM_IT_UPDATE);
		
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3);              /* 抢占1,子优先级3 */
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 
			
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;   
			GPIO_InitType.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
			GPIO_InitType.Pull=GPIO_PULLUP;          
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
  		
		}
}

/* 定时器5中断服务函数 */
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1);  /* 定时器HAL库共用处理函数 */
	
}


//函数在定时器捕获到指定的输入事件(如上升沿或下降沿)时自动被触发。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
		
	if(htim->Instance==TIM2)
	{
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_1)   //CCR1
		{		
				if(newnum==0xFFFFFFFF)
				{	//说明第一次按下
					newnum=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1)+(g_Overflow_flag*65536);
				}
				else
				{
					oid=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1)+(g_Overflow_flag*65536);
					difference=oid-newnum;
					delay_ms(15);
					newnum=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1)+(g_Overflow_flag*65536);
				}
		}	
	}
}
//更新事件中断 CNT==ARR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		g_Overflow_flag++;
		if(g_Overflow_flag==0xFFFFFFFF)g_Overflow_flag=0;
	}
}

四:输出比较

07:HAL------通用定时器功能(输出比较PWM)

CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/137024445

A:匹配反转

向下或者向上计数:占空比为固定50%(不能调节),周期和ARR,PSC有关

中央计数:占空比可以调节

功能:使用内部时钟源触发CNT计数器,通过不停的改变比较值和ARR的值观察占空比,周期,频率。

观察向上,向下计数,中央计数的不同

 路线

使用TIM_CH1

#include "stm32f1xx_hal.h"
#include "pwm.h"
#include "delay.h"

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_ICinit={0};
	TIM_OC_InitTypeDef TIM_oc={0};
	
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_OC_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
	//定时器2通道1的捕获  CCR1               
	TIM_oc.OCMode=TIM_OCMODE_TOGGLE;   //输入捕获的模式---匹配反转
	TIM_oc.Pulse=20;                    //比较值
	TIM_oc.OCPolarity=TIM_OCPOLARITY_HIGH;    //输出极性  --高电平为有效电平
	/*配置输入映射通道*/
	HAL_TIM_OC_ConfigChannel(&HandleTIM4CH1, &TIM_oc, TIM_CHANNEL_1);
	
	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_OC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_1);
	//使能更新事件
	__HAL_TIM_ENABLE_IT(&HandleTIM4CH1,TIM_IT_UPDATE);
		
}

void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3);              /* 抢占1,子优先级3 */
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 
			
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_AF_PP;    //AF表示“复用功能”,PP表示“推挽输出”
			GPIO_InitType.Pin=GPIO_PIN_0;          
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
  		
		}
}

/* 定时器5中断服务函数 */
void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1);  /* 定时器HAL库共用处理函数 */
	
}


//CNT==CCR时进入中断函数:输出比较
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
		
	if(htim->Instance==TIM2)
	{
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_1)   //CCR1
		{		
				
		}	
	}
}
//更新事件中断 CNT==ARR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
	
	}
}

 通过改变计数的模式,改变比较值。

计数模式---向上
HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP; 
比较值
TIM_oc.Pulse=20;                    

结论:

 中央计数3种模式的不同:

输出比较中断标志位的设置

关键函数的参:

HAL_StatusTypeDef HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef *htim,
                                           TIM_OC_InitTypeDef *sConfig,
                                           uint32_t Channel)

typedef struct
{
  uint32_t OCMode;         工作模式    
  uint32_t Pulse;          比较值                            
  uint32_t OCPolarity;     匹配初始极性 (有效值)   
  uint32_t OCNPolarity;    匹配时互补通道的输出极性
  uint32_t OCFastMode;     快速模式
  uint32_t OCIdleState;    空闲模式
  uint32_t OCNIdleState;   互补通道的空闲模式
} TIM_OC_InitTypeDef;


 边界值的测量:

B:匹配有效和无效

 和匹配反转的代码差不多,只需要改模式

 输入捕获的模式-
TIM_oc.OCMode=; 
匹配有效
#define TIM_OCMODE_ACTIVE 
匹配无效                  
#define TIM_OCMODE_INACTIVE 

C:强制模式

PWM模式也是基于输出比较的一种模式,只不过HAL库提供了PWM模式单独的API函数接口。

D:PWM1

 功能:使用内部时钟源触发CNT计数器。PWM1模式输出PWM

路线:

#include "stm32f1xx_hal.h"
#include "pwm.h"
#include "delay.h"

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_ICinit={0};
	TIM_OC_InitTypeDef TIM_oc={0};
	
	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_PWM_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
	//定时器2通道1的捕获  CCR1               
	TIM_oc.OCMode=TIM_OCMODE_PWM1;   //输入捕获的模式-pwm1
	TIM_oc.Pulse=arr/2;                    //比较值
	TIM_oc.OCPolarity=TIM_OCPOLARITY_HIGH;    //输出极性  --高电平为有效电平
	/*配置输入映射通道*/
	HAL_TIM_PWM_ConfigChannel(&HandleTIM4CH1, &TIM_oc, TIM_CHANNEL_2);
	
	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_PWM_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_2);
	//使能更新事件
	__HAL_TIM_ENABLE_IT(&HandleTIM4CH1,TIM_IT_UPDATE);
		
}

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM3)
		{
			__HAL_RCC_GPIOB_CLK_ENABLE() ;
			__HAL_RCC_TIM3_CLK_ENABLE();
			
			//把TIM3_CH2映射到PB5上面
			__HAL_RCC_AFIO_CLK_ENABLE() ;
			__HAL_AFIO_REMAP_TIM3_PARTIAL(); 
      HAL_NVIC_SetPriority(TIM3_IRQn, 1, 3);              /* 抢占1,子优先级3 */
      HAL_NVIC_EnableIRQ(TIM3_IRQn); 
			
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_AF_PP;    //AF表示“复用功能”,PP表示“推挽输出”
			GPIO_InitType.Pin=GPIO_PIN_5;         
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOB,&GPIO_InitType);
			
  		
		}
}

/* 定时器5中断服务函数 */
void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1);  /* 定时器HAL库共用处理函数 */
	
}


//CNT=ARR
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
		
	if(htim->Instance==TIM3)
	{
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_2)   //CCR1
		{		
				HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
		}	
	}
}
//更新事件中断 CNT==ARR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM3)
	{
			//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	}
}

 

l临界值:


 重要参数:

HAL_StatusTypeDef HAL_TIM_PWM_ConfigChannel(TIM_HandleTypeDef *htim,
                                            TIM_OC_InitTypeDef *sConfig,
                                            uint32_t Channel)
typedef struct
{
  uint32_t OCMode;         工作模式    
  uint32_t Pulse;          比较值                            
  uint32_t OCPolarity;     匹配初始极性 (有效值)   
  uint32_t OCNPolarity;    匹配时互补通道的输出极性
  uint32_t OCFastMode;     快速模式
  uint32_t OCIdleState;    空闲模式
  uint32_t OCNIdleState;   互补通道的空闲模式
} TIM_OC_InitTypeDef;  参数和输出比较的一样

HAL_TIM_PWM_PulseFinishedCallback 通常在PWM(脉冲宽度调制)模式下的定时器计数器的特定事件发生时被调用。具体来说,这个回调函数会在以下情况下被触发:

  1. 当计数器比较完成时:在PWM模式1(向上计数模式)中,当TIMx_CNT(当前计数器值)小于TIMx_CCR1(通道1的捕获/比较寄存器值)时,通道1输出有效电平(通常是高电平)。当TIMx_CNT达到或超过TIMx_CCR1时,通道1输出无效电平(通常是低电平)。在这个转换点,即高电平结束时,HAL_TIM_PWM_PulseFinishedCallback 会被调用。

  2. 在使用单定时器多通道产生SPWM(正弦脉冲宽度调制)信号时:如果一个定时器被配置为产生多个通道的输出,并且每个通道的占空比(CCR值)设置不同,那么在一个完整的周期内,每个通道的比较完成事件会分别触发中断。因此,HAL_TIM_PWM_PulseFinishedCallback 会在每个通道的比较完成时被调用。

请注意,中断的具体行为可能会受到硬件和固件实现的影响,因此在实际应用中,建议参考具体的硬件手册和固件库文档,以了解该函数的确切调用条件和行为。

另外,为了确保正确和安全地使用该函数,你应该确保已经正确配置了PWM模式,包括选择了正确的定时器通道,设置了适当的时钟源和预分频因子,以及配置了所需的占空比等参数。

CNT=ARR计数器溢出的时候捕获调用HAL_TIM_PWM_PulseFinishedCallback这个,只会调用跟新中断函数。

六:单脉冲模式

当输入信号发生变化的时候,可以控制输出的信号。只能CH1和CH2,不能使用通道3,4

延时可控,脉宽可控

       

        单脉冲模式在不同领域中具有不同的应用方式。

        在步进电机控制中,单脉冲模式指的是步进电机每接收到一个脉冲信号就会运动一定的角度。具体来说,当控制器向驱动器发出单脉冲信号时,驱动器会向电机发送一个脉冲信号,使电机转动一个角度,这一次转动通常称为一步。由于单脉冲模式只需要一个脉冲信号便可转动一步,因此其控制简单,适用于低速、低精度的应用,例如舞台灯光控制、低速走车等。

        在定时器应用中,单脉冲模式是指定时器只输出一个脉冲信号,即在特定的时间间隔内产生一个脉冲信号并停止计数。这种模式可以用于需要在特定时间间隔内产生脉冲信号的应用,例如触发外部设备的操作或测量某个事件的持续时间等。

此外,单脉冲调光模式也被广泛应用于LED照明、流明衰减测试、固态激光器及其它光电领域。

  

 A:单脉冲--PWM模式

#include "stm32f1xx_hal.h"
#include "pwm.h"
#include "delay.h"

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_ICinit={0};
	TIM_OnePulse_InitTypeDef TIM_one={0};

	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_OnePulse_Init(&HandleTIM4CH1,TIM_OPMODE_SINGLE);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
	          
	TIM_one.OCMode=TIM_OCMODE_PWM1; //工作模式   //TIM_OCPOLARITY_LOW
	TIM_one.Pulse=400;            //比较值
	TIM_one.OCPolarity=TIM_OCPOLARITY_LOW;   //匹配的输出有效值  //TIM_OCPOLARITY_HIGH
	
	TIM_one.ICPolarity=TIM_ICPOLARITY_FALLING;    //输入捕获极性--下降
	TIM_one.ICSelection=TIM_ICSELECTION_DIRECTTI;  //输入的方式直连
	TIM_one.ICFilter=0x8;    //输入滤波器
	/*配置输入映射通道 输出,输入*/
	HAL_TIM_OnePulse_ConfigChannel(&HandleTIM4CH1, &TIM_one, TIM_CHANNEL_2,TIM_CHANNEL_1);
	
	//使能输入捕获中断--(CNT==ARR溢出产生的中断)
	HAL_TIM_OnePulse_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_2);
	
		
}

void HAL_TIM_OnePulse_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			

			//输入   CH1
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;    
			GPIO_InitType.Pin=GPIO_PIN_0; 
			GPIO_InitType.Pull=GPIO_PULLUP;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
			//输出  CH2
			GPIO_InitType.Mode=GPIO_MODE_AF_PP;    //AF表示“复用功能”,PP表示“推挽输出”
			GPIO_InitType.Pin=GPIO_PIN_1; 
			GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
		
		}
}

注意输出模式,在没有接收到输入信号之前,他的默认电平为输出极性的电平。 EG:下面的默认信号为低电平,在输入信号来之后发生变化。(模式选择:PWM模式)

TIM_one.OCPolarity=TIM_OCPOLARITY_LOW;   //匹配的输出有效值  //TIM_OCPOLARITY_HIGH

结论:

 重要参数:

HAL_StatusTypeDef HAL_TIM_OnePulse_ConfigChannel(TIM_HandleTypeDef *htim, TIM_OnePulse_InitTypeDef *sConfig,
                                                 uint32_t OutputChannel,  uint32_t InputChannel);


typedef struct
{
  uint32_t OCMode         工作模式
  uint32_t Pulse;         比较值
  uint32_t OCPolarity;    匹配时输出的极性  有效电平
  uint32_t OCNPolarity;   匹配时互补通道的极性
  uint32_t OCIdleState;   空闲状态
  uint32_t OCNIdleState;  互补通道空闲状态
  uint32_t ICPolarity;    输入捕获的有效边沿
  uint32_t ICSelection;   输入的对应方式
  uint32_t ICFilter;      输入的捕获滤波器
} TIM_OnePulse_InitTypeDef;

B:单脉冲---匹配反转

代码和上面的一样,只要改 uint32_t OCMode         工作模式‘;

输出的有效电平为:高电平,(没有匹配时无效电平,低电平)

 七:编码器

使用的都是外部时钟

09:HAL--通用定时器编码器接口

CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/137206197

只能CH1和CH2,不能使用通道3,4

A:编码器模式--单

功能:使用外部的时钟(编码器只能使用外部时钟),判断编码器是正转还是逆转,并计数。

          我们使用的是一个通道做为触发信号(CH1PA6),另一个通道做为参考信号(CH2PA7)。

         我们使用的为 PA6:TIM3_CH1,PA7:TIM3_CH2 。编码器A连接PA6,B连接PA7。

路线


       

 当编码器旋转起来的时候, 会输出下面的方波信号

正传:B为参考信号的时候

当编码器正传的时候,向上计2个数,正转一圈向上计2个数

反转:B为参考信号的时候

反转:反转一圈,计数器向下计2个数。

#include "stm32f1xx_hal.h"
#include "pwm.h"
#include "delay.h"
int64_t num=0;
int64_t nums=0;
int64_t up=0;
int64_t ixa=0;
//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_Encoder_InitTypeDef TIM_Encoder={0};

	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	
	TIM_Encoder.EncoderMode=TIM_ENCODERMODE_TI2; //编码器模式---通道2做为参考信号  /
	TIM_Encoder.IC1Filter=0x8;                   //捕获1滤波器   /
	TIM_Encoder.IC1Polarity=TIM_ICPOLARITY_RISING;//捕获1极性 ---上降 //在下降沿产生标志位值1(输入捕获标志位)
	TIM_Encoder.IC1Prescaler=TIM_ICPSC_DIV1;  		//捕获值1预分频
	TIM_Encoder.IC1Selection=TIM_ICSELECTION_DIRECTTI;//捕获1对应方式--直连  
	HAL_TIM_Encoder_Init(&HandleTIM4CH1,&TIM_Encoder);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
	
	HAL_TIM_Encoder_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_1);//参数2对应捕获的通道
		
}

void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM3)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM3_CLK_ENABLE();
			
			HAL_NVIC_SetPriority(TIM3_IRQn,2,0);
			HAL_NVIC_EnableIRQ(TIM3_IRQn);
			
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_AF_INPUT;    
			GPIO_InitType.Pin=GPIO_PIN_6|GPIO_PIN_7; 
			GPIO_InitType.Pull=GPIO_NOPULL;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);	
				
		}
}

void TIM3_IRQHandler()
{
		HAL_TIM_IRQHandler(&HandleTIM4CH1);
 		

}

//输入捕获通道1 ---在下降沿产生标志位值1(输入捕获标志位)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM3)
	{				
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_1) //捕获CCR1的值
		{
			if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&HandleTIM4CH1))
			{
				ixa=1;// 向下计数
				num=(HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1))/2;
			
			}
			else
			{
				up=1;  //向上计数
				num=(HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1)+1)/2;

			}	
		}		
	}
}

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"
#include "pwm.h"

int CNT=0;
int CCR1=0;

int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	
	IC_TIM4_CH1_init(65536-1,1-1);  
	OLED_ShowString(1,1,"num:");
	
//	OLED_ShowString(2,1,"CNT:");
//	OLED_ShowString(3,1,"CCR1:");

	 while (1)
    { 	
			OLED_ShowNum(1,5,num,6);
			if (up==1) 
			{
			OLED_ShowString(2,1,"up!!!");
				up=0;
			
			}
			else OLED_ShowString(2,1,"       ");
		
			
			if (ixa==1) 
			{
			
			OLED_ShowString(3,1,"xia!!!");
				ixa=0;
			}
			else OLED_ShowString(3,1,"          ");
			
//			CNT=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
//			CCR1=(HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1));
//			
//			OLED_ShowNum(2,5,CNT,5);
//			OLED_ShowNum(3,5,CCR1,5);
    }
}


CNT和CCR1:

正传的时候(向上计数):CCR1=CNT+1

反转(向下计数):CCR1=CNT

int CNT=0;
int CCR1=0;
CNT=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
CCR1=(HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1));
			
OLED_ShowNum(2,5,CNT,5);
OLED_ShowNum(3,5,CCR1,5);

或者使用仿真


重要函数: 

 TIM_Encoder.IC1Polarity=TIM_ICPOLARITY_FALLING;//捕获1极性 ---下降 //在下降沿产生标志位值1(输入捕获标志位)

HAL_StatusTypeDef HAL_TIM_Encoder_Init(TIM_HandleTypeDef *htim,  TIM_Encoder_InitTypeDef *sConfig);
typedef struct
{
  uint32_t EncoderMode;   编码器的工作模式
  uint32_t IC1Polarity;   捕获1极性
  uint32_t IC1Selection;  捕获1输入对应的方式
  uint32_t IC1Prescaler;  捕获1预分频值
  uint32_t IC1Filter;     捕获1滤波器 
  uint32_t IC2Polarity;   捕获2极性
  uint32_t IC2Selection;  捕获2输入对应方式
  uint32_t IC2Prescaler;  捕获2预分频
  uint32_t IC2Filter;     捕获2滤波器
} TIM_Encoder_InitTypeDef;

 IC1Polarity;   极性 

        TIM_ICPOLARITY_RISING-----上升沿(极性不反转); TIM_ICPOLARITY_FALLING---下降沿(极性反转)

        我们编码器极性的选择和其他的不一样,其他的是哪个边沿发生捕获,因为我们编码器的2个边沿都需要计数。所以在我们编码器这里的意思为极性是不是需要反转

          编码器接口,都是上升沿和下降沿都有效的 , 上升沿和下降沿都需要计次 ,  所以在编码器接口模式下 ,  边沿检测极性选择就不再是边沿的极性选择了 ,  而是高低电平的极性选择.

        选择上升沿的参数------就是信号直通过来,高低电平极性不反转

        选择下升沿的参数-------就是信号通过一个非门过来,高低电平极性反转

 不反转

 TI1反转

 B:编码器模式--双

功能:和上面完全一样,不过就是改变了计数模式,2个都为触发信号,2个都为参考信号。精度更加高了。

路线


       

#include "stm32f1xx_hal.h"
#include "pwm.h"
#include "delay.h"
int64_t num=0;
int64_t nums=0;
int64_t up=0;
int64_t ixa=0;
//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_Encoder_InitTypeDef TIM_Encoder={0};

	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	
	TIM_Encoder.EncoderMode=TIM_ENCODERMODE_TI12; //编码器模式---通道1,2做为参考信号  /
	TIM_Encoder.IC1Filter=0x8;                   //捕获1滤波器   
	TIM_Encoder.IC1Polarity=TIM_ICPOLARITY_RISING;//捕获1极性 ---上降 //极性不反转
	TIM_Encoder.IC1Prescaler=TIM_ICPSC_DIV1;  		//捕获值1预分频
	TIM_Encoder.IC1Selection=TIM_ICSELECTION_DIRECTTI;//捕获1对应方式--直连  
	
	TIM_Encoder.IC2Filter=0x8;                   //捕获2滤波器   /
	TIM_Encoder.IC2Polarity=TIM_ICPOLARITY_RISING;//捕获2性 ---上降 极性不反转
	TIM_Encoder.IC2Prescaler=TIM_ICPSC_DIV1;  		//捕获值2预分频
	TIM_Encoder.IC2Selection=TIM_ICSELECTION_DIRECTTI;//捕获2应方式--直连  
	HAL_TIM_Encoder_Init(&HandleTIM4CH1,&TIM_Encoder);
	
	
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
	
	HAL_TIM_Encoder_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_ALL);//参数2对应捕获的通道
		
}

void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM3)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM3_CLK_ENABLE();
			
			HAL_NVIC_SetPriority(TIM3_IRQn,2,0);
			HAL_NVIC_EnableIRQ(TIM3_IRQn);
			
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_AF_INPUT;    
			GPIO_InitType.Pin=GPIO_PIN_6|GPIO_PIN_7; 
			GPIO_InitType.Pull=GPIO_NOPULL;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);	
				
		}
}

void TIM3_IRQHandler()
{
		HAL_TIM_IRQHandler(&HandleTIM4CH1);
 		

}

//输入捕获通道1 ---在下降沿产生标志位值1(输入捕获标志位)
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM3)
	{				
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_1) //捕获CCR1的值
		{
			if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&HandleTIM4CH1)==0)
			{
				//向上计数
				up=1;
				num=(HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1)+2)/4;	
			}
		}
			
			
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_2) //捕获CCR1的值
		{
			if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&HandleTIM4CH1)==1)
			{
				ixa=1;// 向下计数
				num=(HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_2)-2)/4;			
			}				
		}		
}
}

不过需要注意的是:他一次计数为4个,CCR和CNT计数器差2个

八:从模式

从模式:复位模式、门控模式和触发模式,外部时钟模式2 + 触发模式。

       

A:复位模式-ED通道

          在发生一个触发输入事件时,计数器和它的预分频器能够重新被初始化;同时,如果TIMx_CR1 寄存器的URS位为低,还产生一个更新事件 UEV ;然后所有的预装载寄存器 (TIMx_ARR , TIMx_CCRx)都被更新了。
        URS默认为低。可以把URS拉高,复位就不会产生跟新事件。

向上计数:计数器清零。向下计数:计数器=设置的ARR的值。

中央计数:分为2种情况:上升的时候触发,计数器=0;下降触发:计数器=设置的ARR的值 。

CH3 和CH4不能设置为从模式。

从模式的复位模式被触发也会触发更新事件。

功能:使用内部时钟源来触发CNT计数器,使用从模式的复位功能,输入捕获TI1。实现判断按键按下的时间长短。

路线

注意TI1F_ED在上升沿或者下降沿都触发。

时间的计算:72000 000 /(36000-1+1)=2000----频率;1/2000=0.0005s=0.5ms(一个周期的时间,计一个数的时间)。

(65536-1+1)*0.5=320768ms=32.678s---------一个周期的时间(定时器的溢出时间)。

或者:65536*36000/72000 000=32.678s  ------一个周期的时间


从模式:因为使用的是通道TI1F_ED,使用下降和上升沿都会触发触发事件(过了TRGI);

计数器和预分频器都被初始化。

因为使用的是从模式加上TI1F_ED:上升或者下降沿触发更新事件或者CNT=ARR触发更新事件。

当输入捕获为上升沿的时候捕获发生,吧CNT的值捕获到CCR1寄存器里面去。

流程: 我们按键一段接地,一段接IO口(高电平),所以按下为---低,松开为--高。当我们按键按下,首先发生触发和更新中断,把我们的CNT和预分频器值置为0,保证了起始值为0,

松开的时候

1:捕获事件触发把CNT的值拿CCR1中。

2:  触发中断和更新中断发生,再次清零CNT和预分频器值。

时间=CCR1*(72000 000 /预分频系数)

在外面松开按键的时候是:先触发触发中断还是更新中断?

可以观察到,复位一一点延迟,但是外面输入捕获到CCR1的值没有延迟,所以我们是先把计数器的值拿到CCR1中,然后在触发计数器清零。

#include "stm32f1xx_hal.h"
#include "pwm.h"
#include "delay.h"
#include "OLED.h"
uint64_t num=0;
uint16_t update=0;
uint16_t  trigger=0;
uint32_t   biaozw=0;

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_IC_InitTypeDef TIM_IC_Init={0};
	TIM_SlaveConfigTypeDef TIM_Slave={0};
	
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_IC_Init(&HandleTIM4CH1);
	
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
	//输入捕获通道配置
	TIM_IC_Init.ICFilter=0x08;    										//滤波器
	TIM_IC_Init.ICPolarity=TIM_ICPOLARITY_RISING;   //捕获极性--上升
	TIM_IC_Init.ICPrescaler=TIM_ICSELECTION_DIRECTTI; //连接方式--直连
	TIM_IC_Init.ICSelection=TIM_ICPSC_DIV1;           //分频值
	
	//从模式配置
	TIM_Slave.SlaveMode=TIM_SLAVEMODE_RESET;     //从模式功能---复位
	TIM_Slave.InputTrigger=TIM_TS_TI1F_ED;       //触发源-----ED
	
	//输入捕获
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_IC_Init, TIM_CHANNEL_1);
	
	//从模式----触发中断(TRGI)
	HAL_TIM_SlaveConfigSynchro_IT(&HandleTIM4CH1, &TIM_Slave);

	//打开更新事件的中断
	__HAL_TIM_ENABLE_IT(&HandleTIM4CH1,TIM_IT_UPDATE);
	
		//输入捕获----捕获中断
	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_1);
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
			HAL_NVIC_SetPriority(TIM2_IRQn,2,0);
			HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;     
			GPIO_InitType.Pin=GPIO_PIN_0; 
			GPIO_InitType.Pull=GPIO_PULLUP;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
			
			
		
		}
}

void TIM2_IRQHandler()
{
		HAL_TIM_IRQHandler(&HandleTIM4CH1);
				


}

//更新事件中断:从模式--ED.
//触发条件:上升和下降的时候都触发;或者CNT=ARR时
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{		
			update=1;
			
		 if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET)
		 {
				if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) != RESET)
				{				
					
				}			
		}
		else
		{
			
			
		}				 
	}
}
//触发事件(TRGI):从模式:清零计数器.从模式--ED,上升和下降的时候都触发
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM2)
	{		
			trigger=1;
	}

}


//捕获事件---捕获极性决定:
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM2)
	{		
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			num=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_1);
		
		}
		
	}

}
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"
#include "pwm.h"


uint32_t   time=0;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	
	IC_TIM4_CH1_init(65536-1,36000-1);  //0.5ms   max:32.768s
	OLED_ShowString(3,1,"CNT:");
	OLED_ShowString(4,3,"s");

	 while (1)
    { 	
			if(update==1)
			{
				OLED_ShowString(1,1,"update"); 
				update=0;
			}
			else OLED_ShowString(1,1,"            "); 

			if(trigger==1)
			{
				OLED_ShowString(2,1,"trigger"); 
				trigger=0;
			}
			else OLED_ShowString(2,1,"          ");
			
			OLED_ShowNum(3,5,num,10);		
			time=num*0.5/1000;
			OLED_ShowNum(4,1,time,2);	
    }
}

重要函数:

从模式:
HAL_StatusTypeDef HAL_TIM_SlaveConfigSynchro_IT(TIM_HandleTypeDef *htim,
                                                TIM_SlaveConfigTypeDef *sSlaveConfig)
typedef struct
{ 
  uint32_t  SlaveMode;         模式选择       
  uint32_t  InputTrigger;      触发源
  uint32_t  TriggerPolarity;   触发信号
  uint32_t  TriggerPrescaler;  触发预分频
  uint32_t  TriggerFilter;     触发滤波
} TIM_SlaveConfigTypeDef;

输入捕获
HAL_StatusTypeDef HAL_TIM_IC_ConfigChannel(TIM_HandleTypeDef *htim, TIM_IC_InitTypeDef *sConfig, uint32_t Channel)

typedef struct
{
  uint32_t ICPolarity;  输入捕获有效边沿
  uint32_t ICSelection; 输入对应方式   直连/交叉/TRC触发
  uint32_t ICPrescaler; 捕获预分频器
  uint32_t ICFilter;    输入捕获滤波器
} TIM_IC_InitTypeDef;

从模式的复位会导致:更新事件的产生,我们可以通过调节参数使从模式的复位不触发更新事件。

__HAL_TIM_URS_ENABLE()

B:复位模式-ETR

功能:这次我们简单点,不使用它的输入捕获功能,只为了练习它的另一个通道。

路线:

#include "stm32f1xx_hal.h"

uint16_t update=0;
uint16_t  trigger=0;

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_Slave={0};
	
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);

	//从模式配置
	TIM_Slave.SlaveMode=TIM_SLAVEMODE_RESET;     //从模式功能---复位
	TIM_Slave.InputTrigger=TIM_TS_ETRF;       //触发源--
	TIM_Slave.TriggerFilter=0x8;             //滤波器
	TIM_Slave.TriggerPolarity=TIM_TRIGGERPOLARITY_INVERTED;   //极性下降
	TIM_Slave.TriggerPrescaler=TIM_TRIGGERPRESCALER_DIV1;      //预分频器
	//从模式----触发中断(TRGI)
	HAL_TIM_SlaveConfigSynchro_IT(&HandleTIM4CH1, &TIM_Slave);
	
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
	
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
			HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
			HAL_NVIC_SetPriority(TIM2_IRQn,2,0);
			HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;     
			GPIO_InitType.Pin=GPIO_PIN_0; 
			GPIO_InitType.Pull=GPIO_PULLUP;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
		
		
		}
}

void TIM2_IRQHandler()
{
		HAL_TIM_IRQHandler(&HandleTIM4CH1);
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		
}

//更新事件中断:从模式.
//触发条件:上升和下降的时候都触发;或者CNT=ARR时
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{		
			update=1;
			
					 
	}
}
//触发事件(TRGI):从模式:清零计数器.从模式--ED,上升和下降的时候都触发
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM2)
	{		
			trigger=1;
	}

}


C:复位模式--按键时长

功能:使用内部时钟源做为触发CNT计数器。使用通道1做为从模式的触发源,CH1在把交叉到通道2,捕获CNT的数据到CCR2中,测按键的时间。

路线

捕获中断:我们配置的上升沿捕获CNT的数据到CCR2中。上升沿发生捕获中断

从模式复位:我们使用的是TIM_TS_TI1FP1配置为低电平触发,低电平的时候,触发从模式的复位,然后还会触发更新事件(更新事件在CNT=ARR的时候也会触发)。

触发事件:只要过了TRGI,就会触发TRGI触发事件。(满足电平变化触发)

#include "stm32f1xx_hal.h"

uint16_t update=0;
uint16_t  trigger=0;
uint32_t CCR_2=0;
//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_Slave={0};
	TIM_IC_InitTypeDef TIM_IC_Init={0};
	
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_IC_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);

	//从模式配置
	TIM_Slave.SlaveMode=TIM_SLAVEMODE_RESET;     //从模式功能---复位
	TIM_Slave.InputTrigger=TIM_TS_TI1FP1;       //触发源--
	TIM_Slave.TriggerFilter=0x8;             //滤波器
	TIM_Slave.TriggerPolarity=TIM_TRIGGERPOLARITY_FALLING;   //极性下降
	
	//输入捕获配置
	TIM_IC_Init.ICFilter=0x8;         //输入捕获滤波器
	TIM_IC_Init.ICPolarity=TIM_ICPOLARITY_RISING;   //极性上升沿触发
	TIM_IC_Init.ICPrescaler=TIM_ICPSC_DIV1;
	TIM_IC_Init.ICSelection=TIM_ICSELECTION_INDIRECTTI; //交叉连接  CH1的连接到CH2中去读取的是CCR2的值;
	
	
	//从模式----触发中断(TRGI)
	HAL_TIM_SlaveConfigSynchro_IT(&HandleTIM4CH1, &TIM_Slave);
	
	//打开输入捕获的通道---通道2
	HAL_TIM_IC_ConfigChannel(&HandleTIM4CH1, &TIM_IC_Init , TIM_CHANNEL_2);

	HAL_TIM_IC_Start_IT(&HandleTIM4CH1,TIM_CHANNEL_2);
	
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
			HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
			HAL_NVIC_SetPriority(TIM2_IRQn,2,0);
			HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;     
			GPIO_InitType.Pin=GPIO_PIN_0; 
			GPIO_InitType.Pull=GPIO_PULLUP;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
		
		
		}
}

void TIM2_IRQHandler()
{
		HAL_TIM_IRQHandler(&HandleTIM4CH1);
	
		
}



//捕获中断
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{	
		if( htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			//通道2
				HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
			CCR_2=HAL_TIM_ReadCapturedValue(&HandleTIM4CH1,TIM_CHANNEL_2);	//读取CNT的值到CCR2中
		}
	
	}
}

//更新事件中断:从模式.
//触发条件:上升和下降的时候都触发;或者CNT=ARR时
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{		
			update=1;
			
					 
	}
}
//触发事件(TRGI):从模式:清零计数器.从模式--ED,上升和下降的时候都触发
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM2)
	{		
			trigger=1;
	}

}


D:门控模式--按键时长

 TIF:产生触发中断。

功能: 使用内部时钟源做为触发CNT计数器。获取计数器的值来判断按键按下的时长。不使用输入捕获模式。

路线

#include "stm32f1xx_hal.h"

uint32_t count=0;
uint32_t one_CCR_1=0;
uint32_t two_CCR_1=0;
uint32_t num=0;

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_Slave={0};

	
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);

	//从模式配置
	TIM_Slave.SlaveMode=TIM_SLAVEMODE_GATED;     //从模式功能---门控模式
	TIM_Slave.InputTrigger=TIM_TS_ETRF;       //触发源--ETR
	TIM_Slave.TriggerFilter=0x8;             //滤波器
	//极性:反转电平:低电平有效,低电平CNT开始计数。(PA0默认为高电平)
	TIM_Slave.TriggerPolarity=TIM_TRIGGERPOLARITY_INVERTED;    
	TIM_Slave.TriggerPrescaler=TIM_TRIGGERPRESCALER_DIV1;
	
	
	//从模式----触发中断(TRGI)
	HAL_TIM_SlaveConfigSynchro_IT(&HandleTIM4CH1, &TIM_Slave);
	
	//以中断的方式打开计数器
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
	
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
			HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
			HAL_NVIC_SetPriority(TIM2_IRQn,2,0);
			HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;     
			GPIO_InitType.Pin=GPIO_PIN_0; 
			GPIO_InitType.Pull=GPIO_PULLUP;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
		
		
		}
}

void TIM2_IRQHandler()
{
		HAL_TIM_IRQHandler(&HandleTIM4CH1);
	
		
}



//更新事件中断:CNT=ARR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{		
			count++;
			if(count==0XFFFFFFFF) count=0;
			HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_0);					 
	}
}
//触发事件(TRGI):从模式门控模式开始和结束都触发
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM2)
	{		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0)
			{
				//按键按下
				one_CCR_1=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1)+count*65536;
			}
			if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==1)
			{
				//松开按键
				two_CCR_1=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1)+count*65536;
				num=two_CCR_1-one_CCR_1;
				
			}	
						
	}
}

E:门控模式-其他通道

我们还是不使用输入捕获的功能,只需改2个参数就好了。



TIM_Slave.InputTrigger=TIM_TS_ETRF;       //触发源--ETR
	           //滤波器
//极性:反转电平:低电平有效,低电平CNT开始计数。(PA0默认为高电平)
TIM_Slave.TriggerPolarity=TIM_TRIGGERPOLARITY_INVERTED; 

EG:


TIM_Slave.InputTrigger=TIM_TS_TI1FP1;       //触发源--ETR
//极性:低电平有效
TIM_Slave.TriggerPolarity=TIM_TRIGGERPOLARITY_FALLING;    

其他代码完全一样

F:触发模式

TIF:触发中断(TRGI) 。在来一个上升沿,触发中断还会被触发,但是由于计数器只能开始收控,计数器不能再次被停止。

功能:使用内部时钟源触发CNT计数器。我们使用的是按键一段接低,一段接IO口(高),所以默认为高电平。当按键按下变为低电平CNT开始计数,(然后就周期性的反复,只有开始收控)。但是每来一个低电平都会触发我们的TRGI触发中断。---电平极性配置为低电平有效。

路线

#include "stm32f1xx_hal.h"

uint32_t count=0;
uint32_t one_CCR_1=0;
uint32_t two_CCR_1=0;
uint32_t num=0;

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_Slave={0};

	
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);

	//从模式配置
	TIM_Slave.SlaveMode=TIM_SLAVEMODE_TRIGGER;     //从模式功能---触发模式
	TIM_Slave.InputTrigger=TIM_TS_TI1FP1;       //触发源--ETR
	TIM_Slave.TriggerFilter=0x8;             //滤波器
	//极性:低电平有效
	TIM_Slave.TriggerPolarity=TIM_TRIGGERPOLARITY_FALLING;    
	//从模式----触发中断(TRGI)
	HAL_TIM_SlaveConfigSynchro_IT(&HandleTIM4CH1, &TIM_Slave);
	
	//以中断的方式打开计数器
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
	
	
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
			HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
			HAL_NVIC_SetPriority(TIM2_IRQn,2,0);
			HAL_NVIC_EnableIRQ(TIM2_IRQn);
		
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;     
			GPIO_InitType.Pin=GPIO_PIN_0; 
			GPIO_InitType.Pull=GPIO_PULLUP;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
		
		
		}
}

void TIM2_IRQHandler()
{
		HAL_TIM_IRQHandler(&HandleTIM4CH1);
	
		
}



//更新事件中断:CNT=ARR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{		
			count++;
			if(count==0XFFFFFFFF) count=0;
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
							 
	}
}
//触发事件(TRGI):从模式门控模式开始和结束都触发
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{		
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		
	}
}

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"



uint32_t   time=0;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	
	IC_TIM4_CH1_init(10000-1,36000-1);  //0.5ms   T=5s
	OLED_ShowString(1,1,"CNT:");
	
	 while (1)
    { 
			num=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
			OLED_ShowNum(1,5,num,7); 
 
    }
		
		
}

注意:触发源如果配置为ED通道的时候,不需要配置电平极性,因为ED是双边沿触发。

G:外部时钟模式2 + 触发模式

        外部时钟源模式二:见上面的。从模式:不建议使用TIMx_SMCR寄存器的TS位选择ETR作为TRGI。 因为ETR已经做为我们外部模式2的通道触发源了。

        可以实现一下效果:


功能:必须按下PA1开启计数器时,按下PA0驱动计数器才有效,否则按下PA0不计数

路线: 从模式直接影响计数器

#include "stm32f1xx_hal.h"

uint32_t count=0;
uint32_t one_CCR_1=0;
uint32_t two_CCR_1=0;
uint32_t num=0;

//输入捕获功能
TIM_HandleTypeDef HandleTIM4CH1;

void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_Slave={0};
	TIM_ClockConfigTypeDef TIM_Clock={0};
	
	HandleTIM4CH1.Instance=TIM2;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);

	//外部时钟源配置
	TIM_Clock.ClockFilter=0x8;
	TIM_Clock.ClockPolarity=TIM_CLOCKPOLARITY_INVERTED;  //极性反转:低(默认为高,所以反转后为低)
	TIM_Clock.ClockPrescaler=TIM_CLOCKPRESCALER_DIV1;
	TIM_Clock.ClockSource=TIM_CLOCKSOURCE_ETRMODE2;

	//从模式配置
	TIM_Slave.SlaveMode=TIM_SLAVEMODE_TRIGGER;     //从模式功能---触发模式
	TIM_Slave.InputTrigger=TIM_TS_TI2FP2;       //触发源-
	TIM_Slave.TriggerFilter=0x8;             //滤波器
	//极性:低电平有效
	TIM_Slave.TriggerPolarity=TIM_TRIGGERPOLARITY_FALLING;    
	
	//设置外部时钟源驱动CNT
	HAL_TIM_ConfigClockSource(&HandleTIM4CH1,&TIM_Clock);
	
	//从模式----触发中断(TRGI)
	HAL_TIM_SlaveConfigSynchro_IT(&HandleTIM4CH1, &TIM_Slave);


	//以中断的方式打开计数器
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
	
	
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
			HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);
			HAL_NVIC_SetPriority(TIM2_IRQn,2,0);
			HAL_NVIC_EnableIRQ(TIM2_IRQn);
			//外部通道ETR驱动计数器CNT
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_INPUT;;     
			GPIO_InitType.Pin=GPIO_PIN_0; 
			GPIO_InitType.Pull=GPIO_PULLUP;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
			//从模式引脚配置PA1--TIM2_CH2,上面必须使用TIM_TS_TI2FP2
			
			GPIO_InitType.Mode=GPIO_MODE_INPUT;     
			GPIO_InitType.Pin=GPIO_PIN_1; 
			GPIO_InitType.Pull=GPIO_PULLUP;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);
			
		
		
		}
}

void TIM2_IRQHandler()
{
		HAL_TIM_IRQHandler(&HandleTIM4CH1);
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		
}



//更新事件中断:CNT=ARR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{		
			count++;
			if(count==0XFFFFFFFF) count=0;
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
							 
	}
}
//触发事件(TRGI):从模式门控模式开始和结束都触发
void HAL_TIM_TriggerCallback(TIM_HandleTypeDef *htim)
{
	HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
	if(htim->Instance==TIM2)
	{		
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		
	}
}

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"



uint32_t   time=0;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	
	IC_TIM4_CH1_init(10-1,1-1);  
	OLED_ShowString(1,1,"CNT:");
	
	 while (1)
    { 
			num=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
			OLED_ShowNum(1,5,num,3); 
 
    }
		
		
}


        外部时钟模式2+从模式的其他模式。只需要改变从模式的模式(必须),也可以改变从模式模式的通道。

//从模式配置
TIM_Slave.SlaveMode=TIM_SLAVEMODE_TRIGGER;     //从模式功能---触发模式
TIM_Slave.InputTrigger=TIM_TS_TI2FP2;       //触发源-
TIM_Slave.TriggerFilter=0x8;             //滤波器
//极性:低电平有效
TIM_Slave.TriggerPolarity=TIM_TRIGGERPOLARITY_FALLING;    
	
//从模式----触发中断(TRGI)
HAL_TIM_SlaveConfigSynchro_IT(&HandleTIM4CH1, &TIM_Slave);

九:PWM输入模式

        因为我们上面讲解了从模式,我们知道从模式的复位是有延迟的,所以我们明白是先捕获计数器的值在清零计数器。


功能:使用PWM输出信号,在输入PWM输入模式捕获测量PWM信号的参数(占空比,周期)

路线

        从模式:上升沿触发。

        TIF2FP1:上升沿触发。占空比=CCR2*PWM输入模式计一个数的时间。

        TIF2FP2:下降沿触发。周期=(CCR2/CCR1)*100%

我们使用32输出PWM信号和测量pwm信号的各种参数

//发生PWM波 T=2000us  占空比:50%
   IC_TIM4_CH1_init(2000-1,72-1);

#include "stm32f1xx_hal.h"


TIM_HandleTypeDef TIM_HandleTIMCH3;
void TIM3_CH2_init(uint16_t psc,uint16_t arr)
{
	TIM_OC_InitTypeDef TIM_OC_Init={0};
	TIM_HandleTIMCH3.Instance=TIM3;
	
	TIM_HandleTIMCH3.Init.Period=arr;
	TIM_HandleTIMCH3.Init.ClockDivision=TIM_COUNTERMODE_UP; /*向上计数*/
	TIM_HandleTIMCH3.Init.Prescaler=psc;
	HAL_TIM_Base_Init(&TIM_HandleTIMCH3);
	
	TIM_OC_Init.OCMode=TIM_OCMODE_PWM1;  /*为pwm模式1*/
	TIM_OC_Init.Pulse=arr/2;     /*比较值 CCRX的值*/
	TIM_OC_Init.OCPolarity=TIM_OCPOLARITY_HIGH;   /*输出极性-低电频有效*/
										
	/*配置pwm模式比较值等*/
	HAL_TIM_PWM_ConfigChannel(&TIM_HandleTIMCH3,&TIM_OC_Init,TIM_CHANNEL_2);
	//使能计数器
	HAL_TIM_PWM_Start(&TIM_HandleTIMCH3,TIM_CHANNEL_2);
	
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
			
		__HAL_RCC_GPIOA_CLK_ENABLE() ;
		__HAL_RCC_TIM3_CLK_ENABLE();
		
		GPIO_InitTypeDef GPIO_InitType;
		GPIO_InitType.Mode=GPIO_MODE_AF_PP;   /*复用推完输出*/
		GPIO_InitType.Pin=GPIO_PIN_7;
		GPIO_InitType.Pull=GPIO_NOPULL;
		GPIO_InitType.Speed=GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA,&GPIO_InitType); 
	
	}

}

测量PWM信号

#include "stm32f1xx_hal.h"


uint32_t CCR2=0;
uint32_t period=0;
uint32_t CCR1=0;
uint32_t count=0;
uint32_t dutyfactor=0;
TIM_HandleTypeDef TIM_Handle;
void TIM_PWM_IC(uint16_t ARR,uint16_t PSC)
{	
	TIM_IC_InitTypeDef TIM_IC_Init1={0};
	TIM_IC_InitTypeDef TIM_IC_Init2={0};
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};

	TIM_Handle.Instance=TIM2;
	TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;
	TIM_Handle.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE;//自动重装载值
	TIM_Handle.Init.Period=ARR;
	TIM_Handle.Init.Prescaler=PSC;

	HAL_TIM_IC_Init(&TIM_Handle);
	__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);//清除更新中断标志位
	
	//从模式配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_TI1FP1;
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_RESET;
	TIM_SlaveConfig.TriggerFilter=0x8;
	TIM_SlaveConfig.TriggerPolarity=TIM_TRIGGERPOLARITY_RISING;
	TIM_SlaveConfig.TriggerPrescaler=TIM_TRIGGERPRESCALER_DIV1;
	//从模式配置--打开触发中断
	HAL_TIM_SlaveConfigSynchro_IT(&TIM_Handle,&TIM_SlaveConfig);
	
	//输入模式
	TIM_IC_Init1.ICFilter=0x8;
	TIM_IC_Init1.ICPolarity=TIM_ICPOLARITY_RISING;
	TIM_IC_Init1.ICPrescaler=TIM_ICPSC_DIV1;
	TIM_IC_Init1.ICSelection=TIM_ICSELECTION_DIRECTTI;  //直连
	//输入捕获配置
	HAL_TIM_IC_ConfigChannel(&TIM_Handle,&TIM_IC_Init1,TIM_CHANNEL_1);
	
	//输入模式
	TIM_IC_Init2.ICFilter=0x8;
	TIM_IC_Init2.ICPolarity=TIM_ICPOLARITY_FALLING;
	TIM_IC_Init2.ICPrescaler=TIM_ICPSC_DIV1;
	TIM_IC_Init2.ICSelection=TIM_ICSELECTION_INDIRECTTI;  //交叉
	//输入捕获配置
	HAL_TIM_IC_ConfigChannel(&TIM_Handle,&TIM_IC_Init2,TIM_CHANNEL_2);
	
	HAL_TIM_IC_Start_IT(&TIM_Handle,TIM_CHANNEL_1);
	HAL_TIM_IC_Start_IT(&TIM_Handle,TIM_CHANNEL_2);

}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM2)
		{
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
			__HAL_RCC_TIM2_CLK_ENABLE();
			
			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 3);              /* 抢占1,子优先级3 */
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 
			
			GPIO_InitTypeDef GPIO_InitType;
			GPIO_InitType.Mode=GPIO_MODE_AF_INPUT;    //AF表示“复用功能”,PP表示“推挽输出”
			GPIO_InitType.Pin=GPIO_PIN_0;         
			GPIO_InitType.Pull=GPIO_NOPULL;
			HAL_GPIO_Init(GPIOA,&GPIO_InitType);	
		}
}

void TIM2_IRQHandler()
{
	HAL_TIM_IRQHandler(&TIM_Handle); 
	HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
}




void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{ 
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
		
			CCR1=HAL_TIM_ReadCapturedValue(&TIM_Handle,TIM_CHANNEL_1);
			period=CCR1;   //计一个数1us
		}
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
				CCR2=HAL_TIM_ReadCapturedValue(&TIM_Handle,TIM_CHANNEL_2);
				dutyfactor=(CCR2/CCR1)*100;
		}
	}		
}


#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"
#include "pwm.h"
#include "pwmIC.h"

uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	//发生PWM波 T=2000us  占空比:50%
	IC_TIM4_CH1_init(2000-1,72-1); 

	//检测PWM
	TIM_PWM_IC(65536-1,72-1);   //72000 000/72=1000 000s=1us 计一个数1us
	OLED_ShowString(1,1,"period:");
	OLED_ShowString(1,13,"us");
	OLED_ShowString(2,1,"dutyfactor:");
	OLED_ShowString(2,15,"%");
	 while (1)
    {
			OLED_ShowNum(1,8,period,5);	
			OLED_ShowSignedNum(2,12,dutyfactor,2);					
    }
}


十:主从模式

     

在手册的定时器同步中

        所有TIMx 定时器在内部相连,用于定时器同步或链接。当一个定时器处于主模式时,它可以对 另一个处于从模式的定时器的计数器进行复位、启动、停止或提供时钟等操作。

主定时器和从定时器的选择不是随便选的,而是根据表格选取的。ITRx做为从定时器的通道也必须按照表中来选取。

主定时器(MMS):信号从TRGO发送给从定时器

从定时器(SMS):通过ITR0,ITR1,ITR2,ITR3,中的一个通道接收来自主模式的信号

eg:

选择TIM3为从定时器,主定时器可以是TIM2,但是从定时器的通道必须为ITR1。

 从定时器

主定时器 

什么时候主定时器把信号发送给从定时器,根据8中模式来判断。


A:使用一个定时器作为另一个定时器的预分频器

从定时器的CNT计数器由主定时器驱动,因为从定时器使用了外部时钟模式1。

功能:主定时器TIM2,从定时器TIM3,   定时器2发送更新中断时,定时器3计一个数。

因为:主定时器发生一个更新事件,给从定时器一个信号,从定时器开始计一个数。(一个更新事件计一个数。)

主定时器:

从定时器:

路线

#include "stm32f1xx_hal.h"

#include "delay.h"

//从定时器
TIM_HandleTypeDef HandleTIM4CH1;


//主定时器
TIM_HandleTypeDef TIM_Handle;
uint16_t zhu=0;
uint16_t c=0;


/**
  * @brief  定时器2做为主定时器
  *         
  */
void IC_TIM2(uint16_t arr,uint16_t psc)
{
	TIM_MasterConfigTypeDef TIM_MasterConfig={0};
	
	TIM_Handle.Instance=TIM2;   //基地址
	TIM_Handle.Init.Period=arr;
	TIM_Handle.Init.Prescaler=psc;
	TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&TIM_Handle);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);
      
	TIM_MasterConfig.MasterOutputTrigger=TIM_TRGO_UPDATE;  //模式:发送更新中断提供信号给从定时器
	HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle,&TIM_MasterConfig);
	
	HAL_TIM_Base_Start_IT(&TIM_Handle);
	
}

/**
  * @brief  定时器3做为从定时器
  *         
  */
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	
	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
   
	//从定时器配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_ITR1;    //触发源
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_EXTERNAL1;  //模式外部时钟模式1
	HAL_TIM_SlaveConfigSynchro(&HandleTIM4CH1,&TIM_SlaveConfig);
	
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
		
}





void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM3)
		{
			 __HAL_RCC_TIM3_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM3_IRQn, 1, 2);              
      HAL_NVIC_EnableIRQ(TIM3_IRQn); 	
					
		}
			
		if(htim->Instance==TIM2)
		{
			__HAL_RCC_TIM2_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 4);              
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 
					

		}
						

}


void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1); 
		
}


void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM_Handle);  
	
}



void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		//主定时器
		
		zhu++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		if(zhu==5) zhu=0;
				
	}
	if(htim->Instance==TIM3)
	{
		//从定时器
		c++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	
	}
}


#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"


uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	OLED_ShowString(1,1,"z:");
	OLED_ShowString(2,1,"c:");
	//主模式
	IC_TIM2(2000-1,36000-1);   //T=1S
	//从模式
	IC_TIM4_CH1_init(5-1,1-1);

	 while (1)
    {
			OLED_ShowNum(1,3,zhu,4);
			OLED_ShowNum(2,3,c,4);
							
    }
}

 当主定时器溢出5次的时候(给从定时器发送了5从信号),从定时器才发生一次溢出。

	主模式
	IC_TIM2(2000-1,36000-1);   //T=1S
	从模式
	IC_TIM4_CH1_init(5-1,1-1);

重要参数:

主定时器
HAL_StatusTypeDef HAL_TIMEx_MasterConfigSynchronization(TIM_HandleTypeDef *htim,
                                                        TIM_MasterConfigTypeDef *sMasterConfig)
typedef struct
{
  uint32_t  MasterOutputTrigger;   主模式选择:主模式下送到从定时器的同步信息
  uint32_t  MasterSlaveMode;       主模式使能
} TIM_MasterConfigTypeDef

从定时器
HAL_StatusTypeDef HAL_TIM_SlaveConfigSynchro(TIM_HandleTypeDef *htim, TIM_SlaveConfigTypeDef *sSlaveConfig)
typedef struct
{
  uint32_t  SlaveMode;           模式选择
  uint32_t  InputTrigger;        触发源
  uint32_t  TriggerPolarity;     触发信号
  uint32_t  TriggerPrescaler;    触发预分频
  uint32_t  TriggerFilter;       触发滤波
} TIM_SlaveConfigTypeDef;

  uint32_t  MasterSlaveMode;       主模式使能 

B:使用一个定时器复位一个定时器

2个定时器的计数器都由系统时钟驱动

和上面的所有全部一样,只需要把从模式的模式改变就ok了。

从定时器配置
TIM_SlaveConfig.InputTrigger=TIM_TS_ITR1;    //触发源
TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_RESET;  //模式外部时钟模式1
HAL_TIM_SlaveConfigSynchro(&HandleTIM4CH1,&TIM_SlaveConfig);
__HAL_TIM_URS_ENABLE(&HandleTIM4CH1);

         从模式的复位会导致:更新事件的产生,我们可以通过调节参数使从模式的复位不触发更新事件。

__HAL_TIM_URS_ENABLE()

C:使用一个外部触发同步地启动2个定时器

2个定时器的计数器都由系统时钟驱动

功能:PA0下降沿,主定时器和从定时器同步计数。

使用了主定时器的从模式。    使能下面的这个

TIM_MasterConfig.MasterSlaveMode=TIM_MASTERSLAVEMODE_ENABLE;

主定时器:

从模式配置为触发模式

从定时器:

主模式的定时器被使能的时候,发送信号给从模式。(TIM_MasterConfig.MasterSlaveMode=TIM_MASTERSLAVEMODE_ENABLE;)所以2个定时器为同步的

路线

#include "stm32f1xx_hal.h"

#include "delay.h"

//从定时器
TIM_HandleTypeDef HandleTIM4CH1;


//主定时器
TIM_HandleTypeDef TIM_Handle;
uint16_t zhu=0;
uint16_t c=0;


/**
  * @brief  定时器2做为主定时器
  *         
  */
void IC_TIM2(uint16_t arr,uint16_t psc)
{
	TIM_MasterConfigTypeDef TIM_MasterConfig={0};
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	
	TIM_Handle.Instance=TIM2;   //基地址
	TIM_Handle.Init.Period=arr;
	TIM_Handle.Init.Prescaler=psc;
	TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&TIM_Handle);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);
      
	TIM_MasterConfig.MasterOutputTrigger=TIM_TRGO_ENABLE;  //模式:使能
	TIM_MasterConfig.MasterSlaveMode=TIM_MASTERSLAVEMODE_ENABLE;
	HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle,&TIM_MasterConfig);
	//从模式配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_TI1FP1;
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_TRIGGER;   //触发模式
	TIM_SlaveConfig.TriggerFilter=0x8;
	TIM_SlaveConfig.TriggerPolarity=TIM_TRIGGERPOLARITY_FALLING; //下降沿
	
	HAL_TIM_SlaveConfigSynchro_IT(&TIM_Handle,&TIM_SlaveConfig);
	
	HAL_TIM_Base_Start_IT(&TIM_Handle);
	
}

/**
  * @brief  定时器3做为从定时器
  *         
  */
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	
	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
   
	//从定时器配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_ITR1;    //触发源
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_TRIGGER;  //触发
	
	HAL_TIM_SlaveConfigSynchro(&HandleTIM4CH1,&TIM_SlaveConfig);
	__HAL_TIM_URS_ENABLE(&HandleTIM4CH1);
	
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
		
}





void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM3)
		{
			 __HAL_RCC_TIM3_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM3_IRQn, 1, 2);              
      HAL_NVIC_EnableIRQ(TIM3_IRQn); 	
					
		}
			
		if(htim->Instance==TIM2)
		{//主模式
			__HAL_RCC_TIM2_CLK_ENABLE();
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 4);              
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 
				

			GPIO_InitTypeDef GPIO_InitType;
		 GPIO_InitType.Mode=GPIO_MODE_INPUT;
		 GPIO_InitType.Pin=GPIO_PIN_0;
		 GPIO_InitType.Pull=GPIO_PULLUP; //上拉
	
	
		 HAL_GPIO_Init(GPIOA,&GPIO_InitType); 		


		}
						

}


void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1); 
		
}


void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM_Handle);  
	
}






void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		//主定时器
		
		zhu++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		
				
	}
	if(htim->Instance==TIM3)
	{
		//从定时器
		c++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	
	}
}
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"


uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	OLED_ShowString(1,1,"z:");
	OLED_ShowString(2,1,"c:");
//	//主模式
//	IC_TIM2(2000-1,36000-1);   //T=1S
//	//从模式
//	IC_TIM4_CH1_init(4000-1,36000-1);  //T=2
	
	
	IC_TIM2(65536-1,7200-1);   //T=1S
	//从模式
	IC_TIM4_CH1_init(65536-1,7200-1);  //T=2
	 while (1)
    {
			OLED_ShowNum(1,3,zhu,4);
			OLED_ShowNum(2,3,c,4);
			
			uint16_t z=__HAL_TIM_GET_COUNTER(&TIM_Handle);
			uint16_t c=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
			
			
			OLED_ShowNum(3,1,z,8);	
		  OLED_ShowNum(4,1,c,8);	
							
    }
}

D:主定时器的输入捕获复位从定时器

2个定时器的计数器都由系统时钟驱动

功能:主定时器2 捕获PA0下降沿 从定时器3被复位

主定时器:

注意:只有通道1才可以。主定时器需要配置为输入捕获模式。

 从模式:

        当在主定时器中捕获到PA0的下降沿的时候,主定时器会发送信号给从定时器,从定时器计数器清零。

路线:

#include "stm32f1xx_hal.h"

#include "delay.h"

//从定时器
TIM_HandleTypeDef HandleTIM4CH1;


//主定时器
TIM_HandleTypeDef TIM_Handle;
uint16_t zhu=0;
uint16_t c=0;


/**
  * @brief  定时器2做为主定时器
  *         
  */
void IC_TIM2(uint16_t arr,uint16_t psc)
{
	TIM_MasterConfigTypeDef TIM_MasterConfig={0};
	TIM_IC_InitTypeDef TIM_IC_Init={0};
	
	TIM_Handle.Instance=TIM2;   //基地址
	TIM_Handle.Init.Period=arr;
	TIM_Handle.Init.Prescaler=psc;
	TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_IC_Init(&TIM_Handle);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);
      
	//主定时器配置
	TIM_MasterConfig.MasterOutputTrigger=TIM_TRGO_OC1;  //模式:比较脉冲
	HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle,&TIM_MasterConfig);

	//输入捕获配置
	TIM_IC_Init.ICFilter=0x8;
	TIM_IC_Init.ICPolarity=TIM_ICPOLARITY_FALLING;
	TIM_IC_Init.ICPrescaler=TIM_ICPSC_DIV1;
	TIM_IC_Init.ICSelection=TIM_ICSELECTION_DIRECTTI; //直连
	HAL_TIM_IC_ConfigChannel(&TIM_Handle,&TIM_IC_Init,TIM_CHANNEL_1);
	
	//以捕获中断的方式打开
	HAL_TIM_IC_Start_IT(&TIM_Handle,TIM_CHANNEL_1);
	
}

/**
  * @brief  定时器3做为从定时器
  *         
  */
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	
	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
   
	//从定时器配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_ITR1;    //触发源
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_RESET;  //触发
	
	HAL_TIM_SlaveConfigSynchro(&HandleTIM4CH1,&TIM_SlaveConfig);
	__HAL_TIM_URS_ENABLE(&HandleTIM4CH1);   //从模式复位不会触发更新事件
	
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
		
}





void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM3)
		{
			 __HAL_RCC_TIM3_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM3_IRQn, 1, 2);              
      HAL_NVIC_EnableIRQ(TIM3_IRQn); 	
					
		}
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{//主模式
			__HAL_RCC_TIM2_CLK_ENABLE();
			__HAL_RCC_GPIOA_CLK_ENABLE() ;
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 4);              
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 
				

			GPIO_InitTypeDef GPIO_InitType;
		 GPIO_InitType.Mode=GPIO_MODE_INPUT;
		 GPIO_InitType.Pin=GPIO_PIN_0;
		 GPIO_InitType.Pull=GPIO_PULLUP; //上拉
	
		 HAL_GPIO_Init(GPIOA,&GPIO_InitType); 		

		}
	
}
void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1); 
		
}


void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM_Handle);  
	
}






void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
		//从定时器
		c++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	
	}
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
 
 	if(htim->Instance==TIM2)
	{
		//主定时器
		
		zhu++;
		
				
	}
 
}#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"


uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	OLED_ShowString(1,1,"z:");
	OLED_ShowString(2,1,"c:");
//	//主模式
//	IC_TIM2(2000-1,36000-1);   //T=1S
//	//从模式
//	IC_TIM4_CH1_init(4000-1,36000-1);  //T=2
	
	
	IC_TIM2(65536-1,7200-1);   //T=1S
	//从模式
	IC_TIM4_CH1_init(65536-1,7200-1);  //T=2
	 while (1)
    {
			OLED_ShowNum(1,3,zhu,4);
			OLED_ShowNum(2,3,c,4);
			
			uint16_t z=__HAL_TIM_GET_COUNTER(&TIM_Handle);
			uint16_t c=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
			
			
			OLED_ShowNum(3,1,z,8);	
		  OLED_ShowNum(4,1,c,8);	
							
    }
}

E:主定时器的输出比较让从定时器计数

从定时器的CNT计数器由主定时器驱动,因为从定时器使用了外部时钟模式1。

功能:主定时器2 通道2匹配时  从定时器3 计一个数

主定时器:

从定时器:

每当主定时器的CNT=比较值,主定时器就会把信号发送给从定时器,从定时器会计一个数。

路线

#include "stm32f1xx_hal.h"

#include "delay.h"

//从定时器
TIM_HandleTypeDef HandleTIM4CH1;


//主定时器
TIM_HandleTypeDef TIM_Handle;
uint16_t zhu=0;
uint16_t c=0;


/**
  * @brief  定时器2做为主定时器
  *         
  */
void IC_TIM2(uint16_t arr,uint16_t psc)
{
	TIM_MasterConfigTypeDef TIM_MasterConfig={0};
	TIM_OC_InitTypeDef TIM_OC_Init={0};
	
	TIM_Handle.Instance=TIM2;   //基地址
	TIM_Handle.Init.Period=arr;
	TIM_Handle.Init.Prescaler=psc;
	TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_OC_Init(&TIM_Handle);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);
      
	//主定时器配置
	TIM_MasterConfig.MasterOutputTrigger=TIM_TRGO_OC2REF;  //模式:比较脉冲
	HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle,&TIM_MasterConfig);

	//输出比较
	TIM_OC_Init.OCMode=TIM_OCMODE_TOGGLE;   //模式比配反转
	TIM_OC_Init.Pulse=1000;
	TIM_OC_Init.OCPolarity=TIM_OCPOLARITY_HIGH;
	HAL_TIM_OC_ConfigChannel(&TIM_Handle,&TIM_OC_Init,TIM_CHANNEL_2);
	
	//以捕获中断的方式打开
	HAL_TIM_OC_Start_IT(&TIM_Handle,TIM_CHANNEL_2);
	
}

/**
  * @brief  定时器3做为从定时器
  *         
  */
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	
	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
   
	//从定时器配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_ITR1;    //触发源
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_EXTERNAL1;  //
	
	HAL_TIM_SlaveConfigSynchro(&HandleTIM4CH1,&TIM_SlaveConfig);
	__HAL_TIM_URS_ENABLE(&HandleTIM4CH1);   //从模式复位不会触发更新事件
	
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
		
}





void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM3)
		{
			 __HAL_RCC_TIM3_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM3_IRQn, 1, 2);              
      HAL_NVIC_EnableIRQ(TIM3_IRQn); 	
					
		}
}

void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM2)
		{//主模式
			__HAL_RCC_TIM2_CLK_ENABLE();

			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 4);              
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 		
		}
	
}
void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1); 
		
}


void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM_Handle);  
	
}






void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
		//从定时器
		c++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	
	}
}

void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
 
 	if(htim->Instance==TIM2)
	{
		if(htim->Channel ==HAL_TIM_ACTIVE_CHANNEL_2)
		{
			//主定时器
			
			zhu++;
			HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
		
		
		}
		
				
	}
 
}#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"


uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	OLED_ShowString(1,1,"z:");
	OLED_ShowString(2,1,"c:");
//	//主模式
	IC_TIM2(2000-1,36000-1);   //T=1S   0.5ms
//	//从模式
	IC_TIM4_CH1_init(4 -1,1-1);  //T=2
	
	

	 while (1)
    {
			OLED_ShowNum(1,3,zhu,4);
			OLED_ShowNum(2,3,c,4);
			
			uint16_t z=__HAL_TIM_GET_COUNTER(&TIM_Handle);
			uint16_t c=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
			
			
			OLED_ShowNum(3,1,z,8);	
		  OLED_ShowNum(4,1,c,8);	
							
    }
}

F :一主多从

从定时器的CNT计数器由主定时器驱动,因为从定时器使用了外部时钟模式1。

功能使用定时器2做为主定时器, 定时器3和定时器4做为从定时器。(一主二从)

主定时器发生一次溢出,发生信号给2个从定时器,从定时器计一个数。

 主定时器:

从定时器:

#include "stm32f1xx_hal.h"

#include "delay.h"

//从定时器
TIM_HandleTypeDef HandleTIM4CH1;
TIM_HandleTypeDef TIM_Handleinit; //从定时器4

//主定时器
TIM_HandleTypeDef TIM_Handle;
uint16_t zhu=0;
uint16_t c=0;
uint16_t c1=0;

/**
  * @brief  定时器2做为主定时器
  *         
  */
void IC_TIM2(uint16_t arr,uint16_t psc)
{
	TIM_MasterConfigTypeDef TIM_MasterConfig={0};

	
	TIM_Handle.Instance=TIM2;   //基地址
	TIM_Handle.Init.Period=arr;
	TIM_Handle.Init.Prescaler=psc;
	TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&TIM_Handle);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);
      
	//主定时器配置
	TIM_MasterConfig.MasterOutputTrigger=TIM_TRGO_UPDATE;  
	HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle,&TIM_MasterConfig);


	//以跟新中断的方式打开
	HAL_TIM_Base_Start_IT(&TIM_Handle);
	
}

/**
  * @brief  定时器3做为从定时器
  *         
  */
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	
	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
   
	//从定时器配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_ITR1;    //触发源
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_EXTERNAL1;  //
	
	HAL_TIM_SlaveConfigSynchro(&HandleTIM4CH1,&TIM_SlaveConfig);
	__HAL_TIM_URS_ENABLE(&HandleTIM4CH1);   //从模式复位不会触发更新事件
	
	
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
		
}




/**
  * @brief  定时器4做为从定时器
  *         
  */
void TIM4__init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	
	TIM_Handleinit.Instance=TIM4;   //基地址
	TIM_Handleinit.Init.Period=arr;
	TIM_Handleinit.Init.Prescaler=psc;
	TIM_Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&TIM_Handleinit);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&TIM_Handleinit,TIM_FLAG_UPDATE);
   
	//从定时器配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_ITR1;    //触发源
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_EXTERNAL1;  //
	
	HAL_TIM_SlaveConfigSynchro(&TIM_Handleinit,&TIM_SlaveConfig);
	__HAL_TIM_URS_ENABLE(&TIM_Handleinit);   //从模式复位不会触发更新事件
	
	
	HAL_TIM_Base_Start_IT(&TIM_Handleinit);
		
}



void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{		
	
		if(htim->Instance==TIM2)
		{//主模式
			__HAL_RCC_TIM2_CLK_ENABLE();

			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 4);              
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 		
		}
		
		if(htim->Instance==TIM3)
		{
			//从模式
			 __HAL_RCC_TIM3_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM3_IRQn, 1, 2);              
      HAL_NVIC_EnableIRQ(TIM3_IRQn); 	
					
		}
		
		if(htim->Instance==TIM4)
		{
			//从模式
			 __HAL_RCC_TIM4_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM4_IRQn, 1, 3);              
      HAL_NVIC_EnableIRQ(TIM4_IRQn); 	
					
		}
}


void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1); 
		
}


void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM_Handle);  
	
}

void TIM4_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM_Handleinit);  
	
}






void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
		//从定时器
		c++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	}
	if(htim->Instance==TIM3)
	{
		//从定时器
		c++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	}
	if(htim->Instance==TIM4)
	{
		//从定时器
		c1++;
		//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	}
	
	
	
}

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"


uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	OLED_ShowString(1,1,"zhuTIM2:");
	OLED_ShowString(2,1,"cTIM3:");
	OLED_ShowString(3,1,"cTIM4:");
//	//主模式
	IC_TIM2(4000-1,36000-1);   //T=1S   0.5ms
//	//从模式定时器3
	IC_TIM4_CH1_init(4 -1,1-1);  //T=2
	//从定时器4
	TIM4__init(10-1,1-1);
	

	 while (1)
    {
			
			
			uint16_t z=__HAL_TIM_GET_COUNTER(&TIM_Handle);
			//从定时器3
			uint16_t c=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
				//从定时器4
			uint16_t c2=__HAL_TIM_GET_COUNTER(&TIM_Handleinit);
			
			OLED_ShowNum(1,9,z,8);
			OLED_ShowNum(2,7,c,8);
			OLED_ShowNum(3,7,c2,8);
			

	
							
    }
}

G:定时器串联

功能

        主定时器2 更新时 从定时器3记一个数

        主定时器3 更新时 从定时器4记一个数

        定时器3既做主也做从

#include "stm32f1xx_hal.h"

#include "delay.h"

//从定时器
TIM_HandleTypeDef HandleTIM4CH1;
TIM_HandleTypeDef TIM_Handleinit; //从定时器4

//主定时器
TIM_HandleTypeDef TIM_Handle;
uint16_t zhu=0;
uint16_t c=0;
uint16_t c1=0;

/**
  * @brief  定时器2做为主定时器
  *         
  */
void IC_TIM2(uint16_t arr,uint16_t psc)
{
	TIM_MasterConfigTypeDef TIM_MasterConfig={0};

	
	TIM_Handle.Instance=TIM2;   //基地址
	TIM_Handle.Init.Period=arr;
	TIM_Handle.Init.Prescaler=psc;
	TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&TIM_Handle);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&TIM_Handle,TIM_FLAG_UPDATE);
      
	//主定时器配置
	TIM_MasterConfig.MasterOutputTrigger=TIM_TRGO_UPDATE;  
	HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle,&TIM_MasterConfig);


	//以跟新中断的方式打开
	HAL_TIM_Base_Start_IT(&TIM_Handle);
	
}

/**
  * @brief  定时器3做为从定时器
  *         
  */
void IC_TIM4_CH1_init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	TIM_MasterConfigTypeDef TIM_MasterConfig={0};
	
	HandleTIM4CH1.Instance=TIM3;   //基地址
	HandleTIM4CH1.Init.Period=arr;
	HandleTIM4CH1.Init.Prescaler=psc;
	HandleTIM4CH1.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&HandleTIM4CH1);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&HandleTIM4CH1,TIM_FLAG_UPDATE);
   
	//从定时器配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_ITR1;    //触发源
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_EXTERNAL1;  //

	//主定时器配置
	TIM_MasterConfig.MasterOutputTrigger=TIM_TRGO_UPDATE;  
	HAL_TIMEx_MasterConfigSynchronization(&HandleTIM4CH1,&TIM_MasterConfig);
	
	
	HAL_TIM_SlaveConfigSynchro(&HandleTIM4CH1,&TIM_SlaveConfig);
	__HAL_TIM_URS_ENABLE(&HandleTIM4CH1);   //从模式复位不会触发更新事件
	
	
	HAL_TIM_Base_Start_IT(&HandleTIM4CH1);
		
}




/**
  * @brief  定时器4做为从定时器
  *         
  */
void TIM4__init(uint16_t arr,uint16_t psc)
{
	TIM_SlaveConfigTypeDef TIM_SlaveConfig={0};
	
	TIM_Handleinit.Instance=TIM4;   //基地址
	TIM_Handleinit.Init.Period=arr;
	TIM_Handleinit.Init.Prescaler=psc;
	TIM_Handleinit.Init.CounterMode=TIM_COUNTERMODE_UP;   //向上计数
	HAL_TIM_Base_Init(&TIM_Handleinit);
	//清除更新中断标志位
	__HAL_TIM_CLEAR_FLAG(&TIM_Handleinit,TIM_FLAG_UPDATE);
   
	//从定时器配置
	TIM_SlaveConfig.InputTrigger=TIM_TS_ITR2;    //触发源
	TIM_SlaveConfig.SlaveMode=TIM_SLAVEMODE_EXTERNAL1;  //
	
	HAL_TIM_SlaveConfigSynchro(&TIM_Handleinit,&TIM_SlaveConfig);
	__HAL_TIM_URS_ENABLE(&TIM_Handleinit);   //从模式复位不会触发更新事件
	
	
	HAL_TIM_Base_Start_IT(&TIM_Handleinit);
		
}



void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{		
	
		if(htim->Instance==TIM2)
		{//主模式
			__HAL_RCC_TIM2_CLK_ENABLE();

			
      HAL_NVIC_SetPriority(TIM2_IRQn, 1, 4);              
      HAL_NVIC_EnableIRQ(TIM2_IRQn); 		
		}
		
		if(htim->Instance==TIM3)
		{
			//从模式
			 __HAL_RCC_TIM3_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM3_IRQn, 1, 2);              
      HAL_NVIC_EnableIRQ(TIM3_IRQn); 	
					
		}
		
		if(htim->Instance==TIM4)
		{
			//从模式
			 __HAL_RCC_TIM4_CLK_ENABLE();
      HAL_NVIC_SetPriority(TIM4_IRQn, 1, 3);              
      HAL_NVIC_EnableIRQ(TIM4_IRQn); 	
					
		}
}


void TIM3_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&HandleTIM4CH1); 
		
}


void TIM2_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM_Handle);  
	
}

void TIM4_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&TIM_Handleinit);  
	
}






void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM3)
	{
		//从定时器
		c++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	}
	if(htim->Instance==TIM3)
	{
		//从定时器
		c++;
		HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	}
	if(htim->Instance==TIM4)
	{
		//从定时器
		c1++;
		//HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
	}
	
	
	
}

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"


uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	OLED_ShowString(1,1,"zhuTIM2:");
	OLED_ShowString(2,1,"cTIM3:");
	OLED_ShowString(3,1,"cTIM4:");
//	//主模式
	IC_TIM2(4000-1,36000-1);   //T=1S   0.5ms
//	//从模式定时器3 主定时器3
	IC_TIM4_CH1_init(4 -1,1-1);  //T=2
	//从定时器4
	TIM4__init(10-1,1-1);
	

	 while (1)
    {
			
			
			uint16_t z=__HAL_TIM_GET_COUNTER(&TIM_Handle);
			//从定时器3
			uint16_t c=__HAL_TIM_GET_COUNTER(&HandleTIM4CH1);
				//从定时器4
			uint16_t c2=__HAL_TIM_GET_COUNTER(&TIM_Handleinit);
			
			OLED_ShowNum(1,9,z,8);
			OLED_ShowNum(2,7,c,8);
			OLED_ShowNum(3,7,c2,8);
			

	
							
    }
}

十一:DMA

CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/132571722不管是哪个一半(Half)的回调函数都是为我们DMA准备的回调函数。

A:DMA单次方式改变ARR

使用高级定时器TIM1

功能:定时器1 DMA单次方式 改变时间

当计数器溢出的时候,发生更新中断。DMA转运

        更新DMA事件可以改变ARR重载值,(每次发生更新事件的时候,把DMA把值搬给ARR,导致ARR的值发生改变)从而改变基础定时时间。

          DMA本身不会打开定时器的更新中断但是我们为了方便观察现象,我们人为的手动打开更新中断。DMA单次方式,传输4次数据,改变定时时间第一次定时1s,第二次定时2s,第三次定时3s,第四次定时4s第五次定时5s,然后以后一直都是5s。

        

        通常,当你调用 HAL_TIM_Base_Start_DMA() 函数时,你实际上是在配置定时器以便在某个特定的事件(比如更新事件)发生时触发 DMA 传输。这个事件通常是定时器的计数器溢出或者达到预设值

#include "stm32f1xx_hal.h"

#include "delay.h"
uint16_t count=0;


TIM_HandleTypeDef TIM1_Handle;

DMA_HandleTypeDef DMA_Handle={0};

uint16_t tim1_dmabuff[4] = {4000-1,6000-1,8000-1,10000-1};  //内存

void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
	TIM1_Handle.Instance = TIM1;
	TIM1_Handle.Init.Prescaler = psc;
	TIM1_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
	TIM1_Handle.Init.Period = arr;
	TIM1_Handle.Init.RepetitionCounter = rep;   //重复计数器
	TIM1_Handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动重装载值
	HAL_TIM_Base_Init(&TIM1_Handle);	
	
	__HAL_TIM_CLEAR_FLAG(&TIM1_Handle, TIM_FLAG_UPDATE);
	
	
	__HAL_TIM_ENABLE_IT(&TIM1_Handle,TIM_IT_UPDATE);
	//传输地址  传输4次
	HAL_TIM_Base_Start_DMA(&TIM1_Handle,(uint32_t *)tim1_dmabuff,4);	
	
	
}




void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{		
	if(htim->Instance==TIM1)
	{
		__HAL_RCC_TIM1_CLK_ENABLE(); 
		__HAL_RCC_DMA1_CLK_ENABLE(); 
		
		//打开TIM1的更新中断
		HAL_NVIC_SetPriority(TIM1_UP_IRQn,1,2);
		HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
		//打开MDA1的通道5中断
		HAL_NVIC_SetPriority(DMA1_Channel5_IRQn,1,3);
		HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
		
		
		
		DMA_Handle.Instance=DMA1_Channel5;  //TIM1更新中断在DMA1的通道5上
		//传输方向:内存(tim1_dmabuff数组)----->外设(ARR寄存器)
		DMA_Handle.Init.Direction=DMA_MEMORY_TO_PERIPH;  
		//ARR=16位。一个半子=2个字节   1个字节=8位。
		DMA_Handle.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //内存宽度
		DMA_Handle.Init.MemInc=DMA_MINC_ENABLE;   //内存地址是否自增(上面的数组)
		DMA_Handle.Init.Mode=DMA_NORMAL;    //模式  DMA_CIRCULAR
		DMA_Handle.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD; //外设宽度
		DMA_Handle.Init.PeriphInc=DMA_MINC_DISABLE;    //外设地址是否自增(ARR)
		DMA_Handle.Init.Priority=DMA_PRIORITY_MEDIUM;     //优先级
		
		//建立连接关系
		__HAL_LINKDMA(&TIM1_Handle,hdma[TIM_DMA_ID_UPDATE],DMA_Handle);

		HAL_DMA_Init(&DMA_Handle);
		
	
	}	
}

//TIM1跟新中断

void TIM1_UP_IRQHandler(void)
{
	 HAL_TIM_IRQHandler(&TIM1_Handle);
}


//MDA1的通道5中断

void DMA1_Channel5_IRQHandler(void)
{
		HAL_DMA_IRQHandler(&DMA_Handle);
		
}



//溢出中段CNT=CRR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM1)
		{
				HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
				count++;
			
		}
}



//DMA转运完成一半的时候进入这个中断
//在我们这里也就是转运完成2次进入这个
void HAL_TIM_PeriodElapsedHalfCpltCallback(TIM_HandleTypeDef *htim)
{
			
		if(htim->Instance==TIM1)
		{
				HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
				count++;
		}

}

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"


uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	OLED_ShowString(1,1,"num:");

	Timer1_Init(2000-1,36000-1,0);    //1s

	 while (1)
    {
			
			OLED_ShowNum(1,5,count,4);
			uint16_t CNT=__HAL_TIM_GET_COUNTER(&TIM1_Handle);
			OLED_ShowNum(2,1,CNT,8);
	
							
    }
}

重要参数:

__HAL_LINKDMA
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma)typedef struct
{
  uint32_t Direction;            传输方向         
  uint32_t PeriphInc;            外设地址是否递增       
  uint32_t MemInc;               内存地址是否递增     
  uint32_t PeriphDataAlignment;  外设数据对齐方式    
  uint32_t MemDataAlignment;     内存数据对齐方式    
  uint32_t Mode;                 DMA的工作模式    
  uint32_t Priority;             DMA通道的优先级    
} DMA_InitTypeDef;

B:DMA循环方式改变ARR

使用高级定时器TIM1

功能:定时器1 DMA循环方式 改变时间

        更新DMA事件可以改变ARR重载值,从而改变基础定时时间。

        DMA本身不会打开定时器的更新中断但是我们为了方便观察现象,我们人为的手动打开更新中断。DMA循环方式,每次传输4次数据第一次定时1s,第二次定时2s,第三次定时3s,第四次定时4s第五次定时5s,第六次定时2s,第七次定时3s,第八次定时4s第九次定时5s,第十次定时2s,往复循环

只需把DMA的模式改为:循环。 剩下的代码和上面单次的一样

DMA_Handle.Init.Mode=DMA_CIRCULAR;    //模式 

 C:输入捕获--直连DMA

使用高级定时器TIM1

功能:当按键每次按下把CCR1的值拿到数组中去。一对一,捕获2次按键间隔的时间。

发生捕获事件(按键按下)的时候DMA转运。

#include "stm32f1xx_hal.h"

uint16_t count=0;

uint16_t one_anjian;
uint16_t two_anjian;
uint16_t shijian;

DMA_HandleTypeDef DMA_Handle={0};
TIM_HandleTypeDef TIM1_Handle;
//把捕获的CCR的值放入这个数组里面
uint16_t tim1_dmabuff[2] ;  //内存

void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
	TIM_IC_InitTypeDef TIM_IC_Init={0};
	
	TIM1_Handle.Instance = TIM1;
	TIM1_Handle.Init.Prescaler = psc;
	TIM1_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
	TIM1_Handle.Init.Period = arr;
	TIM1_Handle.Init.RepetitionCounter = rep;   //重复计数器
	TIM1_Handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动重装载值

	HAL_TIM_IC_Init(&TIM1_Handle);	
	__HAL_TIM_CLEAR_FLAG(&TIM1_Handle, TIM_FLAG_UPDATE);
	
	//输入捕获
	TIM_IC_Init.ICFilter=0x8;
	TIM_IC_Init.ICPolarity=TIM_ICPOLARITY_RISING;  //极性:上升沿   
	TIM_IC_Init.ICPrescaler=TIM_ICPSC_DIV1;
	TIM_IC_Init.ICSelection=TIM_ICSELECTION_DIRECTTI; //直连
	
	
	HAL_TIM_IC_ConfigChannel(&TIM1_Handle,&TIM_IC_Init,TIM_CHANNEL_1);
	__HAL_TIM_ENABLE_IT(&TIM1_Handle,TIM_IT_UPDATE);
	
	//传输地址  传输4次   不会打开输入捕获中断
	HAL_TIM_IC_Start_DMA(&TIM1_Handle,TIM_CHANNEL_1,(uint32_t *)tim1_dmabuff,2);	
	
	
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{		
	if(htim->Instance==TIM1)
	{
		__HAL_RCC_TIM1_CLK_ENABLE(); 
		__HAL_RCC_DMA1_CLK_ENABLE(); 
		__HAL_RCC_GPIOA_CLK_ENABLE() ;

		
		//打开TIM1的更新中断
		HAL_NVIC_SetPriority(TIM1_UP_IRQn,1,2);
		HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
		//打开MDA1的通道5中断
		HAL_NVIC_SetPriority(DMA1_Channel2_IRQn,1,3);
		HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);

		GPIO_InitTypeDef GPIO_InitType;
		GPIO_InitType.Pin = GPIO_PIN_8;
		GPIO_InitType.Mode = GPIO_MODE_INPUT;
		GPIO_InitType.Pull = GPIO_PULLDOWN;
		HAL_GPIO_Init(GPIOA,&GPIO_InitType);	
		
		
		
		DMA_Handle.Instance=DMA1_Channel2;  //TIM1更新中断在DMA1的通道5上
		//传输方向:外设(CCR1寄存器)----->内存(tim1_dmabuff数组)
		DMA_Handle.Init.Direction=DMA_PERIPH_TO_MEMORY;  
		//CCR1=16位。一个半子=2个字节   1个字节=8位。
		DMA_Handle.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //内存宽度
		DMA_Handle.Init.MemInc=DMA_MINC_ENABLE;   //内存地址是否自增(上面的数组)
		DMA_Handle.Init.Mode=DMA_CIRCULAR;    //模式 :循环
		DMA_Handle.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD; //外设宽度
		DMA_Handle.Init.PeriphInc=DMA_MINC_DISABLE;    //外设地址是否自增(CCR1)
		DMA_Handle.Init.Priority=DMA_PRIORITY_MEDIUM;     //优先级
		
		//建立连接关系
		__HAL_LINKDMA(&TIM1_Handle,hdma[TIM_DMA_ID_CC1],DMA_Handle);

		HAL_DMA_Init(&DMA_Handle);
	}	
}

//TIM1跟新中断

void TIM1_UP_IRQHandler(void)
{
	 HAL_TIM_IRQHandler(&TIM1_Handle);
}

//MDA1的通道2中断

void DMA1_Channel2_IRQHandler(void)
{
		HAL_DMA_IRQHandler(&DMA_Handle);
		
}

//溢出中段CNT=CRR
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
		if(htim->Instance==TIM1)
		{
				HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
				count++;
				if(count==0XFFFF) count=0;
			
		}
}


//由于没有开启捕获中断,所以进入这个函数的是:2次转运完成
//也就是第二次按下
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM1)
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{

			two_anjian=	count;
			shijian=tim1_dmabuff[1]+(two_anjian*65536)-tim1_dmabuff[0]+(one_anjian*65536);
		}		
	}
}

//DMA转运完成一半的时候进入这个中断
//在我们这里也就是转运完成1次进入这个
//也就是第一次按下
void HAL_TIM_IC_CaptureHalfCpltCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM1)
		{
			if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
			{
				one_anjian=count;
				HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);
			}
		}
}
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "OLED.h"
#include "wwdg.h"
#include "key.h"
#include "IC.h"


uint16_t num=0;
uint16_t zone_bit=1;
int main(void)
{
	HAL_Init();                         /* 初始化HAL库 */
  sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
  delay_init(72);                     /* 延时初始化 */
  LED_Init();                        /* LED初始化 */
	LED_Exit_Init();
	OLED_Init();
	OLED_ShowString(1,1,"time:");

	Timer1_Init(65536-1,36000-1,0);    //1s

	 while (1)
    {
			
			OLED_ShowNum(1,6,shijian,8);	
			uint16_t CNT=__HAL_TIM_GET_COUNTER(&TIM1_Handle);
			OLED_ShowNum(2,1,CNT,8);
			OLED_ShowNum(3,1,tim1_dmabuff[0],8);
			OLED_ShowNum(4,1,tim1_dmabuff[1],8);
				
    }
}

D:输入捕获--Burst方式按键时长

#include "stm32f1xx_hal.h"

uint16_t count=0;

uint16_t one_anjian;
uint16_t two_anjian;
uint16_t shijian;

DMA_HandleTypeDef DMA_Handle={0};
TIM_HandleTypeDef TIM1_Handle;
//把捕获的CCR的值放入这个数组里面 0ccr1 1CCR2
uint16_t tim1_dmabuff[2] ;  //内存

void Timer1_Init(uint16_t arr, uint16_t psc, uint8_t rep)
{
	TIM_IC_InitTypeDef TIM_IC_Init={0};
	TIM_IC_InitTypeDef TIM_IC_Init2={0};
	TIM1_Handle.Instance = TIM1;
	TIM1_Handle.Init.Prescaler = psc;
	TIM1_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
	TIM1_Handle.Init.Period = arr;
	TIM1_Handle.Init.RepetitionCounter = rep;   //重复计数器
	TIM1_Handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动重装载值

	HAL_TIM_IC_Init(&TIM1_Handle);	
	__HAL_TIM_CLEAR_FLAG(&TIM1_Handle, TIM_FLAG_UPDATE);
	
	//输入捕获
	//按下---CCR1
	TIM_IC_Init.ICPolarity = TIM_ICPOLARITY_RISING;
	TIM_IC_Init.ICSelection = TIM_ICSELECTION_INDIRECTTI; //交叉
	TIM_IC_Init.ICPrescaler = TIM_ICPSC_DIV1;
	TIM_IC_Init.ICFilter = 0x08;
	HAL_TIM_IC_ConfigChannel(&TIM1_Handle,&TIM_IC_Init,TIM_CHANNEL_1);
	//放开CCR2
	TIM_IC_Init2.ICPolarity = TIM_ICPOLARITY_FALLING;
	TIM_IC_Init2.ICSelection = TIM_ICSELECTION_DIRECTTI;  //直连
	TIM_IC_Init2.ICPrescaler = TIM_ICPSC_DIV1;
	TIM_IC_Init2.ICFilter = 0x08;
	HAL_TIM_IC_ConfigChannel(&TIM1_Handle,&TIM_IC_Init2,TIM_CHANNEL_2);
	
	
	HAL_TIM_IC_ConfigChannel(&TIM1_Handle,&TIM_IC_Init,TIM_CHANNEL_1);
	HAL_TIM_IC_ConfigChannel(&TIM1_Handle,&TIM_IC_Init2,TIM_CHANNEL_2);

	
	
	//以Burst连续读取方式读取DMA
	HAL_TIM_DMABurst_ReadStart(&TIM1_Handle,TIM_DMABASE_CCR1,TIM_DMA_CC2,(uint32_t *)tim1_dmabuff,TIM_DMABURSTLENGTH_2TRANSFERS);
	//使用连续的方式,必须以种方式开启,不能以单次开始(_DMA的方式)
	HAL_TIM_IC_Start(&TIM1_Handle,TIM_CHANNEL_2);	
	HAL_TIM_IC_Start(&TIM1_Handle,TIM_CHANNEL_1);	
	
}

void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
{		
	if(htim->Instance==TIM1)
	{
		__HAL_RCC_TIM1_CLK_ENABLE(); 
		__HAL_RCC_DMA1_CLK_ENABLE(); 
		__HAL_RCC_GPIOA_CLK_ENABLE() ;

		
		//打开TIM1的更新中断
		HAL_NVIC_SetPriority(TIM1_UP_IRQn,1,2);
		HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
		//打开MDA1的通道5中断
		HAL_NVIC_SetPriority(DMA1_Channel3_IRQn,1,3);
		HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);

		GPIO_InitTypeDef GPIO_InitType;
		GPIO_InitType.Pin = GPIO_PIN_9;
		GPIO_InitType.Mode = GPIO_MODE_INPUT;
		GPIO_InitType.Pull = GPIO_PULLDOWN;
		HAL_GPIO_Init(GPIOA,&GPIO_InitType);	
		
		
		
		DMA_Handle.Instance=DMA1_Channel3;  //TIM1更新中断在DMA1的通道5上
		//传输方向:外设(CCR1寄存器)----->内存(tim1_dmabuff数组)
		DMA_Handle.Init.Direction=DMA_PERIPH_TO_MEMORY;  
		//CCR1=16位。一个半子=2个字节   1个字节=8位。
		DMA_Handle.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //内存宽度
		DMA_Handle.Init.MemInc=DMA_MINC_ENABLE;   //内存地址是否自增(上面的数组)
		DMA_Handle.Init.Mode=DMA_CIRCULAR;    //模式 :循环
		DMA_Handle.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD; //外设宽度
		DMA_Handle.Init.PeriphInc=DMA_MINC_DISABLE;    //外设地址是否自增
		DMA_Handle.Init.Priority=DMA_PRIORITY_MEDIUM;     //优先级
		
		//建立连接关系
		__HAL_LINKDMA(&TIM1_Handle,hdma[TIM_DMA_ID_CC2],DMA_Handle);

		HAL_DMA_Init(&DMA_Handle);
	}	
}

//TIM1跟新中断

void TIM1_UP_IRQHandler(void)
{
	 HAL_TIM_IRQHandler(&TIM1_Handle);
}

//MDA1的通道2中断

void DMA1_Channel3_IRQHandler(void)
{
		HAL_DMA_IRQHandler(&DMA_Handle);
		
}


//由于没有开启捕获中断,所以进入这个函数的是:2次转运完成
//也就是第二次按下
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance==TIM1)
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{

			
			shijian=tim1_dmabuff[1]-tim1_dmabuff[0];
		}		
	}
}

因为使用了DMA的连续读方式,所以开启DMA不能在使用单次模式,只能使用:

HAL_TIM_IC_Start()

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Arduino ESP32-C3板(ESP32-C3 DevKitM)有多个硬件定时器,可以用来生成精确定时的信号,例如PWM信号、定时采样等。在这里,我们将介绍如何在Arduino ESP32-C3板上使用硬件定时器来生成PWM信号。 步骤1:引入头文件 首先,需要在Arduino IDE中引入ESP32-C3的头文件,其中包含了定时器相关的函数和常量。 #include <esp32-hal-timer.h> 步骤2:配置定时器 在Arduino ESP32-C3板上,有四个硬件定时器可供使用,分别为TIMER0、TIMER1、TIMER2和TIMER3。在使用定时器之前,需要先进行配置。以下是一个示例代码段,用于配置TIMER0。 void initTimer0() { // 配置TIMER0为PWM模式 timerAttach(TIMER0, 0, true); timerSetMode(TIMER0, TIMER_PWM_MODE, 1); timerSetFrequency(TIMER0, 1000); timerSetDuty(TIMER0, 0, 50); // 开始TIMER0 timerAlarmEnable(TIMER0); } 在上述代码中,我们首先使用timerAttach()函数将TIMER0与GPIO0引脚绑定,然后使用timerSetMode()函数将其设置为PWM模式。接下来,使用timerSetFrequency()函数设置PWM频率为1000Hz,然后使用timerSetDuty()函数设置PWM占空比为50%。最后,使用timerAlarmEnable()函数启动TIMER0。 步骤3:控制PWM输出 完成定时器的配置后,可以使用timerWrite()函数来控制PWM输出。以下是一个示例代码段,用于控制TIMER0输出PWM信号。 void loop() { for (int i = 0; i <= 100; i++) { timerWrite(TIMER0, i); delay(10); } } 在上述代码中,我们使用一个for循环来逐步增加PWM占空比,从0到100。每次循环使用timerWrite()函数来设置PWM占空比,然后使用delay()函数延时10毫秒。 总结 在Arduino ESP32-C3板上使用硬件定时器可以生成精确的PWM信号,用于控制各种设备和传感器。在使用定时器时,需要注意配置定时器的模式、频率和占空比。同时,也需要注意控制PWM输出的时序,以保证信号的稳定性和准确性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值