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);

}

}

相关推荐
晶振厂家-晶发电子1 天前
晶振在5G时代的角色:高精度时钟的核心支撑
单片机·嵌入式硬件·5g·晶振·电子元器件·晶振知识
F137298015571 天前
WD5030A 芯片,12V降5V,输出电流12A,电路设计
stm32·单片机·嵌入式硬件·汽车·51单片机
小莞尔1 天前
【51单片机】【protues仿真】基于51单片机的篮球计时计分器系统
c语言·stm32·单片机·嵌入式硬件·51单片机
三佛科技-187366133971 天前
分享机械键盘MCU解决方案
单片机·嵌入式硬件·计算机外设
李永奉1 天前
51单片机-使用IIC通信协议实现EEPROM模块教程
单片机·嵌入式硬件·51单片机
工大一只猿1 天前
51单片机学习
嵌入式硬件·学习·51单片机
小莞尔1 天前
【51单片机】【protues仿真】 基于51单片机八路抢答器系统
c语言·开发语言·单片机·嵌入式硬件·51单片机
风_峰1 天前
Ubuntu Linux SD卡分区操作
嵌入式硬件·ubuntu·fpga开发
bing_feilong1 天前
STM32精准控制水流
单片机·嵌入式硬件
Hello_Embed1 天前
STM32HAL 快速入门(二十):UART 中断改进 —— 环形缓冲区解决数据丢失
笔记·stm32·单片机·学习·嵌入式软件