PWM频率 = 更新频率 = 72M / (PSC – 1) / (ARR – 1)
占空比 = CCR / (ARR + 1)
所以通过PSC调节频率,不会影响占空比,会比较方便
设定ARR为100 – 1不变只改变PSC来调节频率,而且ARR为此值时,CCR的数值直接就是占空比 ,用起来比较直观
一般我们可以根据分辨率的要求,先确定好ARR,再用PSC决定频率,CCR决定占空比。
void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
单独写入PSC的函数,TIM_PSCReloadMode可以选择时更新事件重装还是立即重装,也就是影子寄存器
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
OCInit四个通道都是分开来的,需要单独操控
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
而ICInit是4各通道共用一个函数,在结构体中有一个参数,可以用来选择具体配置哪个通道,因为可能有交叉通道的配置,所以函数合在一起比较方便
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
这个函数和上一个函数类似,都是用于初始化输入捕获单元的,但是上一个函数是只是单一地配置一个通道,而这个函数,可以快速配置两个通道,把外设结构配置成上图二中展示的PWMI模式。
void TIM_ICStructInit(TIM_ICInitTypeDef* TIM_ICInitStruct);
可以给输入捕获的结构体赋一个初始值。
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
选择输入触发源TRGI,这里就对应了上图三的从模式触发源选择
void TIM_SelectOutputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_TRGOSource);
选择输出触发源TRGO,对应上图三的选择主模式输出的触发源
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
选择从模式对应上图三的模式选择部分
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);
分别用于单独配置通道1,2,3,4的分频器,这个参数结构体里也能够配置,效果一样
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);
分别读取4个通道的CCR与之前的SetCompare函数对应的,读写的都是CCR寄存器,输出比较模式下,CCR只写,要用SetCompare写入,输入捕获模式下,CCR只读,要用GetCapture读取。
我们要用TIM2来输出PWM,再用TIM3来捕获。
首先根据图一的顺序来还是GPIO和时基单元的初始化
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;//查表可得TIM3的捕获通道1对应的是PA6口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 65536 – 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 – 1;//PSC决定测周法的标准频率fc(72M / 72 = 1MHz)
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
接着是输入捕获单元的初始化:
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//因为配置IC初始化的函数只有一个,需要选择通道
TIM_ICInitStructure.TIM_ICFilter = 0xF;//一般滤波器的采样频率都会远高于信号频率,所以只会滤除高频噪声使信号更平滑
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//选择上升沿触发
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//选择不分频,另外DIV2是二分频,其余DIV4,8是4,8分频
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//选择直连通道
TIM_ICInit(TIM3, &TIM_ICInitStructure);
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);//配置TRGI的触发源为TI1FP1
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);//配置从模式为Reset以清零CNT计数器
TIM_Cmd(TIM3, ENABLE);
捕获电路里的分频器,不分频就是每次触发都有效,2分频就是每隔一次有效一次,以此类推
最后再来一个读取CCR寄存器的函数,就能够读取频率了:
uint32_t IC_GetFreq(void)
{
return 1000000 / (TIM_GetCapture1(TIM3) + 1);//这里因为有误差为了得到整数调整加一
}
最后主函数选择好输出的频率,再在TIM3捕获通道读取CCR即可捕获TIM2输出的频率:
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//因为配置IC初始化的函数只有一个,需要选择通道
TIM_ICInitStructure.TIM_ICFilter = 0xF;//一般滤波器的采样频率都会远高于信号频率,所以只会滤除高频噪声使信号更平滑
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//选择上升沿触发
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//选择部分品,另外DIV2是二分频,其余DIV4,8是4,8分频
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//选择直连通道
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//在函数中,会自动把剩下一个通道初始化成相反的配置,如这里会配置成交叉通道,下降沿,该通道只支持通道一和通道二的配置
{
return (TIM_GetCapture2(TIM3) + 1) * 100/ (TIM_GetCapture1(TIM3) + 1);//CCR2 / CCR1 = 占空比
}