1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 使用STM32测量PWM方波频率和占空比的方法

使用STM32测量PWM方波频率和占空比的方法

时间:2022-11-08 10:16:33

相关推荐

使用STM32测量PWM方波频率和占空比的方法

简介

使用STM32中TIMER的输入捕获功能可以测量PWM方波的频率和占空比。测量通常有两种方法:中断法和DMA传输法。根据我的经验,中断法最多能测量到150KHz的方波,而DMA方法最多可达1MHz(注:在这种极限状态下,信号占空比太大也容易测量失败)。下面就分别介绍这两种方法。

1. 使用STM32CubeMX生成代码

首先是选用TIMER,TIMER必须要选用两个相邻通道,并且一个是Input Capture Direct Mode,另一个是Input Capture Indirect Mode。在这种模式下,STM32将两个通道同时连接到同一个外部GPIO端口上。然后将TIMER的加载值设置成最大值,并将前一个通道设置成上升沿触发,后一个设置成下降沿触发。最后打开中断和DMA,DMA要设置成循环模式。最后根据个人硬件配置情况设置好后,生成代码就可以了。(注:以下用例选择的是TIME15的通道1和通道2。)

2. 中断方法测量

注意:尽管上面配置中使能了DMA,但使用中断测量方法没有用到DMA。

首先需要在main.c中定义全局变量:

#define COUNT_MAX8static volatile uint16_t risingCount[COUNT_MAX];static volatile uint16_t fallingCount[COUNT_MAX];static volatile uint16_t offset, number;

然后在main()函数中的无限循环的前面加入TIMER的启动语句:

HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_1);HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_2);

再在无限循环中加入测量结果的打印语句:

if (number >= 2){uint16_t index1 = (offset - 2) & (COUNT_MAX - 1);uint16_t index2 = (index1 + 1) & (COUNT_MAX - 1);uint16_t width = fallingCount[index1] - risingCount[index1];uint16_t period = risingCount[index2] - risingCount[index1];printf("W:%u P:%u\r\n", width, period); /* W是脉冲宽度,P是方波周期 */number = 1;}

打印出的测量结果值单位是TIMER的计数,需要根据TIMER的时钟频率折算成时间单位。这里省略。

最后加入中断采样函数:

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){if (htim->Instance == TIM15 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){risingCount[offset] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); /* 上升沿的时间戳采样 */}if (htim->Instance == TIM15 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2){fallingCount[offset] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); /* 下降沿的时间戳采样 */offset = (offset + 1) & (COUNT_MAX - 1);number++;}}

由于中断处理需要时间,这种测量方法仅对频率在150KHz以下的方波有效。

3. DMA方法测量

DMA方法不同于上面的中断方法,所以程序需要重新写。也首先需要在main.c中定义全局变量:

#define DMA_LEN16static uint16_t dmaBuff[DMA_LEN] __attribute__(( aligned(32)));static uint16_t dmaReady;

然后在main()函数中的无限循环的前面加入启动TIMER和DMA的语句:

HAL_TIM_DMABurst_MultiReadStart(&htim15, TIM_DMABASE_CCR1, TIM_DMA_CC1, (uint32_t *)dmaBuff, TIM_DMABURSTLENGTH_2TRANSFERS, DMA_LEN);TIM_CCxChannelCmd(htim15.Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE); /* HAL库函数内可能没有启动TIMER,这里补上 */TIM_CCxChannelCmd(htim15.Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);__HAL_TIM_ENABLE(&htim15);

这是启动TIMER的Burst读模式。在这一模式下TIMER可以一次DMA请求传输多个寄存器的值。这里我们需要读出通道1和通道2两个寄存器的时间戳值,DMA请求由通道1触发。

有些STM32处理器的HAL库没有提供这个Burst读模式的API,可以用下面的替代函数:

void TIM_DMABurst_MultiReadStart(TIM_HandleTypeDef *htim, uint32_t BurstBaseAddress, uint32_t BurstRequestSrc,uint32_t *BurstBuffer, uint32_t BurstLength, uint32_t BufferLength){/* Set the DMA capture callbacks */htim->hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TIM_DMACaptureCplt;htim->hdma[TIM_DMA_ID_CC1]->XferHalfCpltCallback = TIM_DMACaptureHalfCplt;/* Set the DMA error callback */htim->hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TIM_DMAError ;/* Enable the DMA channel */HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)&htim->Instance->DMAR, (uint32_t)BurstBuffer, BufferLength);/* configure the DMA Burst Mode */htim->Instance->DCR = (BurstBaseAddress | BurstLength);/* Enable the TIM DMA Request */__HAL_TIM_ENABLE_DMA(htim, BurstRequestSrc);TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_2, TIM_CCx_ENABLE);TIM_CCxChannelCmd(htim->Instance, TIM_CHANNEL_1, TIM_CCx_ENABLE);__HAL_TIM_ENABLE(htim);htim->State = HAL_TIM_STATE_READY;}

再在无限循环中加入测量结果的打印语句:

if (dmaReady){uint16_t offset = (DMA_LEN - ((DMA_Stream_TypeDef *)htim15.hdma[TIM_DMA_ID_CC1]->Instance)->NDTR) & (DMA_LEN - 1);uint16_t index1 = (offset - 4) & (DMA_LEN - 1);uint16_t index2 = (index1 + 2) & (DMA_LEN - 1);uint16_t period = dmaBuff[index2] - dmaBuff[index1];uint16_t width = period + dmaBuff[index1 + 1] - dmaBuff[index1];if (width < period) printf("W:%u P:%u\r\n", width, period);dmaReady = 0;}

注:这里直接使用了DMA的计数寄存器NDTR。STM32处理器不同其名称可能也不同,比如也许是CNDTR。请查阅自己处理器的手册修改成正确名称。

最后加入DMA中断函数:

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){if (htim->Instance == TIM15){dmaReady = 1;}}

由于DMA中断是在每次BUFFER满时才触发,所以对采样速率影响很小。

4. 结束语

以上仅是展示测量的基本方法,如要使其工作完善还需要一些更为细致的处理,这里就不涉及了。两种测量中都使用了双通道的测量方法。其实单通道也可以使用中断测量。但这需要在中断中加入触发沿的切换,可想而知其对测量速率会产生影响。好处仅是少占用了一个TIMER通道。

另外使用DMA的测量方法需要STM32微处理器支持Burst模式。我不确定有哪些STM32支持或不支持此功能,你需要查阅手册确认其TIMER支持此功能才可以使用。

5.备注

请参考使用DMA测量方法的具体实例。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。