这次在初步熟悉了TI板子的使用之后,我就开始学习输入捕获了(23年C题)
关于输入捕获,我想说说我今天学习之后的理解。
通过测量高低电平,来实现测量数据。
高低电平:上升沿、下降沿(这个可以通过直接配置,不用在自己写函数来判断)
测量数据:频率、占空比
开始讲讲理论部分:
第一遍观看了江科大的教程:[6-5] TIM输入捕获_哔哩哔哩_bilibili
这个时候我大概知道了测量频率的实现有三种方法:测周法、测频法、测中法
测周法:通过规定时间内(1s),计数上升沿的个数来计算频率(f = 1/n)(高频适用)
测频法:用标准频率计数俩个上升沿之间的计数个数,以此来计算周期(低频适用)
测中法:通过上述的公式来计算这个高低频的中间划分值应该是多少。
还有就是对单片机内部处理输入捕获的信息的处理流程,有了一个大概的了解。
第二遍再看视频,我才对这些有一个入门的了解。
(这里再次提醒自己要多看官方原理图)
我就我学了一天的来说说我的理解:
对输入的信号进行处理(滤波:边沿跳变),然后判定是高低电平作为触发条件,结束后面的频率计数周期。将计数值进行处理,就可以得到频率了。
(这下发现自己对这个还是没理解很懂,再去多看看)
至于其中的细节,这个就要在写代码中来细讲了。
代码部分:
思路是:用通用定时器(TIM5)的频率( 72M/(pre+1)/(arr+1))来对外接入的信号进行输入捕获处理,在中断(高低电平触发都可以 )中处理数据(标志位,计数值)
GPIO:
这里我开启的是TIM5时钟的CH2和CH3,查看硬件分布图知道是PA2和PA3。
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructure; //引脚输入方波
//配置输入引脚:PA2 PA3
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //开启时钟
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD; //上拉输入
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_2; //这里查询硬件分布:PA2-TIM5-CH3
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // PA3-TIM5_CH4
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化结构体
配置定时器TIM5:
定时器的基本配置:开启时钟、向上计数、时钟clockdivision=1、prescaler = 72-1(这里是用1MHz比较好算)、arr设定为ffff(因为不知道会计数多少个)
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //这里使用测周法来测量频率
//配置定时器5
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //开启时钟
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStructure); //这个我也不知道
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //不分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数处理
TIM_TimeBaseInitStructure.TIM_Period=arr; //计数重新转载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //预分频系数
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure); //初始化定时器5
输入捕获的配置:
因为我这次是用来计算俩个正弦波的相位差(经过运放化成方波处理),我就开启了俩个通道
选择通道:CH2 CH3(因为我最初借鉴的代码是这样的配置的,我就直接照着来了)
滤波处理:这个值可以根据自己实际电路的噪声来处理,0~f。我这里就直接拉满了。
极性触发:我都选择上升沿触发,就是直接选择测量高电平的所占频率(这里选择低电平ok的)
precalser:这个我不是太懂,我就理解到视频中说的:这个就看你几次高电平触发一次采集,选择1分频就是单次采集就触发、选择2就是两次高电平才触发
Selection:这个就是生效时间,这个不追求细节就是直接就好了。
TIM_ICInitStructure.TIM_Channel=TIM_Channel_4; //通道4
TIM_ICInitStructure.TIM_ICFilter=0xf; //最大滤除噪声模式
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising; //上升沿触发
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //单次触发
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//立刻生效
TIM_ICInit(TIM5,&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_3;
TIM_ICInitStructure.TIM_ICFilter=0xf;
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM5,&TIM_ICInitStructure);
中断NVIC的配置:
这个我觉得比较重要的是,下面config中的几个参数要记住:
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC4|TIM_IT_CC3,ENABLE); //开启中断
这里要记得把CC4和CC3一起算进去就好了。(这个我也不是太懂)
中断服务助手:
这里说说通道3的处理就好了(因为通道4就是类似的),直接上代码
if((TIM5CH4_Cap_State&0x80)==0) //第一路信号未捕获到下降沿
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET)
{
if(TIM5CH4_Cap_State&0x40) //第一路信号已捕获到上升沿
{
if((TIM5CH4_Cap_State&0x3f)==0x3f) //第一路信号上升沿到下降沿时间过长,捕获失败
{
TIM5CH4_Cap_State|=0x80;
TIM5CH4_Cap_Value=0xffff;
}
else
TIM5CH4_Cap_State++;
}
}
if(TIM_GetITStatus(TIM5,TIM_IT_CC4) == SET) //捕获中断
{
if(TIM5CH4_Cap_State & 0x40) //第一路信号已经捕获到上升沿,则此次为下降沿被捕获
{
TIM5CH4_Cap_State|=0x80; //标志一次检测完成
TIM5CH4_Cap_Value=TIM_GetCapture4(TIM5); //取出定时器的值
TIM_OC4PolarityConfig(TIM5,TIM_ICPolarity_Rising); //设置为上升沿捕获
}
else //第一路未捕获到上升沿,则此次为上升沿被捕获
{
TIM5CH4_Cap_State=0;
TIM5CH4_Cap_Value=0;
TIM_SetCounter(TIM5,0);
TIM5CH4_Cap_State|=0X40; //标记捕获到上升沿
TIM_OC4PolarityConfig(TIM5,TIM_ICPolarity_Falling); //设置为下降沿捕获
}
}
}
重点关注:标志位和计数值就好了
首先就是判断是不是检测到上升沿,检测到了就给一个标志位,设定为下降沿检测。(这个进入中断服务助手是通过检测到上升沿来触发的)
然后就是循环判断是不是满足下降沿的触发,是的话就赋值跳出中断。
(这里说的比较简单,可以好好看看)
这个标志位的设定和串口传输数据的中断服务助手好像,这个可以学习一下标志位的设定进入不同的if中
主函数:
// if(TIM5CH4_Cap_State&0X80) //成功捕获到了一次上升沿
// {
// temp = TIM5CH4_Cap_State&0X3F;
// temp *= 65536;//溢出时间总和
// temp += TIM5CH4_Cap_Value;//得到总的高电平时间
// printf("HIGH111:%d us\r\n",temp);//打印总的高点平时间
// TIM5CH4_Cap_State=0;//开启下一次捕获
// }
// if(TIM5CH3_Cap_State&0X80)//成功捕获到了一次上升沿
// {
// temp=TIM5CH3_Cap_State&0X3F;
// temp*=65536;//溢出时间总和
// temp+=TIM5CH3_Cap_Value;//得到总的高电平时间
// printf("HIGH222:%d us\r\n",temp);//打印总的高点平时间
// TIM5CH3_Cap_State=0;//开启下一次捕获
// }
这个就是输出计数的数值,没什么好讲的。
总结:
代码的理解还是有待提升,中间很多细节我发现我还是不懂。
下次碰到要学习的知识点,可以先找找有没有教学视频之类的和相关的例程代码,然后看一遍自己取折腾一下;再带着问题去第二遍视频,这个中间自己不懂得细节有哪些?第三遍开始就可以试着建立起自己的理解和整体的思路。
要看原理图!!!一手的数据手册!!!