STM32F103C8T6定时器的输出比较和输入捕获

1.输出比较

首先配置所需要输出PWM的频率,比如我需要输出频率为25KHz的PWM频率,选择定时器2

生成项目之后,可通过调用函数,产生设定的占空比波形,下面的代码说明可产生占空比为50的PWM波形。

__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1,50); 
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);

2.输入捕获

选用定时器3进行输入捕获,进行配置。

需要计算输入波形的高电平时间和低电平时间,可根据高低电平时间计算输入波形的频率。

//输入捕获中断
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_3);
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_4);

在main函数中开启中断。

定义保存数据的变量。

uint16_t ccr1_cnt = 0;                   /* 发生第一次下升沿捕获时CCR1的值 */
uint16_t ccr2_cnt = 0;					 /* 发生第二次上升沿捕获时CCR1的值 */
uint16_t Period_cnt = 0;				 /* 发生计数器溢出事件的次数(过渡用) */
uint16_t Period_cnt1 =0;				 /* 发生计数器溢出事件的次数--计数1 */
uint16_t Period_cnt2 = 0;				 /* 发生计数器溢出事件的次数--计数2 */
uint16_t ic_flag = 0;					 /* 输入捕获标志 */
uint16_t end_flag = 0;					 /* 捕获结束标志 */
float frequency = 0;				     /* 频率 */
float duty_cycle = 0;				     /* 占空比 */

uint16_t ccr1_cnt_CH3 = 0;                   /* 发生第一次下升沿捕获时CCR1的值 */
uint16_t ccr2_cnt_CH3 = 0;					 /* 发生第二次上升沿捕获时CCR1的值 */
uint16_t Period_cnt_CH3 = 0;				 /* 发生计数器溢出事件的次数(过渡用) */
uint16_t Period_cnt1_CH3 =0;				 /* 发生计数器溢出事件的次数--计数1 */
uint16_t Period_cnt2_CH3 = 0;				 /* 发生计数器溢出事件的次数--计数2 */
uint16_t ic_flag_CH3 = 0;					 /* 输入捕获标志 */
uint16_t end_flag_CH3 = 0;					 /* 捕获结束标志 */
float frequency_CH3 = 0;				     /* 频率 */
float duty_cycle_CH3 = 0;				     /* 占空比 */

uint16_t ccr1_cnt_CH4 = 0;                   /* 发生第一次下升沿捕获时CCR1的值 */
uint16_t ccr2_cnt_CH4 = 0;					 /* 发生第二次上升沿捕获时CCR1的值 */
uint16_t Period_cnt_CH4 = 0;				 /* 发生计数器溢出事件的次数(过渡用) */
uint16_t Period_cnt1_CH4 =0;				 /* 发生计数器溢出事件的次数--计数1 */
uint16_t Period_cnt2_CH4 = 0;				 /* 发生计数器溢出事件的次数--计数2 */
uint16_t ic_flag_CH4 = 0;					 /* 输入捕获标志 */
uint16_t end_flag_CH4 = 0;					 /* 捕获结束标志 */
float frequency_CH4 = 0;				     /* 频率 */
float duty_cycle_CH4 = 0;				     /* 占空比 */



void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{    /* 定时器计数溢出回调函数 */
	 if(htim==(&htim1))
	{
		FG_Count++;
	}
	else if(htim==(&htim3))
	{
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			Period_cnt ++;								            /* 定时器计数溢出时间次数 */
		}
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
		{
			Period_cnt_CH3 ++;								            /* 定时器计数溢出时间次数 */
		}
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
		{
			Period_cnt_CH4 ++;								            /* 定时器计数溢出时间次数 */
		}
	}
	
	
}




void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{	    /* 定时器输入捕获回调函数 */
	
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{		    /* 判断是不是通道1 */
			//printf("\nHAL_TIM_IC_CaptureCallback");
			if(end_flag == 0){							        /* 判断结束标志是不是0,在打印期间不进行捕获,防止打印时相关数值改变 */
				switch(ic_flag){							    /* 判断此时处于捕获的第几个阶段 */
					//printf("\nic_flag=%d",ic_flag);
					case 0:									    /* 阶段一:第一次捕获到上升沿 */
					{
						__HAL_TIM_SET_COUNTER(&htim3,0);	    /* 将定时器3计数设置为0 */
						ccr1_cnt = 0;							/* 将相关参数清0 */
						ccr2_cnt =0;
						Period_cnt = 0;
						Period_cnt1 = 0;
						Period_cnt2 = 0;
						__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);/* 设置成下降沿捕获 */
						ic_flag = 1;							/* 捕获设置为等待第二个阶段 */
						break;
					}
						case 1:									/* 阶段二:第一次捕获到下降沿 */
					{
						ccr1_cnt = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_1);/* 获取存放在CCR寄存器的值(捕获值CCR1) */
						Period_cnt1 = 	Period_cnt;				/* 获取计时器溢出次数1 */
						__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING); /* 设置成上升沿捕获 */
						ic_flag = 2;							/* 捕获设置等待为第三个阶段 */
						break;
						
					}
					case 2:										/* 阶段三:第二次捕获到上升沿 */
					{
						ccr2_cnt = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_1);/* 取存放在CCR寄存器的值(捕获值CCR2) */
						Period_cnt2 = Period_cnt;				/* 获取计时器溢出次数2 */
						ic_flag = 0;							/* 捕获设置等待为第一个阶段 */
						end_flag = 1;							/* 完成一次捕获,将标志置1 */
						break;
					}			
				}
			}
		}
		
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
		{		    /* 判断是不是通道3 */
			//printf("\nHAL_TIM_IC_CaptureCallback");
			if(end_flag_CH3 == 0){							        /* 判断结束标志是不是0,在打印期间不进行捕获,防止打印时相关数值改变 */
				switch(ic_flag_CH3){							    /* 判断此时处于捕获的第几个阶段 */
					//printf("\nic_flag=%d",ic_flag);
					case 0:									    /* 阶段一:第一次捕获到上升沿 */
					{
						__HAL_TIM_SET_COUNTER(&htim3,0);	    /* 将定时器3计数设置为0 */
						ccr1_cnt_CH3 = 0;							/* 将相关参数清0 */
						ccr2_cnt_CH3 =0;
						Period_cnt_CH3 = 0;
						Period_cnt1_CH3 = 0;
						Period_cnt2_CH3 = 0;
						__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_3,TIM_INPUTCHANNELPOLARITY_FALLING);/* 设置成下降沿捕获 */
						ic_flag_CH3 = 1;							/* 捕获设置为等待第二个阶段 */
						break;
					}
						case 1:									/* 阶段二:第一次捕获到下降沿 */
					{
						ccr1_cnt_CH3 = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_3);/* 获取存放在CCR寄存器的值(捕获值CCR1) */
						Period_cnt1_CH3 = 	Period_cnt_CH3;				/* 获取计时器溢出次数1 */
						__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_3,TIM_INPUTCHANNELPOLARITY_RISING); /* 设置成上升沿捕获 */
						ic_flag_CH3 = 2;							/* 捕获设置等待为第三个阶段 */
						break;
						
					}
					case 2:										/* 阶段三:第二次捕获到上升沿 */
					{
						ccr2_cnt_CH3 = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_3);/* 取存放在CCR寄存器的值(捕获值CCR2) */
						Period_cnt2_CH3 = Period_cnt_CH3;				/* 获取计时器溢出次数2 */
						ic_flag_CH3 = 0;							/* 捕获设置等待为第一个阶段 */
						end_flag_CH3 = 1;							/* 完成一次捕获,将标志置1 */
						break;
					}			
				}
			}
		}
		
		if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
		{		    /* 判断是不是通道4 */
			//printf("\nHAL_TIM_IC_CaptureCallback");
			if(end_flag_CH4 == 0){							        /* 判断结束标志是不是0,在打印期间不进行捕获,防止打印时相关数值改变 */
				switch(ic_flag_CH4){							    /* 判断此时处于捕获的第几个阶段 */
					//printf("\nic_flag=%d",ic_flag);
					case 0:									    /* 阶段一:第一次捕获到上升沿 */
					{
						__HAL_TIM_SET_COUNTER(&htim3,0);	    /* 将定时器3计数设置为0 */
						ccr1_cnt_CH4 = 0;							/* 将相关参数清0 */
						ccr2_cnt_CH4 =0;
						Period_cnt_CH4 = 0;
						Period_cnt1_CH4 = 0;
						Period_cnt2_CH4 = 0;
						__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_4,TIM_INPUTCHANNELPOLARITY_FALLING);/* 设置成下降沿捕获 */
						ic_flag_CH4 = 1;							/* 捕获设置为等待第二个阶段 */
						break;
					}
						case 1:									/* 阶段二:第一次捕获到下降沿 */
					{
						ccr1_cnt_CH4 = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_4);/* 获取存放在CCR寄存器的值(捕获值CCR1) */
						Period_cnt1_CH4 = 	Period_cnt_CH4;				/* 获取计时器溢出次数1 */
						__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_4,TIM_INPUTCHANNELPOLARITY_RISING); /* 设置成上升沿捕获 */
						ic_flag_CH4 = 2;							/* 捕获设置等待为第三个阶段 */
						break;
						
					}
					case 2:										/* 阶段三:第二次捕获到上升沿 */
					{
						ccr2_cnt_CH4 = __HAL_TIM_GET_COMPARE(&htim3,TIM_CHANNEL_4);/* 取存放在CCR寄存器的值(捕获值CCR2) */
						Period_cnt2_CH4 = Period_cnt_CH4;				/* 获取计时器溢出次数2 */
						ic_flag_CH4 = 0;							/* 捕获设置等待为第一个阶段 */
						end_flag_CH4 = 1;							/* 完成一次捕获,将标志置1 */
						break;
					}			
				}
			}
		}
}
//计算FG1转速
void FG1_Input(void)
{
	//USB_printf("FG1_Input\n");
	//计算风扇转速FG1
		if(end_flag)
		{				
			//Fan1ExistFlag=1;
			high=(float)(Period_cnt1 * 65536 + ccr1_cnt + 1);
			low=(float)((Period_cnt2 * 65536 + ccr2_cnt + 1)-(Period_cnt1 * 65536 + ccr1_cnt + 1));
			high1=(int)high;
			highMS=(float)high1/100;
			
			low1=(int)low;
			lowMS=(float)low1/100;
			
			T=(float)(2*(highMS+lowMS));
			speed=60000/T;
			speedShowLast=speedShow;
			speedShow=(int)speed;
			
			end_flag = 0;																										 /* 将捕获结束标志置0(准备下一次捕获) */
		}
}

#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "exti.h" #include "timer.h" #include "usart.h" #include "IWDG.h" //int main(void) //中断 //{ ////delay_init(); //LED_Init(); ////KEY_Init(); ////NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ////EXTIX_Init(); //LED=0; //while(1); //} //int main(void) //定时器中断 //{ // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // delay_init(); // LED_Init(); // // TIM3_Int_Init(1999,7199);//((1+7199)/72M)*(1+9999)=1秒*/反 // while(1); //} //int main(void) //pwm //{ // u16 ledpwmval=0; // u8 dir=1; // delay_init(); // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // uart_init(115200); // LED_Init (); // // TIM3_PWM_Init(199,7199);//50Hz // while(1) // { // delay_ms(10); // if(dir)ledpwmval++; // else ledpwmval --; // if(ledpwmval >1000) // dir=0; // if(ledpwmval ==0) // dir=1; // TIM_SetCompare2(TIM3,5); // delay_ms(500); // TIM_SetCompare2(TIM3,10); // delay_ms(500); // TIM_SetCompare2(TIM3,15); // delay_ms(500); // TIM_SetCompare2(TIM3,20); // delay_ms(500); // TIM_SetCompare2(TIM3,25); // delay_ms(500); // } //} //int main() //串口 //{ // u16 t; // u16 len; // u16 times=0; // delay_init(); // NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 ); // uart_init(115200); // LED_Init(); // KEY_Init(); // while(1) // { // if(USART_RX_STA&0x8000) // { // len=USART_RX_STA&0x3fff;//得到此次接收的数据长度 // printf("\r\n您发送的消息为:\r\n\r\n"); // for(t=0;t<len;t++) // { // USART_SendData(USART1,USART_RX_BUF[t]); // while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); // } // printf("\r\n\r\n");//插入换行 // USART_RX_STA=0; // } // else // { // times++; // if(times%500000==0) // { // LED=!LED; // } // } // } //} extern void TIM4_Cap_Init(u16 arr,u16 psc); extern u8 TIM4CH1_CAPTURE_STA; //输入捕获状态 输入捕获实验 extern u16 TIM4CH1_CAPTURE_VAL; //输入捕获值 int main(void) { u32 temp=0; delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(115200); //串口初始化为115200 LED_Init(); //LED端口初始化 // TIM3_PWM_Init(899,0); //不分频。PWM频率72000/(899+1)=80Khz TIM4_Cap_Init(0XFFFF,72-1); //以1Mhz的频率计数 while(1) { delay_ms(10); TIM_SetCompare2(TIM3,TIM_GetCapture2(TIM3)+1); if(TIM_GetCapture2(TIM3)==300) TIM_SetCompare2(TIM3,0); if(TIM4CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿 { temp=TIM4CH1_CAPTURE_STA&0X3F; temp*=65536; //溢出时间总 temp+=TIM4CH1_CAPTURE_VAL;//得到总的高电平时间 printf("HIGH:%d us\r\n",temp);//打印总的高点平时间 TIM4CH1_CAPTURE_STA=0;//开启下一次捕获 } } }
### STM32F103C8T6 PWM 输入捕获计算占空比 对于STM32F103C8T6来说,通过PWM输入捕获来测量信号频率占空比是一个常见的应用需求。下面提供了一个基于HAL库实现此功能的具体方法。 #### 初始化配置 首先,在`main.c`文件中初始化TIMx定时器用于捕捉外部PWM波形: ```c void MX_TIM2_Init(void) { TIM_HandleTypeDef htim2; __HAL_RCC_TIM2_CLK_ENABLE(); htim2.Instance = TIM2; htim2.Init.Prescaler = 79; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 65535; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_IC_Init(&htim2) != HAL_OK){ Error_Handler(); } } ``` 接着定义两个全局变量存储上升沿时间下降沿时间差值以便后续处理: ```c volatile uint32_t RisingEdgeTime, FallingEdgeTime; volatile float DutyCyclePercentage; ``` 为了获取更精确的结果,还需要设置回调函数以响应中断事件并更新这些计数值: ```c void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { static uint32_t PreviousRisingEdgeTime = 0; static uint32_t PeriodValue = 0; if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1IF)){ // 获取当前通道的捕获值 RisingEdgeTime = HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1); if(PreviousRisingEdgeTime!=0){ PeriodValue=RisingEdgeTime-PreviousRisingEdgeTime; if(RisingEdgeTime<PreviousRisingEdgeTime){ PeriodValue+=htim->Init.Period+1; } // 计算高电平持续的时间长度 FallingEdgeTime=PeriodValue-DutyCycleMeasurement_GetDutyCycle(); // 更新上一次记录到的上升沿时刻 PreviousRisingEdgeTime=RisingEdgeTime; // 调用自定义函数完成最终百分比转换 DutyCyclePercentage=(float)(DutyCycleMeasurement_GetDutyCycle()*100)/((float)PeriodValue); printf("Frequency:%luHz,Duty Cycle:%.2f%%\r\n",SystemCoreClock/PeriodValue,DutyCyclePercentage); }else { PreviousRisingEdgeTime=RisingEdgeTime; } } } // 自定义辅助函数返回实际测得的高低脉冲宽度之差作为占空比参数 uint32_t DutyCycleMeasurement_GetDutyCycle(){ return FallingEdgeTime; } ``` 上述代码片段展示了如何利用STM32CubeMX生成的基础框架配合HAL库APIs编写程序逻辑[^2]。注意这里假设已经完成了必要的硬件连接以及软件环境搭建工作,并且确保了正确的时钟源配置使得定时器能够正常运作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值