Stm32 第三十四讲:输入捕获实验


输入捕获实验

定时器框图

输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32的定时器,除了TIM6和TIM7,其他定时器都有输入捕获功能。

输入捕获工作过程

输入捕获

输入捕获

一句话总结工作过程:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升沿/下降沿)的时候,将当前定时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器(TIMx_CCRx)里面,完成一次捕获。

(以通道一为例)

步骤一:设置输入捕获滤波器

设置输入捕获滤波器

步骤二:设置输入捕获极性

设置输入捕获极性

步骤三:设置输入捕获映射通道

设置输入捕获映射通道

步骤四:设置输入捕获分频器

设置输入捕获分频器

步骤五:捕获到有效信号可以开启中断

捕获到有效信号可以开启中断

定时器通道

对应引脚TIM5为例:

TIM5通道1、2引脚

输入捕获相关寄存器

捕获/比较模式寄存器TIMx_CCMR1/2

TIMx_CCMR1

当在输入捕捉模式下使用的时候,对应上图的第二行描述。 低八位[7:0]用于捕获/比较通道1的控制,而高八位[15:8]则用于捕获/比较通道2的控制,由此也可以知道TIMx_CCMR2寄存器是用来控制通道3和4的。

TIMx_CCMR1的[7:0]位的详细描述如下:

CCMR1_低八位

捕获/比较使能寄存器TIMx_CCER

TIMx_CCER

CCER_最低2位

要使能输入捕获,必须设置CC1E=1,而CC1P则根据自己的需要来配置。

DMA/中断使能寄存器TIMx_DIER

TIMx_DIER

本文中需要用到中断来处理捕获数据,所以必须开启通道1的捕获比较中断,即CC1IE设置为1,此外更新中断也需要开启,UIE设置为1。

控制寄存器1 TIMx_CR1

最低位,使能寄存器。

状态寄存器TIMx_SR

TIMx_SR

输入捕获相关库函数

输入捕获通道初始化函数

void TIM_ICInit(TIM_TypeDef TIMx, TIM_ICInitTypeDef TIM_ICInitStruct);

typedef struct
{
uint16_t TIM_Channel; //捕获通道1~4
uint16_t TIM_ICPolarity;  //捕获极性
uint16_t TIM_ICSelection;  //映射关系
uint16_t TIM_ICPrescaler;  //分频系数
uint16_t TIM_ICFilter; //滤波器
} TIM_ICInitTypeDef;

示例:

TIM_ICInitTypeDef* TIM_ICInitStructure;
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=0x00;
TIM_ICInit(TIM5,&TIM5_ICInitStructure);

通道极性设置独立函数

void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

获取通道捕获值

uint32_t TIM_GetCapture1(TIM_TypeDef* TIMx);

输入捕获的一般配置步骤

①. 初始化定时器和通道对应IO的时钟。
②. 初始化IO口,模式为输入:GPIO_Init();

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//PA0输入

③. 初始化定时器ARR,PSC

TIM_TimeBaseInit();

④. 初始化输入捕获通道

TIM_ICInit();

⑤. 如果要开启捕获中断

TIM_ITConfig();
NVIC_Init();

⑥. 使能定时器

TIM_Cmd();

⑦. 编写中断服务函数

TIMx_IRQHandler();

输入捕获实验

实验目的

测量信号的脉冲宽度。

脉冲

TIM5CH1_CAPTURE_STA

by库函数

TIM5_CAP_Init()

//定时器5通道1输入捕获配置
void TIM5_CAP_Init(u16 arr, u16 psc)
{
    //定义结构体
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitSturc;
    TIM_ICInitTypeDef TIM_ICInitStructure;
    NVIC_InitTypeDef NVIC_InitStucture;    

    //使能时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);//使能定时器5时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PA时钟

    //GPIOA.0初始化
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//PA.0上拉输入
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//PA.0
    GPIO_Init(GPIOA,&GPIO_InitStructure);//GPIOA.0初始化
    GPIO_ResetBits(GPIOA,GPIO_Pin_0);//将PA.0初始化为低电平

    //TIM5定时器初始化
    TIM_TimeBaseInitSturc.TIM_Period=arr;//重装载值
    TIM_TimeBaseInitSturc.TIM_Prescaler=psc;//预分频系数
    TIM_TimeBaseInitSturc.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
    TIM_TimeBaseInitSturc.TIM_ClockDivision=TIM_CKD_DIV1;//时钟分频因子为1
    TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitSturc);    

    //初始化TIM5输入捕获参数
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//选择输入端IC1映射到TT1上
    TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//上升沿捕获
    TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;//映射到TT1上
    TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//配置输入分频,不分频
    TIM_ICInitStructure.TIM_ICFilter=0x00;//配置输入滤波器,不滤波
    TIM_ICInit(TIM5,&TIM_ICInitStructure);

    //中断分组初始化
    NVIC_InitStucture.NVIC_IRQChannel=TIM5_IRQn;//TIM5中断通道
    NVIC_InitStucture.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级2
    NVIC_InitStucture.NVIC_IRQChannelSubPriority=2;//响应优先级2
    NVIC_InitStucture.NVIC_IRQChannelCmd=ENABLE;//中断使能
    NVIC_Init(&NVIC_InitStucture);

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

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

TIM5_IRQHandler()

u8  TIM5CH1_CAPTURE_STA=0;    //输入捕获状态                            
u16    TIM5CH1_CAPTURE_VAL;    //输入捕获值

void TIM5_IRQHandler(void)
{
    if((TIM5CH1_CAPTURE_STA&0x80)==0)
    {
        if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET)
        {
            if(TIM5CH1_CAPTURE_STA&0x40)//已经捕获到了高电平
            {
                if((TIM5CH1_CAPTURE_STA&0x3f)==0x3f)//不是等于1,此代表高电平时间太长
                {
                    TIM5CH1_CAPTURE_STA|=0x80;//标记成功捕获了一次
                    TIM5CH1_CAPTURE_VAL=0xffff;
                }else TIM5CH1_CAPTURE_STA++;//捕获次数加一
            }
        }
        if(TIM_GetITStatus(TIM5,TIM_IT_CC1)==SET)
        {
            if(TIM5CH1_CAPTURE_STA&0x40)//已经捕获到了上升沿,此为捕获下降沿
            {
                TIM5CH1_CAPTURE_STA|=0x80;//标记成功捕获到一次高电平脉宽
                TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);//获取TIM5当前计数值
                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);//设置为捕获上升沿
            }else//还未开始时,捕获上升沿
            {
                TIM5CH1_CAPTURE_STA=0;    
                TIM5CH1_CAPTURE_VAL=0;
                TIM_SetCounter(TIM5,0);//TIM5从0开始计数
                TIM5CH1_CAPTURE_STA|=0x40;//标记捕获了上升沿
                TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);//设置为捕获下降沿
            }
        }
    }
    TIM_ClearITPendingBit(TIM5,TIM_IT_Update|TIM_IT_CC1);//清除更新和捕获中断标志位
}

main.c

#include "stm32f10x.h"
#include "timer.h"
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "usart.h"

extern u8 TIM5CH1_CAPTURE_STA;//输入捕获状态
extern u16 TIM5CH1_CAPTURE_VAL;//输入捕获值

int main(void)
{
    u32 temp=0;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC中断优先级分组
    delay_init();//延时函数初始化
    LED_Init();//LED初始化函数
    uart_init(115200);//串口初始化
    TIM5_CAP_Init(0xffff,72-1);//以1MHz的频率计数
    while(1)
    {
        if(TIM5CH1_CAPTURE_STA&0x80)//成功捕获一次脉宽
        {
            temp=TIM5CH1_CAPTURE_STA&0x3f;//捕获次数取出
            temp*=65536;//0xffff=65536
            temp+=TIM5CH1_CAPTURE_VAL;//脉宽持续时间
            printf("HIGH:%d us\r\n",temp);//打印总的高点平时间
            TIM5CH1_CAPTURE_STA=0;//清零,准备下一次输入捕获
        }
    }
}

by寄存器

TIM5_CAP_Init()

//TIM5通道1输入捕获初始化
void TIM5_CAP_Init(u16 arr, u16 psc)
{
    //使能时钟
    RCC->APB2ENR|=1<<2;//PA口时钟使能
    RCC->APB1ENR|=1<<3;//TIM5时钟使能

    //GPIOA.0初始化
    GPIOA->CRL&=0XFFFFFFF0;
    GPIOA->CRL|=0X00000008;//PA.0下拉输入,默认下拉

    //TIM5时钟初始化
    TIM5->ARR=arr;//TIM3自动重装载值
    TIM5->PSC=psc;//设置预分频值    

    //TIM5通道1中断初始化
    TIM5->CCMR1|=1<<0;//无滤波,无预分频,IC1映射在TI1上

    //中断分组初始化
    MY_NVIC_Init(2,2,TIM5_IRQn,2);//抢占2,响应2,中断优先级分组2

    TIM5->CCER|=1<<0;         //CC1E=1     允许捕获计数器的值到捕获寄存器中

    //使能捕获和更新中断
    TIM5->DIER|=1<<0;//使能更新中断
    TIM5->DIER|=1<<1;//使能捕获中断    

    //使能定时器5
    TIM5->CR1|=1<<0;
}

TIM5_IRQHandler()

u8  TIM5CH1_CAPTURE_STA=0;    //输入捕获状态                            
u16    TIM5CH1_CAPTURE_VAL;    //输入捕获值

void TIM5_IRQHandler(void)
{
    if((TIM5CH1_CAPTURE_STA&0x80)==0)//还未成功捕获
    {
        if(TIM5->SR&0x01)
        {
            if(TIM5CH1_CAPTURE_STA&0x40)//已经捕获到高电平了
            {
                if((TIM5CH1_CAPTURE_STA&0x3f)==0x3f)
                {
                    TIM5CH1_CAPTURE_STA|=0x80;//标记成功捕获了一次
                    TIM5CH1_CAPTURE_VAL=0xffff;
                }else TIM5CH1_CAPTURE_STA++;
            }
        }
        if(TIM5->SR&0x02)//捕获1发生捕获时间
        {
            if(TIM5CH1_CAPTURE_STA&0x40)//已经捕获到上升沿了,此为下降沿
            {
                TIM5CH1_CAPTURE_STA|=0x80;//标记捕获到一次高电平脉宽
                TIM5CH1_CAPTURE_VAL=TIM5->CCR1;
                TIM5->CCER&=~(1<<1);//设置为捕获上升沿
            }else//还未开始时,捕获上升沿
            {
                TIM5CH1_CAPTURE_STA=0;
                TIM5CH1_CAPTURE_VAL=0;
                TIM5->CNT=0;//计数器清空
                TIM5CH1_CAPTURE_STA|=0x40;//标记捕获了上升沿
                TIM5->CCER|=1<<1;//设置为捕获下降沿
            }
        }
    }
    TIM5->SR&=~(1<<0);//清除更新中断标志位
    TIM5->SR&=~(1<<1);//清除捕获中断标志位
    //可以直接TIM5->SR=0;
}

main.c

#include "sys.h"    
#include "delay.h"     
#include "timer.h"
#include "led.h"
#include "usart.h"

extern u8  TIM5CH1_CAPTURE_STA;    //输入捕获状态                            
extern u16    TIM5CH1_CAPTURE_VAL;    //输入捕获值

int main(void)
{                 
    u32 temp=0;  
    Stm32_Clock_Init(9);//系统时钟设置
    delay_init(72);//延时初始化 
    uart_init(72,115200);//串口初始化
    LED_Init();                  //初始化与LED连接的硬件 接口
TIM5_CAP_Init(0XFFFF,72-1);    //以1MHz的时钟频率计数
while(1)
    {
        if(TIM5CH1_CAPTURE_STA&0x80)
        {
            temp=TIM5CH1_CAPTURE_STA&0x3f;
            temp*=65536;
            temp+=TIM5CH1_CAPTURE_VAL;
            printf("HIGH: %d us\r\n",temp);//左下划线
            TIM5CH1_CAPTURE_STA=0;
        }
    }
}

文章作者: Mat Jenin
文章链接: http://matjenin.xyz
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mat Jenin !
  目录