一、微项目实现目标:
利用TIM2定时器产生的PWM波,输入到TIM3输入检测模块,在接收到输入的PWM信号,模块进行计算,在OLED上打印对应的频率
(总结来说,测周法,测试周期频率)
二、微项目硬件配置需求:
stm32F103C8T6核心板一块
0.96寸OLED显示,用于显示计数
三、前置知识:
整个项目由两大块组成:1,输出比较模式控制输出不同周期的PWM数据;2,输入比较模式下,检测输入的PWM波
1,输出比较模式控制输出不同周期的PWM数据:
①选择PWM1模块,在CNT计数值<CCR时刻,REF置为有效电平,在CNT计数值>=CCR,且小于ARR时刻,REF置为无效电平;
2,输入检测检测PWM周期
①时基单元:主要配置PSC/ARR数值,时钟源选择72MHZ内部时钟
②输入捕获单元的配置。
1-滤波器主要是对于信号进行滤波处理;
2-边沿检测极性选择主要来判断极性;
3-分频器,再一次进行分频处理;如果分频因子为2,则捕获两次上升沿,才认为有效
③从模式选择
在识别上升沿后,触发从模式,清空CNT
输入捕获PWM周期的整体逻辑:
1,时基单元,按照设定的PSC,输入的时钟源信号进行计数处理,当收到输入捕获模式的触发源后,将CNT的数值转移CCR1寄存器中,CCR1的值就是本次计数的数据,在进行一轮计算就可以得到输入的频率,f_x=f_c / N
2,紧接着触发的从模式,会将CNT的数据进行清0,进行下一轮的计数。
3,每次产生触发都是从0开始计数的,所以转移的CNT值就是实际的两次上升沿之间的时间占比
四、代码逻辑分析
主要两大块
1,PWM输出比较模块
①开启TIM2时钟、PA0时钟
②配置时钟源
③配置时基模块参数
④配置输出比较模块参数
⑤配置PA0端口
⑥开启时钟
2,输入比较模块
①开启TIM3时钟、PA6时钟
②配置时钟源
③配置时基模块
④配置输入单元模块
⑤配置从模式
⑥配置GIPO端口
⑦开启时钟
五、代码示例:
1,PWM输出比较模块
①开启TIM2时钟、PA0时钟
//配置时钟RCC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
②配置时钟源
//配置时钟源为RCC -72mhz
TIM_InternalClockConfig(TIM2);
③配置时基模块参数
//配置时基单元数值
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1 ;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up ;
TIM_TimeBaseInitStruct.TIM_Period=100-1; //ARR
TIM_TimeBaseInitStruct.TIM_Prescaler=720-1; //psc
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
④配置输出比较模块参数
TIM_OCStructInit(&TIM_OCInitStruct);用于进行默认初始化,原因是,后面的初始化仅对部分参数进行设定,为防止bug,先进行一次默认初始化
//输出比较单元配置
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1 ;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High ;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse=0;//设置CCR数值
TIM_OC1Init(TIM2, &TIM_OCInitStruct);
⑤配置gpio_PA0端口 复用推挽输出
// 配置PA0端口
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStruct);
⑥开启时钟
//启动定时器
TIM_Cmd(TIM2,ENABLE);
⑦动态配置CCR的数值,输出不同占空比
动态配置psc的数值,输出不同频率
void pwm_setcompare( uint16_t compare)
{
TIM_SetCompare1(TIM2, compare);
}
void pwm_setPerscaler(uint16_t prescaler )//修改psc的数值,达到修改pwm频率
{
TIM_PrescalerConfig(TIM2, prescaler, TIM_PSCReloadMode_Immediate);
}
2,输入比较模块
①开启TIM3时钟、PA6时钟
//开启GPIO、TIM的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//tim3
②配置PA6端口的输入模式-上拉输入
//配置PA6端口
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode= GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
③配置时钟源 72mhz
//时基单元时钟源配置--系统时钟72MHZ
TIM_InternalClockConfig(TIM3);
④配置时基单元
//时基单元配置
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1 ;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up ;
TIM_TimeBaseInitStruct.TIM_Period=65536-1; //ARR
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1; //PSC
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3, & TIM_TimeBaseInitStruct);
⑤配置输入捕获模块
//配置输入捕获
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1 ;//输入捕获的端口
TIM_ICInitStruct.TIM_ICFilter=0xf;//输入捕获的滤波器
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising ;//捕获的状态 上升沿/下降沿
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1 ;//分频器,如果是二分频,则两次输出一次
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//属于直连通道还是交叉通道
TIM_ICInit( TIM3, & TIM_ICInitStruct);
⑥从模式配置
//从模式触发源选择
TIM_SelectInputTrigger( TIM3, TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
⑦开启时钟
//开启时钟
TIM_Cmd(TIM3, ENABLE);
⑧配置输出频率计算模块
f_x=f_c / N
uint32_t IC_getfreq(void)
{
return 1000000/TIM_GetCapture1(TIM3);
}
最后在main函数中简单配置
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "OLED.H"
#include "PWM.H"
#include "ic.H"
uint32_t freq=0;
int main()
{
OLED_Init();
OLED_ShowString(1,3,"freq:");
pwm_init();
ic_init();
pwm_setcompare(50);//duty=CCR/100 占空比
pwm_setPerscaler(720-1); //freq=72M/(psc+1)/100 频率
while(1)
{
freq=IC_getfreq();
OLED_ShowNum(2,1,freq,5);
}
}