完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
前言
之前拿外部中断做了一个频率计,范围到了1MHz,但是精确度并不是很高,误差在%0.5左右(看了一下那些大佬的频率计,基本上都是25MHz的量程范围,误差也是远低于%0.5)。 再结合外部中断的知识,发现除非采用matlab进行数据拟合(应该就是每一个频率节点都进行数据的校对),不然精度是无法提高的,而且对于一块STM32F103单片机而言,将时钟频率配置到最大的72MHz,1MHz的频率也应该是外部中断的极限了,所以我决定再用输入捕获的方法尝试一下。 原理 定时器的输入捕获的功能就是检测上升沿或者下降沿之间的时间间隔(这是我自己的理解可能有点不太严谨),然后就是根据定时器的配置的具体的理解: 第一个框是预装载值,第二个是满载值 这样的话 这个定时器的频率就是 单片机的频率(我这里配置的是72MHz)/预装载值+1 就是1MHz 那每次定时的周期就是1us,言下之意就是如果如果说检测的频率高于1MHz,就靠这样的配置是远远不够的。(而且输入捕获其实也是十分的消耗 cpu的资源的,他也和外部中断一样要不断的进入中断,对于一个100khHz的信号,1s就要进入中断100k次,这样就意味着,不光单片机无法实现其他的功能,而且中断的回调函数也必须十分精简不然会有相当大的误差)。 我的想法是:先检测信号的上升沿,当上升沿到来之后再将输入捕获改变成下降沿捕获,再进行数据处理得到相关的数据。 HAL库输入捕获相关的函数 __HAL_TIM_SET_COUNTER( 定时器地址 , 设置的数值 ); 我用的是定时器2,然后用这个函数执行定时器2的计数值清零的操作,所以我是这样用的: __HAL_TIM_SET_COUNTER(&htim2, 0); TIM2_SetCapturePolarity(捕获触发模式); 我这个函数来改变输入捕获的模式(上升沿模式和下降沿模式) TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_RISING); // 设置为上升沿触发 TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_FALLING); // 设置为下降沿触发 HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) 这个是读取当时的数值,也比较的通俗易懂我这里就不详细介绍了。 代码部分 void TIM2_Poll(void) { switch (TIM2_CAPTURE_STA) { case 0: { TIM2_TIMEOUT_COUNT = 0; __HAL_TIM_SET_COUNTER(&htim2, 0); // 清除定时器2现有计数 memset(TIM2_CAPTURE_BUF, 0, sizeof(TIM2_CAPTURE_BUF)); // 清除捕获计数 TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_RISING); // 设置为上升沿触发 HAL_TIM_Base_Start_IT(&htim2); // 启动定时器更新中断 HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); // 启动捕获中断 TIM2_CAPTURE_STA++; break; } case 4: { double high = TIM2_CAPTURE_BUF[1] - TIM2_CAPTURE_BUF[0]; double cycle = TIM2_CAPTURE_BUF[2] - TIM2_CAPTURE_BUF[0]; float frq = 1.0 / (((float)cycle) / 1000000.0); TIM2_CAPTURE_STA++; printf("高电平持续时间 %.3f msrn", high / 1000); //printf("周期 : %. msrn", cycle / 1000.0); printf("频率 %.3f Hzrn", frq); TIM2_CAPTURE_STA=0; break; } default: break; } } /// 定时器2时间溢出回调函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == htim2.Instance) { TIM2_TIMEOUT_COUNT++; // 溢出次数计数 } } ///< 输入捕获回调函数 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == htim2.Instance) { switch (TIM2_CAPTURE_STA) { case 1: { TIM2_CAPTURE_BUF[0] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) + TIM2_TIMEOUT_COUNT * 0xFFFF; TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_FALLING); // 设置为下降沿触发 TIM2_CAPTURE_STA++; break; } case 2: { TIM2_CAPTURE_BUF[1] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) + TIM2_TIMEOUT_COUNT * 0xFFFF; TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_RISING); // 设置为上升沿触发 TIM2_CAPTURE_STA++; break; } case 3: { TIM2_CAPTURE_BUF[2] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) + TIM2_TIMEOUT_COUNT * 0xFFFF; HAL_TIM_IC_Stop_IT(htim, TIM_CHANNEL_1); // 停止捕获 HAL_TIM_Base_Stop_IT(&htim2); // 停止定时器更新中断 TIM2_CAPTURE_STA++; break; } default: break; } } } 结合函数的说明,这个还是挺好理解的。(重点还是对定时器那预装载值和满载值的理解) 问题 现在串口的输出过于频繁了(本来可以再用一个定时器中断来实现的,但是外部中断那一章节也用的是这个方法,我这次就没用了,之后会用dma来实现,这个更加合理)。 频率精度很高,但是测量范围只有50kHz(看了一些文章,好像输入捕获也可以到1MHz,还在分析是什么原因。。。) |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1867浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
650浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
518浏览 3评论
537浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
506浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 00:20 , Processed in 0.676784 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号