연구 노트 -STM32 타이머 프로그램 응용 프로그램 (2 개)

PWM 입력 캡쳐 코드 설명
안녕하세요 여러분, 드디어 나타났습니다. 대학원 입시 복습을 준비해야했고, 32 년의 공부 끝에 카메라를 배웠고, 며칠간 비둘기를하고 있습니다.

글쎄, 할 말이 많지는 않지만 주제로 직접 가자.

이 실험은 실제로 PWM 신호를 측정하는 데 사용됩니다. 동일한 타이머는 입력 캡처와 출력 비교를 동시에 사용할 수 없으므로이 실험에서는 범용 타이머를 사용하여 신호를 생성하고 고급 타이머를 사용하여 신호를 캡처합니다.

이전 실험에서와 같이 예제의 User 폴더 아래에 bsp_AdvanceTim.c 및 bsp_AdvanceTim.h 파일을 추가합니다. 여기서 주목해야 할 사항은 사전 및 일반 폴더를 넣는 것입니다. 다른 타이머를 사용하면 해당 GPIO가 다르기 때문입니다.

먼저 PIO를 초기화합니다.

static void ADVANCE_TIM_GPIO_Config(void) 
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);
}

여기서 GPIO는 사각 파를 캡처하기 위해 IN_FLOATING 플로팅 입력으로 설정되어야합니다.

그런 다음 루틴에서 .h 파일을 이식하십시오.

#ifndef __BSP_ADVANCETIME_H
#define __BSP_ADVANCETIME_H

#include "stm32f10x.h"

#define            ADVANCE_TIM                   TIM1
#define            ADVANCE_TIM_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define            ADVANCE_TIM_CLK               RCC_APB2Periph_TIM1

//输入捕获能捕获到的最小频率为72M/{(ARR+1)*(PSC+1)}
#define            ADVANCE_TIM_PERIOD            (1000-1)
#define            ADVANCE_TIM_PSC               (72-1)

//中断相关宏定义
#define            ADVANCE_TIM_IRQ               TIM1_CC_IRQn
#define            ADVANCE_TIM_IRQHandler        TIM1_CC_IRQHandler

//TIM1输入捕获通道一
#define            ADVANCE_TIM_CH1_GPIO_CLK      RCC_APB2Periph_GPIOA
#define            ADVANCE_TIM_CH1_PORT          GPIOA
#define            ADVANCE_TIM_CH1_PIN           GPIO_Pin_8

#define            ADVANCE_TIM_IC1PWM_CHANNEL    TIM_Channel_1

void ADVANCE_TIM_Init(void);

#endif

.c 파일에서 GPIO를 구성한 후 초기화해야합니다.

static void ADVANCE_TIM_GPIO_Config(void) 
{
    
    
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure); 
}

다음은 특히주의해야 할 중요한 사항입니다. 구성 할 때 기간 및 PSC의 값을 마음대로 구성 할 수 없습니다. 생성 된 구형파는 100K이고주기는 1 / 100 = 10us라고 가정합니다. 계수주기가 <10us이면주기를 캡처 할 수없고 <1khz 또는> 10ki이면 캡처 할 수 없습니다. 공통 모터의 구동 주파수는 10K에서 25K 사이입니다.

인터럽트 우선 순위를 설정하고 입력 캡처 구조를 초기화해야합니다.

static void ADVANCE_TIM_Mode_Config(void)
{
    
    
 ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE);

 TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

 TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD; 
 //自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新中断 
 TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC; 
 //驱动CNT计数器的时钟
 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
  //时钟分频因子,配置死区时间要用
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;  
  //计数模式,设置为向上计数
  TIM_TimeBaseStructure.TIM_RepetitionCounter=0; 
  //重复计数器的值
  TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);
  //初始化定时器

  TIM_ICInitTypeDef  TIM_ICInitStructure;

  TIM_ICInitStructure.TIM_Channel = ADVANCE_TIM_IC1PWM_CHANNEL;
  //捕获通道IC1配置
  //选择捕获通道
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
  //设置捕获的边沿
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
  //设置捕获通道的信号来自于哪个输入通道,由直连和非直连两种
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
  //1分频,即捕获信号的每个有效边沿都捕获
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
  //不滤波
  TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);
  //初始化PWM输入模式
  

  TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1); 
  //选择输入捕获的触发信号
  TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);
  TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable);
  //选择从模式:复位模式
  //PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位
  TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE);
  //使能捕获中断,这个中断针对的是主捕获通道
  TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);
  //清除中断标志位
  TIM_Cmd(ADVANCE_TIM, ENABLE);
  //使能高级控制定时器,计数器开始计数

인터럽트 우선 순위는 다음과 같습니다.

static void ADVANCE_TIM_NVIC_Config(void)
{
    
    
 NVIC_InitTypeDef NVIC_InitStructure;
 
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
 //设置中断组为0
 NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQ; 
 //设置中断来源
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 //设置抢占优先级
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
 //设置子优先级
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure); 
}

마지막으로 .h로 작성된 세 가지 함수를 타이머 초기화 함수에 넣습니다.

void ADVANCE_TIM_Init(void)
{
    
    
 ADVANCE_TIM_NVIC_Config();
 ADVANCE_TIM_GPIO_Config();
 ADVANCE_TIM_Mode_Config();  
}

그 안에 인터럽트 서비스 함수를 작성해야합니다 .c :

void ADVANCE_TIM_IRQHandler(void)
{
    
    
  TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);
  //清除中断标志位
  IC1Value = TIM_GetCapture1(ADVANCE_TIM);
  IC2Value = TIM_GetCapture2(ADVANCE_TIM);
  //获取输入捕获值
  if (IC1Value != 0)
  //注意:捕获寄存器CCR1和CCR2的值在计算占空比和频率的时候必须+1
  {
    
    
    DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);
    //占空比计算
    Frequency = (72000000/(ADVANCE_TIM_PSC+1))/(float)(IC1Value+1);
    //频率计算
    printf("Õ¼¿Õ±È£º%0.2f%%   ƵÂÊ£º%0.2fHz\n",DutyCycle,Frequency);
  }
  else
  {
    
    
    DutyCycle = 0;
    Frequency = 0;
  }
}
``如果是第一个上升沿中断,计数器会被复位,锁存到CCR1的值为0,CCR2的值也是0.无法计算频率与占空比; 当第二次上升沿到来的时候,CCR1和CCR2捕获到的值为有效的值,其中CCR1对应的是周期,CCR2对应的是占空比。

好的,到这里程序基本上就编写完成了,但是如果现在别写程序的时候就会出现:DutyCycle、Frequency未定义的情况出现,因此我们还需要加最后一步。就是在中断服务函数掐面加上定义:

```c
__IO uint16_t IC2Value = 0;
__IO uint16_t IC1Value = 0;
__IO float DutyCycle = 0;
__IO float Frequency = 0;

마지막으로 main.c를 정렬 할 수 있습니다.

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_GeneralTim.h"  
#include "bsp_AdvanceTim.h" 
#include "bsp_usart.h"

int main(void)
{
    
     
  USART_Config();
  GENERAL_TIM_Init();
  ADVANCE_TIM_Init();

  while(1)
  {
    
    
  }
}

좋아, 모든 관련 타이머가 완료되었으며 다음 업데이트는 카메라 챕터가 될 것입니다. 그래도 타이머를 이해하지 못하는 경우 아래에 댓글을 남기거나 URL을 입력하여 전체 동영상을 볼 수 있습니다. https://www.bilibili.com/video/av28951854?from=search&seid=13956434192947447162

추천

출처blog.csdn.net/weixin_41679822/article/details/102497284