PWM入力キャプチャコードの説明
みなさん、こんにちは。大学院入学試験の見直しの準備をしなければならないので、ようやく登場しました。32年間の勉強でカメラを習得し、数日間鳩になりました。
さて、言うまでもなく、トピックに直接行きましょう。
この実験は、実際にはPWM信号の測定に使用されます。同じタイマーで入力キャプチャと出力比較を同時に使用することはできないため、この実験では、汎用タイマーを使用して信号を生成し、高度なタイマーを使用して信号をキャプチャします。
前の実験と同様に、例のUserフォルダーの下にbsp_AdvanceTim.cファイルとbsp_AdvanceTim.hファイルを追加します。ここで、advanceフォルダーとgeneralフォルダーを配置する必要があることに注意してください。これは、異なるタイマーを使用すると、対応する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);
}
ここに特別な注意を払うべき重要なポイントがあります:私たちが構成しているとき、Periodと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で記述された3つの関数をタイマー初期化関数に入れます。
void ADVANCE_TIM_Init(void)
{
ADVANCE_TIM_NVIC_Config();
ADVANCE_TIM_GPIO_Config();
ADVANCE_TIM_Mode_Config();
}
it.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