发新帖我要提问
12
返回列表
打印
[其他ST产品]

STM32F4_定时器输入捕获详解

[复制链接]
手机看帖
扫描二维码
随时随地手机跟帖
21
铁血丹心LLLL|  楼主 | 2023-10-28 19:15 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
ag.
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1映射到TI1上  
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获  
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上  
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频  
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波  
TIM_ICInit(TIM5, &TIM5_ICInitStructure);

使用特权

评论回复
22
铁血丹心LLLL|  楼主 | 2023-10-28 19:15 | 只看该作者
使能捕获和更新中断(设置TIM5的DIER寄存器)

TIM_ITConfig( TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断和捕获中断

此时开启中断,我们需要在中断中设置:因为此程序是捕获高电平信号的脉宽,所以第一次捕获的是上升沿,第二次是下降沿,这两个时间间隔内就是一个高电平信号。

同时脉宽比较长,就会导致定时器溢出,需要在中断中对溢出进行处理。

使用特权

评论回复
23
铁血丹心LLLL|  楼主 | 2023-10-28 19:16 | 只看该作者
5. 设置中断优先级,编写中断服务函数

NVIC_Init();

中断服务函数:需要完成数据处理和捕获设置等关键操作。    TIM5_IRQHandler

        在中断开始的时候需要进行中断类型的判断,中断结束时要清除中断标志位。

if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET){}//判断是否为更新中断

if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET){}//判断是否发生捕获事件

TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update);//清除中断和捕获标志位

TIM_SetCounter(TIM5,0); //设置计数器的值  将TIM5的计数值设置为0、

使用特权

评论回复
24
铁血丹心LLLL|  楼主 | 2023-10-28 19:16 | 只看该作者
6. 使能定时器

TIM_Cmd(TIM5,ENABLE ); //使能定时器5

最后因为用到了串口输出结果,所以还需要配置一下串口

使用特权

评论回复
25
铁血丹心LLLL|  楼主 | 2023-10-28 19:16 | 只看该作者
实验程序
本实验程序通过输入捕获TIM5_CH1(PA0)上面的高电平脉冲宽度,并从串口打印捕获结果。

注意:

        该程序中的TIM5CH1_CAPTURE_STA是一个状态位,前6位表示捕获高电平后定时器溢出的次数;第七位是捕获到高电平的标志;第八位是捕获完成的标志。TIM5CH1_CAPTURE_VAL用来记录捕获到下降沿时CNT计数器的值,因为该程序是捕获高电平脉冲宽度,每当捕获到下降沿的时候,就意味着捕获到了一个高电平脉冲信号。因为一个高电平是由一个上升沿和一个下降沿组成的。

使用特权

评论回复
26
铁血丹心LLLL|  楼主 | 2023-10-28 19:16 | 只看该作者
main.c
#include "stm32f4xx.h"
#include "delay.h"
#include "LED.h"
#include "BEEP.h"
#include "Key.h"
#include "usart.h"
#include "exti.h"
#include "iwdg.h"
#include "wwdg.h"
#include "Timer.h"
#include "pwm.h"
#include "IntputCapture.h"

extern u8 TIM5_CH1_CAPTURE_STA;//外部声明
//该程序中的TIM5CH1_CAPTURE_STA是一个状态位,前6位表示捕获高电平后定时器溢出的次数;第七位是捕获到高电平的标志;第八位是捕获完成的标志。
extern u32 TIM5_CH1_CAPTURE_VAL;
//TIM5CH1_CAPTURE_VAL用来记录捕获到下降沿时CNT计数器的值


int main(void)
{
        long long Temp=0; //Temp表示溢出的次数,对于溢出我们这样理解的,因为计数器的重装载值是固定设置的,如果频率过快,可能在一次高电平期间,会溢出多次,因此我们需要记录溢出的次数
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
        delay_init(168);
        uart_init(115200);
        TIM14_Init(500-1,84-1);
        TIM5_CH1_InterCapture_Init(0xFFFFFFFF,84-1); //自动重装载值为最大  84/84M=1M,频率为1Mhz
        while(1)
        {
                delay_ms(10);
                TIM_SetCompare1(TIM14,TIM_GetCapture1(TIM14)+1);//设置占空比,占空比是TIM14输出比较来的
                if(TIM_GetCapture1(TIM14)==300)//占空比达到顶峰
                        TIM_SetCompare1(TIM14,0);//清空TIM14定时器
                if(TIM5_CH1_CAPTURE_STA&0x80)//成功捕获一次高电平
                {
                        Temp=TIM5_CH1_CAPTURE_STA&0x3F;//低6位的值给到Temp  循环次数
                        Temp*=0xFFFFFFFF;  //溢出时间总和  循环次数乘以最大重装载值(最大重装载值就是一个周期的计数器值)就是循环这么多次的时间
                        Temp=Temp+TIM5_CH1_CAPTURE_VAL; //总的高电平时间 TIM5_CH1_CAPTURE_VAL表示最后一次检测到低电平时的计数器值
                        printf("HIGH:%lld us\r\n",Temp);//打印总的高电平时间
                        TIM5_CH1_CAPTURE_STA=0; //开启下一次捕获
                }
        }
       
}

使用特权

评论回复
27
铁血丹心LLLL|  楼主 | 2023-10-28 19:17 | 只看该作者
IntputCapture.c
#include "stm32f4xx.h"                  
#include "IntputCapture.h"

//AutomaticReload:自动重装载值    PrioritySendCount:时钟预分频数

void TIM14_Init(u32 AutomaticReload,u32 PrioritySendCount)
{
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);//使能TIM14_CH1 1通道时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);// 使能GPIOF引脚
        GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);//引脚复用PF9引脚复用为TIM14的通道1
        //GPIO的初始化函数,设置初始化的模式为复用
       
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //设置GPIO模式为复用  对应上述引脚复用PF9引脚复用为TIM14的通道1
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
        GPIO_Init(GPIOF,&GPIO_InitStructure);
       
        //初始化TIM14定时器,设置预分频值和自动重装载值
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
        TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数,也就是递增计数
        TIM_TimeBaseInitStructure.TIM_Period=AutomaticReload;//自动重装载值
        TIM_TimeBaseInitStructure.TIM_Prescaler=PrioritySendCount;//时钟预分频值
        TIM_TimeBaseInit(TIM14,&TIM_TimeBaseInitStructure);
       
       
        //设置TIM14的PWM模式
        TIM_OCInitTypeDef TIM_OCInitStructure;
        TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;//输出极性低,也就意味着占空比中低电平有效
        TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//PWM调质模式1
        TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出比较使能
        TIM_OCInitStructure.TIM_Pulse=0;
        TIM_OC1Init(TIM14,&TIM_OCInitStructure);//初始化TIM14通道1
       
        TIM_OC2PreloadConfig(TIM14,TIM_OCPreload_Enable);//使能TIM14在CCR2上的预装载寄存器
        TIM_ARRPreloadConfig(TIM14,ENABLE);//使能自动重装载寄存器
       
        TIM_Cmd(TIM14,ENABLE);//使能TIM14
}
//AutomationReload:自动重装值(TIM2,TIM5的自动重装载值是32位的)   PrioritySendCount:时钟预分频数

void TIM5_CH1_InterCapture_Init(u32 AutomationReload,u16 PrioritySendCount)
{
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//TIM5时钟使能
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能GPIOA
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5);//PA0复用为TIM5
       
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
        GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN; //引脚设置为下拉,因为PA0对应KEY_UP按键,KEY_UP按键左侧接V3.3
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);//GPIOA初始化
       
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
        TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
        TIM_TimeBaseInitStructure.TIM_Period=AutomationReload;
        TIM_TimeBaseInitStructure.TIM_Prescaler=PrioritySendCount;
        TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure);
       
        TIM_ICInitTypeDef TIM_ICInitStructure;
        TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//映射通道1上
        TIM_ICInitStructure.TIM_ICFilter=0x00;//不滤波
        TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
        TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//配置输入不分频
        TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TI1上,也就是TIM5通道1
        TIM_ICInit(TIM5,&TIM_ICInitStructure);//初始化TIM5输入捕获
       
        TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//使能捕获和更新中断
       
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;//TIM5通道
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能中断优先级
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级2
        NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//响应优先级0
        NVIC_Init(&NVIC_InitStructure);//初始化NVIC
       
        TIM_Cmd(TIM5,ENABLE);//使能定时器5
}
//捕获状态位
//位7:0 还没成功捕获  1  成功捕获到一次
//位6:0 还没有捕获到低电平  1  成功捕获到一次低电平
//位5:0  捕获低电平后溢出的次数,当达到最高的溢出次数时,标记成功捕获一次
//这里需要注意,之所以设置低电平捕获状态和溢出次数,是因为初始化TIM5的时候设置的是上升沿捕获,那么就意味着初始化时上升沿就会进行一次捕获,想要获得高电平的持续时间,就要在中断中获得捕获低电平时的计数器值

u8 TIM5_CH1_CAPTURE_STA=0;//定义全局变量输入捕获的状态
u32 TIM5_CH1_CAPTURE_VAL;//输入捕获的值(注意TIM2/TIM5的输入捕获值是32位的)

void TIM5_IRQHandler(void)//两种情况 一种是溢出次数也就是循环了多少次,另一种是发生捕获也就是最后一次的时间,两个相加才是总的时间
//这个也比较好理解,因为我们不确定在我们捕获的低电平是第一次低电平,还是第n次低电平;
//如果只是单纯的记录低电平的计数器值,可能要比实际的高电平时间要小很多,因为中间掺杂着多个周期,我们都没有记录在内
{
        if((TIM5_CH1_CAPTURE_STA&0x80)==0)//输入捕获状态位的最高位为0,还未成功捕获
        {
                if(TIM_GetITStatus(TIM5,TIM_IT_Update)!=RESET)//判断是否为更新中断,溢出
                {
                        if(TIM5_CH1_CAPTURE_STA&0x40)//已经捕获到高电平了
                        {
                                if((TIM5_CH1_CAPTURE_STA&0x3F)==0x3F)//低6位为1,表示溢出的次数达到了最高,默认标记成功捕获一次
                                {
                                        TIM5_CH1_CAPTURE_STA=TIM5_CH1_CAPTURE_STA|0X80;//状态位的最高位置1,表示已经成功捕获了一次
                                        TIM5_CH1_CAPTURE_VAL=0xFFFFFFFF;//捕获值达到最高
                                }
                                else   //不是因为溢出次数达到顶峰而标记捕获,则捕获状态++;
                                        TIM5_CH1_CAPTURE_STA++;
                        }
                }
                if(TIM_GetITStatus(TIM5,TIM_IT_CC1)!=RESET)//捕获1发生捕获事件
                {
                        if(TIM5_CH1_CAPTURE_STA&0x40)//捕获一个下降沿,一次捕获已经结束了,我需要做以下几件事:
                                //标记状态位的最高位为1,表明成功捕获一次,将捕获到的值给到全局变量VAL,
                        //因为要捕获高电平的频率,所以先设置上升沿捕获,在设置下降沿捕获,这样一来,一个上升沿一个下降沿就会得到一个完整的高电平频率
                        {
                                TIM5_CH1_CAPTURE_STA|=0x80;//状态最高位置1,表示成功捕获一次
                                TIM5_CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);//获取捕获值给到全局变量
                                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//设置上升沿捕获
                        }
                        else //否则意味着还没有捕获到下降沿
                        {
                                TIM5_CH1_CAPTURE_STA=0;//清空
                                TIM5_CH1_CAPTURE_VAL=0;
                                TIM5_CH1_CAPTURE_STA|=0x40;//标记捕获到了一个上升沿
                                TIM_Cmd(TIM5,ENABLE);//使能定时器5
                                TIM_SetCounter(TIM5,0);//将定时器5清空
                                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);//设置下降沿捕获
                                TIM_Cmd(TIM5,ENABLE);//使能定时器5
                        }
                }
        }
        TIM_ClearITPendingBit(TIM5,TIM_IT_CC1|TIM_IT_Update);//清除中断标志位
}

使用特权

评论回复
28
铁血丹心LLLL|  楼主 | 2023-10-28 19:17 | 只看该作者
IntputCapture.h
#ifndef _INTPUTCAPTURE__H_
#define _INTPUTCAPTURE__H_

void TIM14_Init(u32 AutomaticReload,u32 PrioritySendCount);
void TIM5_CH1_InterCapture_Init(u32 AutomationReload,u16 PrioritySendCount);
void TIM5_IRQHandler(void);

#endif

使用特权

评论回复
29
铁血丹心LLLL|  楼主 | 2023-10-28 19:17 | 只看该作者

使用特权

评论回复
30
童雨竹| | 2024-2-9 08:02 | 只看该作者

让PCB顶层和底层一样,将它们通过一些过孔(或通孔)连接

使用特权

评论回复
31
Wordsworth| | 2024-2-9 09:05 | 只看该作者

孔璧里头必须经过电镀

使用特权

评论回复
32
Clyde011| | 2024-2-9 10:08 | 只看该作者

需要将阻焊漆(阻焊油墨)覆盖在最外层的PCB设计布线上

使用特权

评论回复
33
公羊子丹| | 2024-2-9 11:01 | 只看该作者

电源中都有一个交流电压最大的节点

使用特权

评论回复
34
万图| | 2024-2-9 12:04 | 只看该作者

做多层板可将做好的两块双面板用特制的粘合剂“压合”起来

使用特权

评论回复
35
Uriah| | 2024-2-9 13:07 | 只看该作者

清除与电镀动作都会在化学过程中完成

使用特权

评论回复
36
帛灿灿| | 2024-2-9 15:03 | 只看该作者

将整个表面铺上一层薄薄的铜箔,并且把多余的部份给消除

使用特权

评论回复
37
Bblythe| | 2024-2-9 16:06 | 只看该作者

在开始电镀之前,必须先清掉孔内的杂物。

使用特权

评论回复
38
周半梅| | 2024-2-9 18:02 | 只看该作者

电容工作在额定的纹波电流下

使用特权

评论回复
39
Pulitzer| | 2024-2-9 19:05 | 只看该作者

在孔璧内部作金属处理后,可以让内部的各层线路能够彼此连接。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则