当前位置:首页 > 单片机 > 单片机
[导读]输入捕获作为定时器的一个功能,在工业测速上有很大的应用。STM32的一些定时器具有四个外部通道,可利用一个定时器采集外部四路脉冲频率,节约硬件资源和软件代码如需要测量一个或多个外部方波脉冲频率,频率低于单片

输入捕获作为定时器的一个功能,在工业测速上有很大的应用。STM32的一些定时器具有四个外部通道,可利用一个定时器采集外部四路脉冲频率,节约硬件资源和软件代码

如需要测量一个或多个外部方波脉冲频率,频率低于单片机运行频率,可如下操作:(以TIM4为例)

初始化:(省略GPIO配置,将TIM4的四个通道引脚配置为上拉或浮空输入,省略定时器RCC配置,省略中断NVIC配置)

void TIM_Configuration(void)

{

TIM_ICInitTypeDef TIM_ICInitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; // TIM4 时基

TIM_DeInit(TIM4);

TIM_TimeBaseStructure.TIM_Period =0xffff;//自动重装值

TIM_TimeBaseStructure.TIM_Prescaler =719;//预分频值, 使TIMx_CLK=1MHz

TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;//输入时钟不分频

TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//向上计数

TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);//TIM4_TimeBase

// TIM_ICInitStructure.TIM_ICMode =TIM_ICMode_ICAP; //输入捕捉方式

TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//|TIM_Channel_2; //输入通道

TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising; //捕捉上升沿

TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //捕捉中断

TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1; //捕捉不分频

TIM_ICInitStructure.TIM_ICFilter =0x0; //捕捉输入不滤波

TIM_ICInit(TIM4, &TIM_ICInitStructure);

TIM_ICInitStructure.TIM_Channel = TIM_Channel_2 ;//|TIM_Channel_2; //输入通道

TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising; //捕捉上升沿

TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //捕捉中断

TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1; //捕捉不分频

TIM_ICInitStructure.TIM_ICFilter =0x0; //捕捉输入不滤波

TIM_ICInit(TIM4, &TIM_ICInitStructure);

TIM_ICInitStructure.TIM_Channel = TIM_Channel_3 ;//|TIM_Channel_2; //输入通道

TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising; //捕捉上升沿

TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //捕捉中断

TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1; //捕捉不分频

TIM_ICInitStructure.TIM_ICFilter =0x0; //捕捉输入不滤波

TIM_ICInit(TIM4, &TIM_ICInitStructure);

TIM_ICInitStructure.TIM_Channel = TIM_Channel_4 ;//|TIM_Channel_2; //输入通道

TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising; //捕捉上升沿

TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI; //捕捉中断

TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1; //捕捉不分频

TIM_ICInitStructure.TIM_ICFilter =0x0; //捕捉输入不滤波

TIM_ICInit(TIM4, &TIM_ICInitStructure);

TIM_Cmd(TIM4, ENABLE);

TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);

TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);

TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE);

TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);

}

其中:

TIM_TimeBaseStructure.TIM_Period = 0xffff;为自动重装值,与普通单片机一样

TIM_TimeBaseStructure.TIM_Prescaler = 719; 预分频值, 使TIMx_CLK=100KHz ,系统时钟运行于72M时720分频,定时器运行于100KHZ,即10us每分度

TIM_ICInitStructure.TIM_ICMode = TIM_ICMode_ICAP; 此句选择定时器为输入捕获模式,但在我的库函数下未定义,所以注释掉,未影响程序执行

TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;配置通道1

TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;上升沿捕获

TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;捕获中断

TIM_ICInitStructure.TIM_ICFilter = 0x0;不滤波

TIM_ICInit(TIM4, &TIM_ICInitStructure);将配置应用

以上每个通道都需要将整个配置再写一遍,使用与'|'是无效的。

TIM_Cmd(TIM4, ENABLE);使能定时器4

TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);

TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);

TIM_ITConfig(TIM4, TIM_IT_CC3, ENABLE);

TIM_ITConfig(TIM4, TIM_IT_CC4, ENABLE);打开四个通道的捕获中断

以上将TIM配置完成,下面是中断内代码:

void

TIM4_IRQHandler(void)

{

//频率缓冲区计数

static u16 this_time_CH1 = 0;

static u16 last_time_CH1 = 0;

static u8 capture_number_CH1 = 0;

vu16 tmp16_CH1;

static u16 this_time_CH2 = 0;

static u16 last_time_CH2 = 0;

static u8 capture_number_CH2 = 0;

vu16 tmp16_CH2;

static u16 this_time_CH3 = 0;

static u16 last_time_CH3 = 0;

static u8 capture_number_CH3 = 0;

vu16 tmp16_CH3;

static u16 this_time_CH4 = 0;

static u16 last_time_CH4 = 0;

static u8 capture_number_CH4 = 0;

vu16 tmp16_CH4;

if(TIM_GetITStatus(TIM4, TIM_IT_CC1) == SET)

{

TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);

if(capture_number_CH1 == 0)

{

capture_number_CH1 = 1;

last_time_CH1 = TIM_GetCapture1(TIM4);

}

else if(capture_number_CH1 == 1)

{

capture_number_CH1 = 0;

this_time_CH1 = TIM_GetCapture1(TIM4);

if(this_time_CH1 > last_time_CH1)

{

tmp16_CH1 = (this_time_CH1 - last_time_CH1);

}

else

{

tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1);

}

//TIM2 counter clock = 1MHz

//

FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100为扩大显示量程

Freq_Value[0]=tmp16_CH1;

}

}

if(TIM_GetITStatus(TIM4, TIM_IT_CC2) == SET)

{

TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);

if(capture_number_CH2 == 0)

{

capture_number_CH2 = 1;

last_time_CH2 = TIM_GetCapture2(TIM4);

}

else if(capture_number_CH2 == 1)

{

capture_number_CH2 = 0;

this_time_CH2 = TIM_GetCapture2(TIM4);

if(this_time_CH2 > last_time_CH2)

{

tmp16_CH2 = (this_time_CH2 - last_time_CH2);

}

else

{

tmp16_CH2 = ((0xFFFF - last_time_CH2) + this_time_CH2);

}

//TIM2 counter clock = 1MHz

//

FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100为扩大显示量程

Freq_Value[1]=tmp16_CH2;

}

}

if(TIM_GetITStatus(TIM4, TIM_IT_CC3) == SET)

{

TIM_ClearITPendingBit(TIM4, TIM_IT_CC3);

if(capture_number_CH3 == 0)

{

capture_number_CH3 = 1;

last_time_CH3 = TIM_GetCapture3(TIM4);

}

else if(capture_number_CH3 == 1)

{

capture_number_CH3 = 0;

this_time_CH3 = TIM_GetCapture3(TIM4);

if(this_time_CH3 > last_time_CH3)

{

tmp16_CH3 = (this_time_CH3 - last_time_CH3);

}

else

{

tmp16_CH3 = ((0xFFFF - last_time_CH3) + this_time_CH3);

}

//TIM2 counter clock = 1MHz //

FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100为扩大显示量程

Freq_Value[2]=tmp16_CH3;

}

}

if(TIM_GetITStatus(TIM4, TIM_IT_CC4) == SET)

{

TIM_ClearITPendingBit(TIM4, TIM_IT_CC4);

if(capture_number_CH4 == 0)

{

capture_number_CH4 = 1;

last_time_CH4 = TIM_GetCapture4(TIM4);

}

else if(capture_number_CH4 == 1)

{

capture_number_CH4 = 0;

this_time_CH4 = TIM_GetCapture4(TIM4);

if(this_time_CH4 > last_time_CH4)

{

tmp16_CH4 = (this_time_CH4 - last_time_CH4);

}

else

{

tmp16_CH4 = ((0xFFFF - last_time_CH4) + this_time_CH4);

}

//TIM2 counter clock = 1MHz //

FreqBuf[cnt] = (1000000L * 100) / tmp16; //*100为扩大显示量程

Freq_Value[3]=tmp16_CH4;

}

}//

GPIO_WriteBit(GPIOC, GPIO_Pin_13,(BitAction)((1-GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13))));

}

中断内四部分代码完全一样,只分析其中一段输入捕获的原理是,

定时器正常计数运行,当外部脉冲到来时,将定时器计数值存起来,当下次脉冲到来时,求出这两次计数值差值,即为这两段脉冲的周期。

例如,

定时器计数到10,外部脉冲到来,使用last_time_CH1存储10,

下次脉冲到来,此时定时器计数值运行到110,使用this_time_CH1存储110,

之后做差,tmp16_CH1存储差值100,由于定时器运行于100KHZ,10us计数值增加一次,所以脉冲周期为100*10=1000us=1ms,即为1KHZ。

当然,定时器会溢出重装,此时需要将差值补偿运算,tmp16_CH1 = ((0xFFFF - last_time_CH1) + this_time_CH1);

可测量的范围取决于定时器运行的频率,如果外部频率慢到当定时器整个计数一周后也没有触发两次,会发生溢出,此时计数值已不准确。

所以定时器时钟配置取决于外部脉冲频率,应配置得当使得脉冲频率范围不致溢出。

由于每次外部脉冲都会触发中断,尤其是四通道时,所以使用中断方式会略微占用CPU资源,使用DMA可以解决这一问题。

得到脉冲周期后,即可通过运算获得外部频率,进而测速。


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

在嵌入式开发中,STM32的时钟系统因其灵活性和复杂性成为开发者关注的焦点。然而,看似简单的时钟配置背后,隐藏着诸多易被忽视的陷阱,轻则导致系统不稳定,重则引发硬件损坏。本文从时钟源选择、PLL配置、总线时钟分配等关键环...

关键字: STM32 时钟系统

在嵌入式系统开发中,STM32系列微控制器的内部温度传感器因其低成本、高集成度特性,广泛应用于设备自检、环境监测等场景。然而,受芯片工艺差异和电源噪声影响,其原始数据存在±1.5℃的固有误差。本文从硬件配置、校准算法、软...

关键字: STM32 温度传感器

在能源效率与智能化需求双重驱动下,AC-DC转换器的数字控制技术正经历从传统模拟方案向全数字架构的深刻变革。基于STM32微控制器的PFM(脉冲频率调制)+PWM(脉冲宽度调制)混合调制策略,结合动态电压调整(Dynam...

关键字: AC-DC STM32

当前智能家居产品需求不断增长 ,在这一背景下 ,对现有浇花装置缺陷进行了改进 ,设计出基于STM32单片机的全 自动家用浇花机器人。该设计主要由机械结构和控制系统构成 ,机械结构通过麦克纳姆轮底盘与喷洒装置的结合实现机器...

关键字: STM32 麦克纳姆轮 安全可靠 通过性强

用c++编程似乎是让你的Arduino项目起步的障碍吗?您想要一种更直观的微控制器编程方式吗?那你需要了解一下Visuino!这个图形化编程平台将复杂电子项目的创建变成了拖动和连接块的简单任务。在本文中,我们将带您完成使...

关键字: Visuino Arduino ESP32 STM32

基于STM32与LoRa技术的无线传感网络凭借其低功耗、广覆盖、抗干扰等特性,成为环境监测、工业自动化等场景的核心解决方案。然而,如何在复杂电磁环境中实现高效休眠调度与动态信道优化,成为提升网络能效与可靠性的关键挑战。本...

关键字: STM32 LoRa

在实时控制系统、高速通信协议处理及高精度数据采集等对时间敏感的应用场景中,中断响应延迟的优化直接决定了系统的可靠性与性能上限。STM32系列微控制器凭借其灵活的嵌套向量中断控制器(NVIC)、多通道直接内存访问(DMA)...

关键字: STM32 DMA

数字电源技术向高功率密度、高效率与高动态响应方向加速演进,STM32微控制器凭借其基于DSP库的算法加速能力与对LLC谐振变换器的精准控制架构,成为优化电源动态性能的核心平台。相较于传统模拟控制或通用型数字控制器,STM...

关键字: STM32 数字电源

STM32微控制器凭借其针对电机控制场景的深度优化,成为高精度、高可靠性驱动系统的核心选择。相较于通用型MCU,STM32在电机控制领域的核心优势集中体现在FOC(磁场定向控制)算法的硬件加速引擎与PWM死区时间的动态补...

关键字: STM32 电机控制

无线充电技术加速渗透消费电子与汽车电子领域,基于Qi协议的无线充电发射端开发成为智能设备能量补给的核心课题。传统模拟控制方案存在响应滞后、参数调整困难等问题,而基于STM32的数字PID控制结合FOD(Foreign O...

关键字: STM32 无线充电
关闭