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