IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32-Project32:通用定时器输入捕获脉冲宽度实验;高级定时器捕获PWM的频率与占空比实验 -> 正文阅读

[嵌入式]STM32-Project32:通用定时器输入捕获脉冲宽度实验;高级定时器捕获PWM的频率与占空比实验

一?捕获脉冲宽度实验
硬件设计
根据开发板引脚使用情况,我们选用通用定时器 TIM5 CH1 ,就 PA0 这个 GPIO
测量信号的脉宽。在开发板中 PA0 接的是一个按键,默认接 GND ,当按键按下的时候 IO
口会被拉高,这个时候我们可以利用定时器的输入捕获功能来测量按键按下的这段高电平
的时间。
(1) 定时器用到的 GP IO 初始化
(2) 定时器时基结构体 TIM_TimeBaseInitTypeDef 初始化
(3) 定时器输入捕获结构体 TIM_ICInitTypeDef 初始化
(4) 编写中断服务函数,读取捕获值,计算出脉宽的时间
#ifndef __GENERALTIME_H
#define __GENERALTIME_H


#include "stm32f10x.h"



// 获取捕获寄存器值函数宏定义
#define            GENERAL_TIM_GetCapturex_FUN                 TIM_GetCapture1
// 捕获信号极性函数宏定义
#define            GENERAL_TIM_OCxPolarityConfig_FUN           TIM_OC1PolarityConfig

// 测量的起始边沿
#define            GENERAL_TIM_STRAT_ICPolarity                TIM_ICPolarity_Rising
// 测量的结束边沿
#define            GENERAL_TIM_END_ICPolarity                  TIM_ICPolarity_Falling


// 定时器输入捕获用户自定义变量结构体声明
typedef struct
{   
	uint8_t   Capture_FinishFlag;   // 捕获结束标志位
	uint8_t   Capture_StartFlag;    // 捕获开始标志位
	uint16_t  Capture_CcrValue;     // 捕获寄存器的值
	uint16_t  Capture_Period;       // 自动重装载寄存器更新标志 
}TIM_ICUserValueTypeDef;

extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure;


void GENERAL_TIM_Init(void);


#endif	



#include "generaltime.h"

// 定时器输入捕获用户自定义变量结构体定义
TIM_ICUserValueTypeDef TIM_ICUserValueStructure = {0,0,0,0};

// 中断优先级配置
static void GENERAL_TIM_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);	// 设置中断组为0	
    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn ;		// 设置中断来源	
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;// 设置主优先级为 0	 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;	  // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}


 // 输入捕获通道 GPIO 初始化浮空输入
static void GENERAL_TIM_GPIO_Config(void) 
{
  GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);	
}



//配置定时器的5个结构体成员
static void GENERAL_TIM_Mode_Config(void)
{
  
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);// 开启定时器时钟,即内部时钟CK_INT=72M

 //时基结构体初始化
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period=0XFFFF;	// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
	TIM_TimeBaseStructure.TIM_Prescaler= (72-1);	// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 时钟分频因子 ,配置死区时间时需要用到,这里没用	
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;	// 计数器计数模式,设置为向上计数	
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 重复计数器的值,没用到不用管	
	TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);	// 初始化定时器

	//输入捕获结构体初始化
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;// 配置输入捕获的通道,需要根据具体的GPIO来配置
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	// 输入捕获信号的极性配置
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;// 输入通道和捕获通道的映射关系,有直连和非直连两种
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	// 输入的需要被捕获的信号的分频系数	
	TIM_ICInitStructure.TIM_ICFilter = 0;// 输入的需要被捕获的信号的滤波系数
	TIM_ICInit(TIM5, &TIM_ICInitStructure);	// 定时器输入捕获初始化
	
  TIM_ClearFlag(TIM5, TIM_FLAG_Update| TIM_IT_CC1);	// 清除更新中断和捕获中断标志位  
	TIM_ITConfig (TIM5, TIM_IT_Update |  TIM_IT_CC1, ENABLE );  // 开启更新和捕获中断
	
	TIM_Cmd(TIM5, ENABLE);// 使能计数器
}

void GENERAL_TIM_Init(void)
{
	GENERAL_TIM_GPIO_Config();
	GENERAL_TIM_NVIC_Config();
	GENERAL_TIM_Mode_Config();		
}
在初始化时基结构体的周期和时钟分频因子这两个成员时,我们使用了两个宏
GENERAL_TIM_PERIOD GENERAL_TIM_PSC GENERAL_TIM_PERIOD 配置的是
ARR 寄存器的值,决定了计数器一个周期的计数时间,默认我们配置为 0XFFFF ,即最大。
GENERAL_TIM_PSC 配置的是分频因子,默认配置为 72-1 ,则可以计算出计数器的计数
周期为 (GENERAL_TIM_PSC+1)/72M = 1US 。所以输入捕获能捕获的最小的时间为 1us
最长的时间为 1us*(0Xffff+1)=65536us=65.536ms ,当超过这个计数周期的时候,就会产生
中断,然后在中断里面做额外的处理,需要记录好产生了多少次更新中断,最后把这个更
新时间加入到脉宽的时间里面。
GENERAL_TIM_Mode_Config() 函 数 中 , 我 们 配 置 输 入 捕 获 的 起 始 边 沿 为
GENERAL_TIM_STRAT_ICPolarity ,这是一个宏,默认配置为上升沿。我们的按键默认是
GND ,当按键按下的时候会被拉高,这个时候这个由低到高的上升沿会被捕获到,这是
第一次捕获,此时我们把计数器清 0,开始计数,同时把捕获边沿改成下降沿捕获。当第
二次进入中断服务函数的时候,说明捕获到下降沿,这个时候表示脉宽捕获完毕,我们读
取捕获寄存器的值即可,然后我们就可以通过这个值算出脉宽的时间。最后把捕获编译配
置为上升沿,为的是下一次捕获。如果脉宽的时间超过了计数器的最大计数时间,那么就
会产生更新中断,我们需要做额外的处理,即产生了多少次更新中断记录下来,最后在算
脉宽的时间的时候把这个更新的时间加进去即可。
中断服务函数里面用到的捕获结束标志位、捕获开始标志位、捕获寄存器的值和自动
重装载更新标志这几个成员是在一个结构体里面定义,具体声明见代码清单 32-12 。其中
声明是在 bsp_GeneralTim.h 这个头文件中,定义和初始化则在 bsp_GeneralTim.c 文件。
//捕获脉冲的核心代码
void TIM5_IRQHandler(void)
{
	// 当要被捕获的信号的周期大于定时器的最长定时时,定时器就会溢出,产生更新中断
	// 这个时候我们需要把这个最长的定时周期加到捕获信号的时间里面去
	if ( TIM_GetITStatus (TIM5, TIM_IT_Update) != RESET )               
	{	
		TIM_ICUserValueStructure.Capture_Period ++;		
		TIM_ClearITPendingBit(TIM5, TIM_FLAG_Update ); 		
	}

	// 上升沿捕获中断
	if ( TIM_GetITStatus(TIM5,TIM_IT_CC1 ) != RESET)
	{
		// 第一次捕获
		if (TIM_ICUserValueStructure.Capture_StartFlag == 0 )
		{
			TIM_SetCounter (TIM5, 0);// 计数器清0
			TIM_ICUserValueStructure.Capture_Period = 0;// 自动重装载寄存器更新标志清0
			TIM_ICUserValueStructure.Capture_CcrValue = 0; // 存捕获比较寄存器的值的变量的值清0	
			TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);// 当第一次捕获到上升沿之后,就把捕获边沿配置为下降沿
			TIM_ICUserValueStructure.Capture_StartFlag = 1;		// 开始捕标志准置1		
		}
		// 下降沿捕获中断
		else // 第二次捕获
		{
			// 获取捕获比较寄存器的值,这个值就是捕获到的高电平的时间的值
			TIM_ICUserValueStructure.Capture_CcrValue = TIM_GetCapture1 (TIM5);

			// 当第二次捕获到下降沿之后,就把捕获边沿配置为上升沿,好开启新的一轮捕获
			TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);
			TIM_ICUserValueStructure.Capture_StartFlag = 0;// 开始捕获标志清0	
			TIM_ICUserValueStructure.Capture_FinishFlag = 1; // 捕获完成标志置1		
		}

		TIM_ClearITPendingBit (TIM5,TIM_IT_CC1);	    
	}		
}
#include "stm32f10x.h"  
#include "led.h" 
#include "key.h"
#include "rcc.h"
#include "exti.h"
#include "systick.h"
#include "usart.h"
#include <stdio.h>
#include "basetime.h"
#include "advancetime.h"
#include "generaltime.h"

/*
 通用定时器TIM5_CH1即PA0引脚测量脉冲,本身接wake_up按键,
 按键按下接高电平,测量高电平脉冲时间,在串口上位机显示

*/

int main(void)
{
	
	uint32_t time;
	uint32_t TIM_PscCLK = 72000000 / ((72-1)+1);	// TIM 计数器的驱动时钟
	
	
	USART_Config();//串口初始化 
	GENERAL_TIM_Init();// 定时器初始化 
	
	printf ( "\r\nSTM32 输入捕获实验\r\n" );
	printf ( "\r\n按下wake_up,测试按下的时间\r\n" );
	
  while (1){
	 if(TIM_ICUserValueStructure.Capture_FinishFlag == 1)
		{
			// 计算高电平时间的计数器的值
			time = TIM_ICUserValueStructure.Capture_Period * (0XFFFF+1) + 
			       (TIM_ICUserValueStructure.Capture_CcrValue+1);
			
			// 打印高电平脉宽时间
			printf ( "\r\n测得高电平脉宽时间:%d.%d s\r\n",time/TIM_PscCLK,time%TIM_PscCLK );
			
			TIM_ICUserValueStructure.Capture_FinishFlag = 0;			
		}		
 }	
}



二??高级定时器捕获PWM的周期与占空比

在本节实验中,我们用通用定时器产 生一路 PWM 信号,然后用高级定时器的通道 1 或者通道 2 来捕获。
硬件设计
实验中用到两个引脚,一个是通用定时器 TIM3 的通道 1 ,即 PA6 ,用于输出 PWM
号,另一个是高级控制定时器 TIM1 的通道 1 ,即 PA8 ,用于 PWM 输入捕获,实验中直接
用一根杜邦线短接即可 PA6 PA8 即可,同时可用示波器监控 PA6 的波形,看看实验捕
获的数据是否正确。
编程要点
(1) 通用定时器产生 PWM 配置
(2) 高级定时器 PWM 输入配置
(3) 编写中断服务程序,计算测量的频率和占空比,并打印出来比较
编程的要点主要分成两部分,一个是通用定时器的 PWM 信号输出,另一个是 PWM
信号输入捕获。
通用定时器 PWM 输出

#include "generaltime3.h" 

/**
  * @brief  通用定时器PWM输出用到的GPIO初始化
  * @param  无
  * @retval 无
  */
static void GENERAL_TIM_GPIO_Config(void) 
{
  GPIO_InitTypeDef GPIO_InitStructure;

  // 输出比较通道1 GPIO 初始化
	RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  GENERAL_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GENERAL_TIM_CH1_PORT, &GPIO_InitStructure);

}



static void GENERAL_TIM_Mode_Config(void)
{
  
	GENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);// 开启定时器时钟,即内部时钟CK_INT=72M

	//时基结构体初始化 配置周期,这里配置为100K
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period=GENERAL_TIM_PERIOD;// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断	
	TIM_TimeBaseStructure.TIM_Prescaler=  (72-1);		// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;	// 时钟分频因子 ,配置死区时间时需要用到	
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;	// 计数器计数模式,设置为向上计数	
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 重复计数器的值,没用到不用管	
	TIM_TimeBaseInit(GENERAL_TIM, &TIM_TimeBaseStructure);	// 初始化定时器

	//输出比较结构体初始化	
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// 配置为PWM模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// 输出使能
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// 输出通道电平极性配置	
	TIM_OCInitStructure.TIM_Pulse = 5;
	TIM_OC1Init(GENERAL_TIM, &TIM_OCInitStructure);// 初始化输出比较通道 1
	TIM_OC1PreloadConfig(GENERAL_TIM, TIM_OCPreload_Enable);

	TIM_Cmd(GENERAL_TIM, ENABLE);// 使能计数器
}


void GENERAL_TIM3_Init(void)
{
	GENERAL_TIM_GPIO_Config();
	GENERAL_TIM_Mode_Config();		
}

高级定时器 PWM 输入捕获
#ifndef __ADVANCETIME1_H
#define __ADVANCETIME1_H


#include "stm32f10x.h"




#define            ADVANCE_TIM                   TIM1
#define            ADVANCE_TIM_APBxClock_FUN     RCC_APB2PeriphClockCmd
#define            ADVANCE_TIM_CLK               RCC_APB2Periph_TIM1

// 输入捕获能捕获到的最小的频率为 72M/{ (ARR+1)*(PSC+1) }
#define            ADVANCE_TIM_PERIOD            (1000-1)
#define            ADVANCE_TIM_PSC               (72-1)

// 中断相关宏定义
#define            ADVANCE_TIM_IRQ               TIM1_CC_IRQn
#define            ADVANCE_TIM_IRQHandler        TIM1_CC_IRQHandler

// TIM1 输入捕获通道1
#define            ADVANCE_TIM_CH1_GPIO_CLK      RCC_APB2Periph_GPIOA
#define            ADVANCE_TIM_CH1_PORT          GPIOA
#define            ADVANCE_TIM_CH1_PIN           GPIO_Pin_8

#define            ADVANCE_TIM_IC1PWM_CHANNEL    TIM_Channel_1


void ADVANCE_TIM1_Init(void);


#endif	


在上面的宏定义里面,我们可以算出计数器的计数周期为 T=72M/(1000*72)=1MS ,这
个是定时器在不溢出的情况下的最大计数周期,也就是说周期小于 1ms PWM 信号都可
以被捕获到,转换成频率就是能捕获到的最小的频率为 1KHZ 。所以我们要根据捕获的
PWM 信号来调节 ADVANCE_TIM_PERIOD ADVANCE_TIM_PSC 这两个宏。

#include "advancetime1.h" 


static void ADVANCE_TIM_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);	 // 设置中断组为0	
    NVIC_InitStructure.NVIC_IRQChannel = ADVANCE_TIM_IRQ; 		// 设置中断来源
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 // 设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  // 设置子优先级	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}


static void ADVANCE_TIM_GPIO_Config(void) 
{
  GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
  GPIO_InitStructure.GPIO_Pin =  ADVANCE_TIM_CH1_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
  GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);	
}



static void ADVANCE_TIM_Mode_Config(void)
{
 
	ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK,ENABLE); //开启定时器时钟,即内部时钟CK_INT=72M

	//时基结构体初始化:用于测量频率那么你的时基就需要比信号高
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period=ADVANCE_TIM_PERIOD;// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断	
	TIM_TimeBaseStructure.TIM_Prescaler= ADVANCE_TIM_PSC;// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 时钟分频因子 ,配置死区时间时需要用到	
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;	// 计数器计数模式,设置为向上计数		
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 重复计数器的值,没用到不用管
	TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);	// 初始化定时器

	//输入捕获结构体初始化 使用PWM输入模式时,需要占用两个捕获寄存器,一个测周期,另外一个测占空比
	TIM_ICInitTypeDef  TIM_ICInitStructure;
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;// 捕获通道IC1配置 ,选择捕获通道
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;// 设置捕获的边沿
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;// 设置捕获通道的信号来自于哪个输入通道,有直连和非直连两种
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;// 1分频,即捕获信号的每个有效边沿(上升沿)捕获
  TIM_ICInitStructure.TIM_ICFilter = 0x0;// 不滤波
  TIM_PWMIConfig(ADVANCE_TIM, &TIM_ICInitStructure);// 初始化PWM输入模式
	
  //直连与非直连区别仅仅是捕获寄存器1来捕获周期,2来捕获占空比。还是捕获寄存器2来捕获周期,1捕获占空比
  TIM_SelectInputTrigger(ADVANCE_TIM, TIM_TS_TI1FP1);// 选择输入捕获的触发信号:即捕获信号周期

	// 选择从模式: 即复位模式。 因为PWM输入模式时,从模式必须工作在复位模式,当捕获开始时,计数器CNT会被复位
  TIM_SelectSlaveMode(ADVANCE_TIM, TIM_SlaveMode_Reset);
  TIM_SelectMasterSlaveMode(ADVANCE_TIM,TIM_MasterSlaveMode_Enable); 
  TIM_ITConfig(ADVANCE_TIM, TIM_IT_CC1, ENABLE);// 使能捕获中断,这个中断针对的是主捕获通道(测量周期那个)
	TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);// 清除中断标志位
  TIM_Cmd(ADVANCE_TIM, ENABLE);// 使能高级控制定时器,计数器开始计数
}

void ADVANCE_TIM1_Init(void)
{
	ADVANCE_TIM_GPIO_Config();
	ADVANCE_TIM_NVIC_Config();
	ADVANCE_TIM_Mode_Config();		
}

ADVANCE_TIM_Mode_Config()函数中初始化了两个结构体,
因为是 PWM 输入模式,只能使用通道 1 和通道 2 ,假如我们使用的是通道 1 ,即 TI1
输入的 PWM 信号会被分成两路,分别是 TI1FP1 TI1FP2 ,两路都可以是触发信号。如
果选择 TI1FP1 为触发信号,那么 IC1 捕获到的是 PWM 信号的周期, IC2 捕获到的是占空
比 , 这 种 输 入 通 道 TI 和 捕获通道 IC 的映射 关系叫直连,输入捕获结构体的
TIM_ICSelection 要配置为 TIM_ICSelection_DirectTI 。如果选择 TI1FP2 为触发信号,则
IC2 捕获到的是周期, IC1 捕获到的是占空比,这种输入通道 TI 和捕获通道 IC 的映射关系
叫非直连,输入捕获结构体的 TIM_ICSelection 要配置为 TIM_ICSelection_IndirectTI 。有关
输入通道 TI 和捕获通道 IC 的具体映射关系见图 ,有直连和非直连两种。
__IO uint16_t IC2Value = 0;
__IO uint16_t IC1Value = 0;
__IO float DutyCycle = 0;
__IO float Frequency = 0;
void ADVANCE_TIM_IRQHandler(void)
{
  
  TIM_ClearITPendingBit(ADVANCE_TIM, TIM_IT_CC1);/* 清除中断标志位 */

  /* 获取输入捕获值 */
  IC1Value = TIM_GetCapture1(ADVANCE_TIM);
  IC2Value = TIM_GetCapture2(ADVANCE_TIM);
	
  // 注意:捕获寄存器CCR1和CCR2的值在计算占空比和频率的时候必须加1
	if (IC1Value != 0)
  {
    
    DutyCycle = (float)((IC2Value+1) * 100) / (IC1Value+1);/* 占空比计算 */
    Frequency = (72000000/(ADVANCE_TIM_PSC+1))/(float)(IC1Value+1);/* 频率计算 */
		printf("占空比:%0.2f%%   频率:%0.2fHz\n",DutyCycle,Frequency);
  }
  else
  {
    DutyCycle = 0;
    Frequency = 0;
  }
}
当捕获到 PWM 信号的第一个上升沿时,产生中断,计数器被复位,锁存到捕获寄存
IC1 IC2 的值都为 0 。当下降沿到来时, IC2 会捕获,对应的是占空比,但是会产生中
断。当捕获到第二个下降沿时, IC1 会捕获,对应的是周期,而且会再次进入中断,这个
时间就可以根据 IC1 IC2 的值计算出频率和占空比。有关 PWM 输入的时序见图?
中断复位函数中,我们获取输入捕获寄存器 CCR1 CCR2 寄存器中的值,当 CCR1
的值不为 0 时,说明有效捕获到了一个周期,然后计算出频率和占空比。在计算的时候
CCR1 CCR2 的值都必须要加 1 ,因为计数器是从 0 开始计数的

?

#include "stm32f10x.h"  
#include "led.h" 
#include "key.h"
#include "rcc.h"
#include "exti.h"
#include "systick.h"
#include "usart.h"
#include <stdio.h>
#include "basetime.h"
#include "advancetime.h"
#include "generaltime.h"
#include "advancetime1.h" 
#include "generaltime3.h"

/*
 采样率不能低于信号频率,不然采集不到,
 把通用定时器3产生100Khz占空比50的pwmPA6引脚接到高级定时器1输入捕获引脚PA8

*/

int main(void)
{
	
	USART_Config();
	GENERAL_TIM3_Init();//基本的事情配置输出100Khz占空比50信号
	ADVANCE_TIM1_Init();/* 高级定时器初始化 ,用户捕获PWM信号*/
	
  while (1){
	 
 }	
}



  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 01:27:45  更:2022-09-04 01:30:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:27:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码