1.接线图:
实物图:
2.代码部分:
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(); OLED_ShowString(1,1,"Freq:00000Hz"); //执行逻辑:PWM模块将待测信号输出给PA0,PA0通过导线输入到PA6,PA6是TIM3的通道1, //通道1通过输入捕获模块,测量得到频率,进入主循环,不断刷新频率 PWM_SetPrescaler(720-1);//频率Freq=72M/(PSC+1)/(ARR+1),此时ARR+1=100,所以频率=1KHz PWM_SetCompare1(50);//占空比:Duty=CCR/(ARR+1),此时ARR+1=100,所以占空比=50% while(1) { OLED_ShowNum(1,6,IC_GetFreq(),5); } }
IC.c(输入捕获模式)代码部分:
#include "stm32f10x.h" // Device header
//思路:参照输入捕获基本结构图
//1.RCC开启时钟,开启GPIO和TIM时钟
//2.GPIO初始化,配置GPIO为输入模式(上拉输入或浮空输入)
//3.配置时基单元,使CNT计数器在内部时钟驱动下自增
//4.配置输入捕获单元,是结构体,包括滤波器,极性,直连通道还是交叉通道,分频器
//5.配置TRGI的触发源为TI1FP1
//6.配置从模式为ReSet
//7.调用TIM_Cmd,开启定时器
void IC_Init(void)//输入捕获初始化
{
//1~3开启时钟,配置GPIO,配置时基单元(直接抄写LED代码,修改通道和引脚,输入模式等即可)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启APB1时钟,TIM2是输出PWM,更改为TIM3(仍是APB1外设)
//配置GPIO RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //GPIO的时钟配置,查表得TIM3的通道1和2对应PA6和PA7(GPIOA);通道3和通道4对应PB0和PB1(GPIOB) GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//选择上拉输入模式 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;//用的是PA6引脚 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); //配置时基单元 TIM_InternalClockConfig(TIM3);//选择内部时钟的定时器TIM3 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //TIM_CKD_DIV1,1分频,不分配;TIM_CKD_DIV2,2分频;TIM_CKD_DIV4,4分频----要求不高时,随意选择 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数 //TIM_CounterMode_Up向上计数;TIM_CounterMode_Down向下计数;TIM_CounterMode_CenterAligned1等为中央对齐 TIM_TimeBaseInitStructure.TIM_Period=65536-1;//自动重装器的值,取最大值,防止溢出---ARR的值 TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//预分频,对72M进行7200分频----PSC的值 TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//高级定时器用到,通用定时器选0 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//结构体 //4.配置输入捕获单元 TIM_ICInitTypeDef TIM_ICInitStructuer; TIM_ICInitStructuer.TIM_Channel=TIM_Channel_1;//指定选择通道几,通道1为TIM_Channel_1 TIM_ICInitStructuer.TIM_ICFilter=0xF;//配置输入捕获的滤波器(有毛刺或噪声时增大滤波器参数) //参数解释:这个数可是是0x0~0xF之间的数.数越大,滤波效果越好 //滤波器计次不会改变信号的原有频率,之后让波形更符合条件. TIM_ICInitStructuer.TIM_ICPolarity=TIM_ICPolarity_Rising;//选择极性----上升沿触发还是下降沿还是都触发 TIM_ICInitStructuer.TIM_ICPrescaler=TIM_ICPSC_DIV1;//分频器, //不分频就是每次触发都有效,2分频是每隔一次有效一次... TIM_ICInitStructuer.TIM_ICSelection=TIM_ICSelection_DirectTI;//选择触发信号从哪个引脚输入, //直连通道,交叉通道等 TIM_ICInit(TIM3,&TIM_ICInitStructuer); //5.配置TRGI的触发源为TI1FP1 TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);//第二个参数选择触发源TIM_TS_TI1FP1 //6.配置从模式为ReSet TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset); //7.调用TIM_Cmd,开启定时器 TIM_Cmd(TIM3,ENABLE); } //注:想要查看频率时,读取CCR,计算即可 //fx=fc/N //fc=72M/(PSC+1) //因为PSC=72,所以fc=1MHz,所以fx=1000000/N,(N就是CCR) uint16_t IC_GetFreq(void) { return 1000000/(TIM_GetCapture1(TIM3)+1); }
IC.h(输入捕获模式)代码部分:
#ifndef __IC_H #define __IC_H uint16_t IC_GetFreq(void); void IC_Init(void); #endif
3.输入捕获模式使用到的STM32库函数
//TIM_ICStructInit,给输入捕获结构体赋初始值
//TIM_SelectInputTrigger,选择输入触发源TRGI(从模式的触发源选择,八个参数对应八个触发源)
//TIM_SelectOutputTrigger,选择输出触发源TRGO(主模式输出的触发源)
//TIM_SelectSlaveMode,选择从模式(4个参数对应从模式的Reset...External1四个从模式)
//TIM_SetIC1Prescaler,配置通道1的分频器,SetIC2是通道2...
//TIM_GetCapture1,输入捕获模式,CCR只读,通过TIM_GetCapture读出
//TIM_SetCompare1,输出比较模式,CCR只写,通过TIM_SetCompare写入