STM32自学☞输入捕获测频率和占空比案例

**本文是通过PA0口输出PWM波,然后通过PA6口捕获PWM波的频率和占空比,最终在oled屏上显示我们自己设置的频率和占空比。**由于和前面的pwm呼吸灯代码有重合部分所以本文中的代码由前者修改而来,对于文件命名不要在意。

++pwm_led.c文件++

/*

编写步骤

1.RCC开启时钟(TIM、GPIO)

2.配置时基单元

3.配置输出比较单元

4.配置GPIO

5.运行控制

*/

#include "stm32f10x.h"

#include "stm32f10x_tim.h"

#include "pwm_led.h"

//初始化函数

void PWM_Init(void)

{

/*开启时钟*/

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟

/*GPIO初始化*/

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO_Pin_15;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/*配置时钟源*/

TIM_InternalClockConfig(TIM2); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟

/*时基单元初始化*/

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量

TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能

TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数

TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //计数周期,即ARR的值

TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //预分频器,即PSC的值

TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元

/*输出比较初始化*/

TIM_OCInitTypeDef TIM_OCInitStructure; //定义结构体变量

TIM_OCStructInit(&TIM_OCInitStructure); //结构体初始化,若结构体没有完整赋值则最好执行此函数,给结构体所有成员都赋一个默认值,避免结构体初值不确定的问题

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //输出比较模式,选择PWM模式1

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性,选择为高,若选择极性为低,则输出高低电平取反

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出使能

TIM_OCInitStructure.TIM_Pulse = 0; //初始的CCR值

TIM_OC1Init(TIM2, &TIM_OCInitStructure); //将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1

/*TIM使能*/

TIM_Cmd(TIM2, ENABLE); //使能TIM2,定时器开始运行

}

/*改变占空比函数*/

void PWM_SetCompare1(uint16_t Compare)

{

TIM_SetCompare1(TIM2, Compare); //设置CCR1的值

}

/*通过设置psc的值来调节频率*/

void PWM_SetPrescaler(uint16_t Prescaler)

{

TIM_PrescalerConfig(TIM2,Prescaler,TIM_PSCReloadMode_Immediate); //写入一个值,立刻生效

}

++pwm_led.h文件++

#ifndef _PWM_LED_H

#define _PWM_LED_H

#include "stdint.h"

void PWM_Init(void);

void PWM_SetCompare1(uint16_t Compare);

void PWM_SetPrescaler(uint16_t Prescaler);

#endif

++ic.c文件++

#include "stm32f10x.h"

#include "stm32f10x_tim.h"

#include "ic.h"

/*初始化函数步骤

1.开启GPIO和TIM的时钟

2.GPIO初始化并把GPIO配置为输入模式

3.配置时基单元,让CNT计数器在内部时钟驱动下自增运行

4.配置输入捕获单元

5.选择从模式的触发源

6.选择触发后执行的操作

7.开启定时器

*/

void IC_Init(void)

{

/*开启时钟*/

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //开启TIM3的时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟

/*GPIO初始化*/

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //GPIO_Pin_6;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA6引脚初始化为复用推挽输出,受外设控制的引脚,均需要配置为复用模式

/*配置时钟源*/

TIM_InternalClockConfig(TIM3); //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟

/*时基单元初始化*/

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; //定义结构体变量

TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能

TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数

TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //计数周期,即ARR的值

TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //预分频器,即PSC的值

TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; //重复计数器,高级定时器才会用到

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure); //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元

/*初始化输入捕获单元*/

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_ICInitStruct.TIM_Channel=TIM_Channel_2; //通道

TIM_ICInitStruct.TIM_ICFilter=0XF; //输入捕获的滤波器

TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Falling; //下降沿触发

TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1; //不分频

TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_IndirectTI; //触发信号交叉通道输入

*/

//下面用这个函数更简单,效果上面注销的代码一样

TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);

/*配置从模式的触发源*/

TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);

/*配置从模式为Reset*/

TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);

//使能

TIM_Cmd(TIM3,ENABLE);

}

//获取频率的函数

uint32_t IC_GetFreq(void)

{

return 1000000/(TIM_GetCapture1(TIM3)+1);

}

//获取占空比的函数

uint32_t IC_GetDuty(void)

{

return TIM_GetCapture2(TIM3)*100/(TIM_GetCapture1(TIM3)+1);

}

++ic.h文件++

#ifndef _IC_H

#define _IC_H

#include "stdint.h"

void IC_Init(void);

uint32_t IC_GetFreq(void);

uint32_t IC_GetDuty(void);

#endif

++main.c文件++

#include "stm32f10x.h"

#include "stm32f10x_tim.h"

#include "delay.h"

#include "OLED.h"

#include "pwm_led.h"

#include "ic.h"

int main (void)

{

/*模块初始化*/

OLED_Init();

PWM_Init();

IC_Init();

OLED_ShowString(1,1,"Freq:00000HZ");

OLED_ShowString(2,1,"Duty:00%");

PWM_SetPrescaler(7200-1);

PWM_SetCompare1(80);

while(1)

{

OLED_ShowNum(1,6,IC_GetFreq(),5);

OLED_ShowNum(2,6,IC_GetDuty(),2);

}

}

相关推荐
杯子不吃紫菜10 分钟前
LangGraph 体系实战(下):中断恢复、流式、子图与设计模式
单片机·嵌入式硬件·设计模式
qq_4480111639 分钟前
中断服务函数简介
嵌入式硬件
Risehuxyc1 小时前
STM32程序逻辑---入口函数逻辑和NVIC嵌套向量中断控制器初始化
stm32·单片机·嵌入式硬件
【 STM32开发 】1 小时前
CubeMX+STM32】SD卡U盘实现__USB+FATFS (F103 篇)
stm32·单片机·嵌入式硬件
jianqiang.xue1 小时前
3倍向量算力:Arm给最小MCU装上本地AI
arm开发·人工智能·单片机
蜀黍@猿3 小时前
ARM 汇编入门(十二):MMU、页表与虚拟内存全解析
汇编·arm开发·stm32·mcu
无敌最俊朗-15 小时前
【电感专题2:电感的感抗、电路的阻抗、电流的滞后】
单片机·嵌入式硬件·元器件·电感
wuyk55520 小时前
嵌入式故障诊断-Bug002-局部大数组压栈高温必死机
stm32·单片机·嵌入式硬件·mcu·物联网·51单片机·嵌入式实时数据库
Zwawa1 天前
嵌入式OLED表驱动菜单:用一张表、一个栈和一个窗口重写表驱动菜单
c语言·单片机·嵌入式
Dev_XH1 天前
【成品设计】基于沁恒单片机的电动汽车充电站智慧调度系统
stm32·单片机·嵌入式硬件·物联网