蓝桥杯嵌入式开发经验分享(11.输入捕获模式讲解)

作者:马一飞                                                         QQ:791729359       

    

        我们的stm32不仅可以使用输出比较产生PWM波,也可以捕获PWM波,那么这个功能就叫做输入捕获。在蓝桥杯的比赛中,这个功能也是经常会考到的,赛题会让你捕获一个方波,并测出占空比和频率

        

        如果大家想详细了解这个捕获的过程,可以看看数据手册通用定时器章节的比较/捕获部分。

实际上捕获/比较都是用到了一个捕获/比较寄存器来进行作用的。那么接下来就从代码的层面看看如何把一个定时器配置成捕获模式。

        在学习捕获之前,首先把输出比较部分掌握好,我们捕获部分直接从上一个文档的输出比较代码进行增加。

        我们用了TIM2来做了比较输出PWM,那么我们捕获就用TIM3,那么TIM3对应的就是PA6、PA7引脚

。分别能够复用成TIM3的通道1、TIM3的通道2 。

 

1. 我们先使能TIM3,和PA引脚的时钟。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

2. 我们把PA6、PA7设置为上拉输入(或者浮空输入)。

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

3. 使能TIM3中断(在捕获方波的过程中必定有跳边沿的变化,因此我们需要在中断中去处理)。

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

4. 配置TIM3。

TIM_TimeBaseInitStructure.TIM_Period = 0xffff;
TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseInitStructure.TIM_CounterMode = 0x0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);

跟比较模式一样,我们把计数值设置到最大,同时71分频。

5. 配置输入通道。

TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
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(TIM3, &TIM_ICInitStructure);

我们要使用到这个库函数

void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

这个函数的原型可以在TIM库函数里面找到。

TIM_Channel是选择的通道

TIM_ICSelsction 我们必须选择指向TI寄存器

TIM_Polarity 代表触发方式,我们要选择选择上升沿触发,因为我们在初始化之后,我们要从采集到上升沿,开始计数

不需要分频,也不需要滤波。

同样通道2的配置也是一样的。

TIM_ICInitStructure.TIM_Channel = 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(TIM3, &TIM_ICInitStructure);

6.使能定时器和中断

TIM_Cmd(TIM3, ENABLE);
TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2, ENABLE);

因为我们使用到了通道1与通道2,因此他的比较值分别保存在CCR1寄存器和CCR2寄存器上。

那么我们初始化好捕获模式后,在中断函数中我们应该如何对数据进行捕获呢和计算占空比和频率呢?

这个过程需要大家去理解一下,我这里给大家画一个捕获的简图。

 

图中紫色部分为我们输入的方波信号,首先我们刚开始时要把捕获通道设置为上升沿触发,假如我们捕获到了一个上升沿,也就是到达了A点,那么我们的定时器就开始计数,随后我们还要吧捕获通道设置成为下降沿触发。当我们捕获了一个下降沿时,也就是到达了B点,那么我们获取一个计数值,定时器还得继续计数,同时重新把捕获通道设置为上升沿触发。直到再次捕获到了一个上升沿,那么就代表已经到达C点了,我们再获取一次计数值。

那么我们通过获取的这两个计数值,就很容易的算出周期和占空比。

占空比 = 第一次捕获值 / 第二次捕获值

周期   = 1000000 / 第二次捕获值

那么这个过程在程序里面到底如何设计呢?我们先用通道1来举例子,通道2的配置是一模一样的。

我们先定义三个变量。

u8 TIM3_CH1_CAPTURE_MODE = 0;
u32 TIM3_CH1_CAPTURE_H = 0;
u32 TIM3_CH1_CAPTURE_HL = 0;

TIM3_CH1_CAPTURE_MODE 用来记录当前捕获在哪个位置

TIM3_CH1_CAPTURE_H 用来记录第一次捕获的时间

TIM3_CH1_CAPTURE_HL 用来记录第二次捕获的时间

那么我们再中断里是这么处理的

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3, TIM_IT_CC1) == 1)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
		if(CAPTURE_MODE)
	    {
			switch(TIM3_CH1_CAPTURE_MODE)
			{
				case 0: TIM3_CH1_CAPTURE_H = 0;
				        TIM3_CH1_CAPTURE_HL = 0;
				        TIM3_CH1_CAPTURE_MODE = 1;
				        TIM_SetCounter(TIM3, 0);//计数值清0
				        TIM_OC1PolarityConfig( TIM3,TIM_ICPolarity_Falling);//下降沿触发
				        break;
			    case 1: TIM3_CH1_CAPTURE_H = TIM_GetCounter(TIM3);//第一次计数值
						TIM3_CH1_CAPTURE_MODE = 2;
						TIM_OC1PolarityConfig( TIM3,TIM_ICPolarity_Rising);//上升沿触发
						break;
				case 2: TIM3_CH1_CAPTURE_HL = TIM_GetCounter(TIM3);//第二次获取计数值
						TIM3_CH1_CAPTURE_MODE = 3;
						TIM_OC1PolarityConfig( TIM3,TIM_ICPolarity_Rising);//上升沿触发
						break;
				default:break;
											 
			}
	}else
	{
		TIM3_CH1_CAPTURE_MODE = 0;
	}
}

CAPTURE_MODE 大家可以先不用看,这个标志位的作用是为了防止两个捕获通道互不干扰,相当于一个分时复用的效果,大致的意义就是,通道1进行捕获的时候,通道2不能作用;通道2捕获时,通道1不能作用。如果大家有更好的方法,可以私聊我一起来讨论讨论喔。

当我们TIM3_CH1_CAPTURE_MODE=0时,如果发生了中断,那么就代表我们捕获到了上升沿,当前在上面简图的A点,我们把定时器计数值清0,让定时器重新计数,同时还要把触发方式设置为下降沿触发。

当TIM3_CH1_CAPTURE_MODE=1时候,发生了中断,那么就代表我们捕获到了下降沿,当前的位置在上面简图的B点,我们获取一次定时器的计数值,同时还得把我们触发方式设置为上升沿触发。

当TIM3_CH1_CAPTURE_MODE=2时候,发生中断,那么就代表我们一个周期已经捕获完毕了,当前位置在上面简图的C点,我们再获取一次定时器的计数值,随后就可以根据我们两次获取的计数值,算出我们方波的频率和周期。

当TIM3_CH1_CAPTURE_MODE=3时,就意味着我们可以开始计算周期和频率,当我们处理好数据后,我们就可以把TIM3_CH1_CAPTURE_MODE清0,准备开始下一次捕获。

那么我们在主函数中就是计算出周期和频率的值,然后显示到LCD上。随后开启下一次捕获。

if(TIM3_CH1_CAPTURE_MODE == 3)
{
	sprintf((char*)string,"ch1_fre:%d       ",1000000 / TIM3_CH1_CAPTURE_HL);
	LCD_DisplayStringLine(Line3, string);
	sprintf((char*)string,"ch1_duty:%d      ",TIM3_CH1_CAPTURE_H * 100/TIM3_CH1_CAPTURE_HL);
	LCD_DisplayStringLine(Line4, string);
	TIM3_CH1_CAPTURE_MODE = 0;
}

接下来我们把程序烧录到CT117E开发板看看效果到底是怎样的。

我们把PA1与PA6相接,PA2与PA7相接,我们使PA1产生1KHZ,40%占空比的方波;PA2产生5KHZ,80占空比的方波。

        我们也能看到,捕获计算出的频率和占空比,与我们产生的PWM是完全一致的,那么就代表我们这个捕获程序是完全没有问题的。

        也许你还有更好的方法与改进,欢迎一起讨论。

                                                                                                                                                                              (以上仅属于个人观点)

  • 20
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fei...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值