文章目录
- 前言
- 一、介绍部分
- 输入捕获简介
- 频率测量
- 捕获比较通道
- 主从模式
- 输入捕获基本结构
- PWMI基本结构
- 二、代码部分
- 使用输入捕获捕获另一个端口的PWM输入
- 线路连接
- 代码内容
- PWMI获取频率占空比
- 线路连接与上个案例一致
- 代码实现
- 总结
- 相关函数
- PSC、ARR都有1的误差
前言
这部分主要介绍输入捕获,通过输入捕获捕获定时器的计数器的值,通过频率检测来获取波形频率。简单介绍主从模式,实现硬件自动化检测。
一、介绍部分
输入捕获简介
也就是定时器框图的这部分
频率测量
都是计次数越大误差越小,所以使用N相等时得到中界频率。
捕获比较通道
主从模式
通过触发触发源自动运行从模式的内容
输入捕获基本结构
PWMI基本结构
二、代码部分
使用输入捕获捕获另一个端口的PWM输入
使用TIM2、PA0端口用于输出PWM波形,使用TIM3、PA6端口来接收这段波形频率。使用的是测周法。
线路连接
代码内容
PWM.c
#include "stm32f10x.h" // Device headervoid PWM_Init(void){// 初始化时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);// 使用内部时钟(默认)TIM_InternalClockConfig(TIM2);// 配置事间基础(时基单元)TIM_TimeBaseInitTypeDef TIM_InitStructure;// 时钟分频TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;// 计算模式TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;// 重载值(有1的偏差)<计数值> ARRTIM_InitStructure.TIM_Period = 100-1;// 预分频(有1的偏差)<频率> PSCTIM_InitStructure.TIM_Prescaler = 720-1;// 重复计数器(不使用)TIM_InitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2,&TIM_InitStructure);//初始化输出比较TIM_OCInitTypeDef TIM_OCInitStruct;// 初始这个结构体,以免因为没有配置高级定时器相关的值而产生问题TIM_OCStructInit(&TIM_OCInitStruct);// PWM1模式TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;// PWM高电平时有效TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;// 输出使能TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;// CCR,用于控制占空比的值TIM_OCInitStruct.TIM_Pulse = 0;TIM_OC1Init(TIM2,&TIM_OCInitStruct);// 启动定时器TIM_Cmd(TIM2,ENABLE);}// 设置CCR
void PWM_SetCCR(uint16_t Compare){TIM_SetCompare1(TIM2,Compare);}// 设置PSC
void PWM_SetPSC(uint16_t Prescaler){// 单独修改TIM2的预分频,立即生效,不使用影子寄存器TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate);
}
封装输入捕获,IC.c内容:
#include "stm32f10x.h" // Device headervoid IC_Init(void){// 开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);// 使用内部时钟(默认)TIM_InternalClockConfig(TIM3);// 配置事间基础(时基单元)TIM_TimeBaseInitTypeDef TIM_InitStructure;// 时钟分频TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;// 计算模式TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;// 重载值(有1的偏差)<计数值> ARRTIM_InitStructure.TIM_Period = 65536-1;// 预分频(有1的偏差)<频率> PSCTIM_InitStructure.TIM_Prescaler = 72-1;// 重复计数器(不使用)TIM_InitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3,&TIM_InitStructure);//初始化输入捕获TIM_ICInitTypeDef TIM_ICInitStructure;// 选择CH1通道TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;// 滤波频率,设置高点过使人耳听不见噪音,不会影响频率TIM_ICInitStructure.TIM_ICFilter = 0xF;// 上升沿触发TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;// 分频器不分频TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;// 选择直连通道TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInit(TIM3,&TIM_ICInitStructure); // 四个通道一个函数// 设置输入触发源TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);// 选择从模式,重置TIM3的计数器TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);// 启动定时器TIM_Cmd(TIM3,ENABLE);
}uint32_t IC_GetFreq(void){// 72000000/73/获取的ARRreturn 1000000 / (TIM_GetCapture1(TIM3)+1);
}
主函数main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();PWM_SetPSC(720-1); // f = 72MHz/(Prescaler+1)/(ARR+1)PWM_SetCCR(50); // 占空比 = CRR/(ARR+1)OLED_ShowString(1,1,"Freq: Hz");while (1){OLED_ShowNum(1,8,IC_GetFreq(),5);}
}
PWMI获取频率占空比
和PWMI基本结构一样,在上面的基础上多加一条交叉通道,用这个通道检测下降沿,来获取占空比
线路连接与上个案例一致
代码实现
PWM.c不用修改,修改IC.c的内容
#include "stm32f10x.h" // Device headervoid IC_Init(void){// 开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度GPIO_Init(GPIOA, &GPIO_InitStructure);// 使用内部时钟(默认)TIM_InternalClockConfig(TIM3);// 配置事间基础(时基单元)TIM_TimeBaseInitTypeDef TIM_InitStructure;// 时钟分频TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;// 计算模式TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;// 重载值(有1的偏差)<计数值> ARRTIM_InitStructure.TIM_Period = 65536-1;// 预分频(有1的偏差)<频率> PSCTIM_InitStructure.TIM_Prescaler = 72-1;// 重复计数器(不使用)TIM_InitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3,&TIM_InitStructure);//初始化输入捕获TIM_ICInitTypeDef TIM_ICInitStructure;// 选择CH1通道TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;// 滤波频率,设置高点过使人耳听不见噪音,不会影响频率TIM_ICInitStructure.TIM_ICFilter = 0xF;// 上升沿触发TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;// 分频器不分频TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;// 选择直连通道TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
// TIM_ICInit(TIM3,&TIM_ICInitStructure); // 四个通道一个函数// 自动配置另一条相反通道,下降沿触发,交叉通道TIM_PWMIConfig(TIM3,&TIM_ICInitStructure);// 设置输入触发源TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);// 选择从模式,重置TIM3的计数器TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);// 启动定时器TIM_Cmd(TIM3,ENABLE);
}uint32_t IC_GetFreq(void){// 72000000/73/获取的ARRreturn 1000000 / (TIM_GetCapture1(TIM3)+1);
}
// 获取占空比
uint32_t IC_GetDuty(void){return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
}
主函数main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
#include "IC.h"int main(void)
{OLED_Init();PWM_Init();IC_Init();PWM_SetPSC(7200-1); // f = 72MHz/(Prescaler+1)/(ARR+1)PWM_SetCCR(80); // 占空比 = CRR/(ARR+1)OLED_ShowString(1,1,"Freq: Hz");OLED_ShowString(2,1,"Duty: %");while (1){// 显示频率OLED_ShowNum(1,8,IC_GetFreq(),5);// 显示占空比OLED_ShowNum(2,11,IC_GetDuty(),2);}
}
总结
相关函数
// 初始化输入捕获
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
// 自动配置没有配置的另一条输入捕获通道
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
// 设置从模式
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
// 设置不同定时器的比较值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
// 设置不同定时器的预分频
void TIM_SetIC1Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC2Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC3Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
void TIM_SetIC4Prescaler(TIM_TypeDef* TIMx, uint16_t TIM_ICPSC);
// 获取不同定时器的捕获计数器内容
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture2(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture3(TIM_TypeDef* TIMx);
uint16_t TIM_GetCapture4(TIM_TypeDef* TIMx);