标题:
stm32系列定时器输入捕获检测高、低脉冲时长的方法 附源程序
[打印本页]
作者:
不知廉耻
时间:
2019-7-16 10:47
标题:
stm32系列定时器输入捕获检测高、低脉冲时长的方法 附源程序
大家好,本人在校老菜鸡一个,最近抽空接手了一个项目,其中一个关键点在于“通过输入捕获检测任意引脚、任意顺序高低电平的持续时间”。
咱们直入主题,stm32的具有丰富的外设资源,小编选择用stm32f1系列单片机作为核心控制器,来完成这个项目。
方案有两种:
方案一:采用中断,例如外部引脚中断等,直接在检测到指定电平时,发生跳变进入中断函数,然后进行计时。
方案二:采用定时器输入捕获,在上升沿、下降沿时发生跳变,然后进行计时。
优缺点分析:方案一实行难度较小,但是需要引脚资源较多(一个检测高电平,一个检测低电平),时间精度稍微弱一点。
方案二拥有现成的历程,直接调用即可,通过定时器输入捕获模式,中断里进行计数。
看似使用方案二是最佳的选择,但是,如果这样的话,小编就不用写这篇博客了
.
至于方案一、小弟也还没有尝试过,不清楚具体效果如何。
背景介绍(大牛不喜勿喷)
输入捕获模式:输入捕获模式可以用来测量脉冲宽度或者测量频率,Stm32定时器除了定时器6和定时器7,其他定时器都有输入捕获功能,简单来说,就是在边沿信号发生跳变的时候(上升沿、下降沿),将当前定时器的值存放到对应通道的捕获/比寄存器中,完成一次捕获,同时,可以再配置捕获到相应跳变时,是否触发中断/DMA等等。
一、测量高电平脉冲宽度:采用正点原子的代码思路。先将引脚设定为下拉输入,然后设置输入捕获为“上升沿触发”,将当前定时器中的时间存储起来,然后再中断里将触发方式设置为“下降沿触发”,再记录一下触发时间,二者相减,即可得出高电平持续时间。
二、测量低电平脉冲宽度:与测量高电平脉冲宽度正好相反,不过应该如何设置呢?小编找了很久,也没有答案,所以只能自己动手,丰衣足食咯。
先看检测高电平脉冲的代码:
//定时器2中断服务程序
void TIM2_IRQHandler(void)
{
if((TIM2CH1_CAPTURE_STA&0X80)==0)// 这里采用了两个变量作为临时判断条件,这两个变量最初值都为0
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//如果是发生了中断,那么向下执行
{
if(TIM2CH1_CAPTURE_STA&0X40)//如果已经捕获到高电平那么就进一步执行程序。
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//
{
TIM2CH1_CAPTURE_STA|=0X80;/
TIM2CH1_CAPTURE_VAL=0XFFFF;
}else TIM2CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//
{
if(TIM2CH1_CAPTURE_STA&0X40) /
{
TIM2CH1_CAPTURE_STA|=0X80; /
TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); /
}else //
{
TIM2CH1_CAPTURE_STA=0;
TIM2CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM2,0);
TIM2CH1_CAPTURE_STA|=0X40; //
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //
}
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); /
}//////(小小吐槽一下,网站上传图片功能个人感觉有点鸡肋。这一段很重要,必须要认真去揣摩TIM2CH1_CAPTURE_STA的赋值关系。不要做拿来主义,这样只能是拔苗助长,得不偿失。)
通过两个变量的“与”、“赋值”等操作,对高电平进行不同的操作。在输入捕获通道中,设置为上升沿触发。过来一个上升沿,进入中断,检查是否标记位被赋值,如果没有,代表是是第一次检测到高电平,记录当前定时器的值,然后设置为下降沿........
测量低电平脉冲时长的代码:简述一下思路,就是同样定义两个变量,按照上述代码的格式,照猫画虎一次,几乎没有大的改变。
具体情况,请在代码文件中进行查看。
备注:有一个语句 TIM_SetCounter(TIM2,0);具体作用我在代码中也有标注,时间所限,就不再多说了,一切尽在代码中。有空再来补全相关内容。
单片机源程序如下:
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "stm32f10x.h"
#include "usart1.1.h"
#include "oled.h"
#include "timer.h"
//MPU6050
//串口1发送1个字符
//c:要发送的字符
float x,y=0;
u8 xy[20];//用于接收坐标?
u8 len;
u16 led0pwmval=1;
int main(void)
{
int i=0;
u8 t;
u16 times=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
delay_init(); //延时函数初始化
usart_init(19200); //串口初始化为9600
OLED_Init();
LED_Init();
TIM2_Cap_Init(0XFFFF,7199); //以1Mhz的频率计数 0XFFFF----1111 1111 1111 1111(2进制)//10khz计数频率,每计数一下是1ms
TIM1_PWM_Init(9999,7199);//1MHZ频率输出。
TIM3_PWM_Init(9999,7199);//10kHZ技术频率。
while(1)
{
//OLED_show();
//show1_all();这两个暂时取消
//delay_ms(300);不清楚会造成什么样的后果
TIM_SetCompare3(TIM3,led0pwmval);
TIM_SetCompare4(TIM3,led0pwmval);
// TIM_SetCompare4(TIM1,led0pwmval);
if(USART_RX_STA&0x8000)//判断接收数组的最高位是否为一,本次接收是否完成
{
len=USART_RX_STA&0x3fff;//取出u16中的低16 位,得到此次接收到的数据长度
USART_RX_STA=0;//对数组清零,方便下一次接收
}
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)==0)
{
delay_ms(1000);
LED=0;
printf("1");
}
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)==0)
{
delay_ms(1000);
LED=1;
printf("2");
}
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)==0)
{
delay_ms(1000);
printf("3");
}
convey();
}
}
复制代码
目前代码还存在很多问题,求大神指导如何修改:
交替检测高低电平.7z
(215.35 KB, 下载次数: 149)
2019-7-16 16:55 上传
点击文件名下载附件
作者:
尤晓權
时间:
2020-3-27 09:50
楼主这个程序是用定时器2的两个输入捕获通道,一个配置成检测高电平脉冲,一个检测低电平脉冲。但是两个通道接到一路PWM信号输入点?
作者:
夜尽天明22
时间:
2020-6-6 21:15
都是捕获高电平的
作者:
星jy辰
时间:
2020-8-14 20:15
夜尽天明22 发表于 2020-6-6 21:15
都是捕获高电平的
误导别人
作者:
星jy辰
时间:
2020-8-14 20:15
夜尽天明22 发表于 2020-6-6 21:15
都是捕获高电平的
他这个代码简直在搞笑吧
作者:
lophost
时间:
2022-1-7 17:05
太扯了,完全不对题
作者:
wliuxiaoxiaow
时间:
2023-8-6 11:49
这个程序能用吗
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1