0、风扇知识补充
1. 风扇测速接法
2. 测转速逻辑
从上图中可以看出:风扇转1圈是由2个完整的PWM组成,且高脉冲占比50%
如果要测试转速,可以测出PWM的平均周期,再计算出 转每分钟的数值。
1、功能描述
需要采集多路风扇转速,使用STM32F103单片机,单片机TIM2、TIM3、TIM4这三个定时器各有4通道输入捕获功能,共计12路,TIM1用来做普通的定时器。
2、各定时器配置
TIM1 定时1ms(完全可以时间长一些,只是本项目中有其他用处)
其他三个定时器配置数输入捕获,上升沿/下降沿触发都行,因为采集风扇转速没必要采集每个脉冲宽度,只需要知道周期即可。本程序采用新的策略:在25ms内数测速引脚的脉冲个数,进而求出风扇转速。
void TIM1_CONFIG(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* Time base configuration */
TIM_DeInit(TIM1);
TIM_TimeBaseStructure.TIM_Period = 1000-1; //计数值为1000,定时器1ms
TIM_TimeBaseStructure.TIM_Prescaler = 72-1; //预分频为1M,此时T1的时钟为1M
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; //重复计数设置
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM1,TIM_FLAG_Update);
TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);
/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);
}
void TIM2_IC_CONFIG(void) //FanSpeed 5-8
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //此 TIM2,TIM3是APB1的外设
//2、配置GPIO
//3、配置时基单元
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure);
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65535 - 1; //ARR周期,给最大值,防止溢出,16位计数器可以满量程计数
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; // 100KHz PSC预分频器,这个值决定测周法的标准频率fc,72M/预分频 = 1Mhz,就是计数器自增的频率,就是计数标准频率
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //把以上参数配置为TIM3的时基单元
//4、初始化输入捕获单元
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0x08; //用于选择输入捕获的滤波器
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //对应边沿检测极性选择这一部分
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //此处不分频,不分频就是每次触发都有效,2分频就是每个一次有效一次,以此类推
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //此处选择直连通道,配置数据选择器,可以选择直连通道或者交叉通道
TIM_ICInit(TIM2,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM2,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_3;
TIM_ICInit(TIM2,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_4;
TIM_ICInit(TIM2,&TIM_ICInitStruct);
TIM_ClearFlag(TIM2,TIM_FLAG_Update|TIM_FLAG_CC1|TIM_FLAG_CC2|TIM_FLAG_CC3|TIM_FLAG_CC4);
TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4 ,ENABLE);//允许更新中(计数器溢出计数中断),允许CC1IE捕获中断
//最后一步
TIM_Cmd(TIM2,ENABLE);
}
void TIM3_IC_CONFIG(void) //FanSpeed 9-12
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //此 TIM3,TIM3是APB1的外设
//2、配置GPIO
//3、配置时基单元
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure);
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65535 - 1; //ARR周期,给最大值,防止溢出,16位计数器可以满量程计数
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; // 100KHz PSC预分频器,这个值决定测周法的标准频率fc,72M/预分频 = 1Mhz,就是计数器自增的频率,就是计数标准频率
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //把以上参数配置为TIM3的时基单元
//4、初始化输入捕获单元
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0x08; //用于选择输入捕获的滤波器
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //对应边沿检测极性选择这一部分
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //此处不分频,不分频就是每次触发都有效,2分频就是每个一次有效一次,以此类推
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //此处选择直连通道,配置数据选择器,可以选择直连通道或者交叉通道
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_3;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_4;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ClearFlag(TIM3,TIM_FLAG_Update|TIM_FLAG_CC1|TIM_FLAG_CC2|TIM_FLAG_CC3|TIM_FLAG_CC4);
TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4 ,ENABLE);//允许更新中(计数器溢出计数中断),允许CC1IE捕获中断
//最后一步
TIM_Cmd(TIM3,ENABLE);
}
void TIM4_IC_CONFIG(void) //Speed 1-4
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_ICInitTypeDef TIM_ICInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //此 TIM4,TIM4是APB1的外设
//2、配置GPIO
//3、配置时基单元
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure);
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInitStructure.TIM_Period = 65535 - 1; //ARR周期,给最大值,防止溢出,16位计数器可以满量程计数
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; // 100KHz PSC预分频器,这个值决定测周法的标准频率fc,72M/预分频 = 1Mhz,就是计数器自增的频率,就是计数标准频率
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure); //把以上参数配置为TIM4的时基单元
//4、初始化输入捕获单元
TIM_ICInitStruct.TIM_Channel = TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter = 0x08; //用于选择输入捕获的滤波器
TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; //对应边沿检测极性选择这一部分
TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; //此处不分频,不分频就是每次触发都有效,2分频就是每个一次有效一次,以此类推
TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; //此处选择直连通道,配置数据选择器,可以选择直连通道或者交叉通道
TIM_ICInit(TIM4,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;
TIM_ICInit(TIM4,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_3;
TIM_ICInit(TIM4,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel = TIM_Channel_4;
TIM_ICInit(TIM4,&TIM_ICInitStruct);
TIM_ClearFlag(TIM4,TIM_FLAG_Update|TIM_FLAG_CC1|TIM_FLAG_CC2|TIM_FLAG_CC3|TIM_FLAG_CC4);
TIM_ITConfig(TIM4,TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4 ,ENABLE);//允许更新中(计数器溢出计数中断),允许CC1IE捕获中断
//最后一步
TIM_Cmd(TIM4,ENABLE);
}
/*******************************************************************************
* Function Name : TIM1_IRQHandler TIM2中断
* Description : This function handles TIM2 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM1_UP_IRQHandler(void)
{
u8 i;
if(TIM_GetITStatus(TIM1,TIM_IT_Update)!=RESET) //1ms 中断 1次
{
TIM_ClearITPendingBit(TIM1,TIM_IT_Update);
//------------------------------------
Sample_timer++;
if(Sample_timer>=25) //每隔25ms进行速度转换
{
Sample_timer = 0;
Sample_Press_s = 1;
}
//------------------------------------
}
}
/*******************************************************************************
* Function Name : TIM2_IRQHandler TIM2中断
* Description : This function handles TIM2 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM2_IRQHandler(void)
{
u8 N;
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET) //实测655.xx ms
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除更新中断标志位
FANS_Time_OVEERcnt[T2_C1]++; //对应的此定时器相关的 溢出计数器 全部+1
FANS_Time_OVEERcnt[T2_C2]++;
FANS_Time_OVEERcnt[T2_C3]++;
FANS_Time_OVEERcnt[T2_C4]++;
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1); //清除中断标志位
N = T2_C1;
FANS_Curr_CCR_Val[N] =TIM_GetCapture1(TIM2); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//捕获2发生捕获事件
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2); //清除中断标志位
N = T2_C2;
FANS_Curr_CCR_Val[N] =TIM_GetCapture2(TIM2); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)//捕获3发生捕获事件
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3); //清除中断标志位
N = T2_C3;
FANS_Curr_CCR_Val[N] =TIM_GetCapture3(TIM2); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)//捕获4发生捕获事件
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中断标志位
N = T2_C4;
FANS_Curr_CCR_Val[N] =TIM_GetCapture4(TIM2); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
}
/*******************************************************************************
* Function Name : TIM3_IRQHandler
* Description : This function handles TIM3 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM3_IRQHandler(void)
{ u8 N;
if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET) //实测655.xx ms
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除更新中断标志位
FANS_Time_OVEERcnt[T3_C1]++; //对应的此定时器相关的 溢出计数器 全部+1
FANS_Time_OVEERcnt[T3_C2]++;
FANS_Time_OVEERcnt[T3_C3]++;
FANS_Time_OVEERcnt[T3_C4]++;
}
if(TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); //清除中断标志位
N = T3_C1;
FANS_Curr_CCR_Val[N] =TIM_GetCapture1(TIM3); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)//捕获2发生捕获事件
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2); //清除中断标志位
N = T3_C2;
FANS_Curr_CCR_Val[N] =TIM_GetCapture2(TIM3); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)//捕获3发生捕获事件
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC3); //清除中断标志位
N = T3_C3;
FANS_Curr_CCR_Val[N] =TIM_GetCapture3(TIM3); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET)//捕获4发生捕获事件
{
TIM_ClearITPendingBit(TIM3, TIM_IT_CC4); //清除中断标志位
N = T3_C4;
FANS_Curr_CCR_Val[N] =TIM_GetCapture4(TIM3); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
}
/*******************************************************************************
* Function Name : TIM4_IRQHandler 1ms
* Description : This function handles TIM4 global interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void TIM4_IRQHandler(void)
{
u8 N;
if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET) //实测655.xx ms
{
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//清除更新中断标志位
FANS_Time_OVEERcnt[T4_C1]++; //对应的此定时器相关的 溢出计数器 全部+1
FANS_Time_OVEERcnt[T4_C2]++;
FANS_Time_OVEERcnt[T4_C3]++;
FANS_Time_OVEERcnt[T4_C4]++;
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1); //清除中断标志位
N = T4_C1;
FANS_Curr_CCR_Val[N] =TIM_GetCapture1(TIM4); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET)//捕获2发生捕获事件
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC2); //清除中断标志位
N = T4_C2;
FANS_Curr_CCR_Val[N] =TIM_GetCapture2(TIM4); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC3) != RESET)//捕获3发生捕获事件
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC3); //清除中断标志位
N = T4_C3;
FANS_Curr_CCR_Val[N] =TIM_GetCapture3(TIM4); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
if(TIM_GetITStatus(TIM4, TIM_IT_CC4) != RESET)//捕获4发生捕获事件
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC4); //清除中断标志位
N = T4_C4;
FANS_Curr_CCR_Val[N] =TIM_GetCapture4(TIM4); //读取当前值
FANS_Period_Val[N] = (FANS_Curr_CCR_Val[N] + (u32)FANS_Time_OVEERcnt[N]*65535-FANS_Last_CCR_Val[N]+5)/10+FANS_Period_Val[N]*9/10;
FANS_Last_CCR_Val[N] = FANS_Curr_CCR_Val[N];
FANS_Time_OVEERcnt[N] = 0;
}
}
3、主函数中速度转换
u16 FAN_Speed_RD(u8 tempch) //·çÉÈתËÙ¶ÁÈ¡
{
u16 tempspd;
u32 temp=6000000;
if(tempch>=Sensor_CH_NUM)
{return 0;}
if(FANS_Period_Val[tempch]==0)
{
tempspd = 0;
}
else
{
temp = temp/2; //һתÓÐÁ½¸öÂö³å
tempspd = temp/FANS_Period_Val[tempch];
}
return tempspd;
}
void main(void)
{
if(Sample_Press_s==1) //25ms 转速重新计算
{
Sample_Press_s = 0;
for(ii=0;ii<Sensor_CH_NUM;ii++)
{
if(FANS_Time_OVEERcnt[ii]>=5) //655ms*5 约3s 超时速度清0处理
{
FANS_Time_OVEERcnt[ii]=5;
FANS_Period_Val[ii] = 0;
FANS_Last_CCR_Val[ii]= 0;
FANS_Curr_CCR_Val[ii]=0;
FANS_Speed_Val[ii] = 0;
}
else
{FANS_Speed_Val[ii] = FAN_Speed_RD(ii);} //风扇转速计算
}
}
}