捕获多路PWM信号的周期、频率、占空比

该文介绍了一种使用AT32F403单片机的多路外部中断EXTI和1个定时器来同时检测多个PWM信号周期、占空比和频率的方法。通过设置外部中断对上升沿和下降沿进行处理,结合定时器溢出次数计算高电平和低电平时间,进而得到占空比和频率。代码示例展示了对两路PWM的配置和处理过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

做项目时需要测量六路PWM的占空比,在网上看到有用定时器输入捕获的做法,在这里我用多路外部中断EXTI和1个定时器的方式来完成,可同时检测多个pwm信号的周期、占空比、频率,实现原理比较简单

本人使用的单片机芯片型号是AT32F403

有纰漏请指出,转载请说明。

学习交流请发邮件 1280253714@qq.com

代码:

pwmIc.h

#ifndef __PWM_IC_H
#define __PWM_IC_H

#include "includes.h"

#define	PWM_EXTI_INT_BITS	0x0000000C		//把当前的中断使能位先暂存在pwmExtiIntBits里

#define PWM1_GPIO_PIN           GPIO_Pins_2
#define PWM1_GPIO_PORT          GPIOA
#define PWM1_GPIO_CLK           RCC_APB2PERIPH_GPIOA

#define PWM2_GPIO_PIN           GPIO_Pins_3
#define PWM2_GPIO_PORT          GPIOA
#define PWM2_GPIO_CLK           RCC_APB2PERIPH_GPIOA

#define		PWM_HIGH	1
#define		PWM_LOW		0

typedef struct pwm_s{
	bool state;
	u8 	pwmNum;
	u16	ovHighTimes;	//	pwm高电平的定时器溢出次数
	u16	ovLowTimes;		
	u16 riseCnt;		//	上升沿时读取到的定时器的CNT寄存器值
	u16 fallCnt;
	u32 highTime;		//	高电平的总时长,单位:us	
	u32	lowTime;
	u32	period;			//	周期,单位:us
	float dutyCycle;	//	25%占空比时对应0.25
	float freq;			//	频率,周期为1000us,对应频率为1000Hz
	
} PWM_S;

extern PWM_S pwm1;

void PWM_IC_Init(void);

#endif

pwmIc.c 

#include "includes.h"

PWM_S pwm1;
PWM_S pwm2;

static void pwmIcInit(void)
{
	pwm1.state = PWM_LOW;
	pwm2.state = PWM_LOW;
}

void PWM_IC_Init(void)
{
	pwmIcInit();
	GPIO_InitType  GPIO_InitStruct;
	EXTI_InitType  EXTI_InitStruct;
	NVIC_InitType NVIC_InitStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitStruct.NVIC_IRQChannel = EXTI2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	
	RCC_APB2PeriphClockCmd(PWM1_GPIO_CLK, ENABLE);	
	GPIO_InitStruct.GPIO_Pins = PWM1_GPIO_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;		
	GPIO_Init(PWM1_GPIO_PORT, &GPIO_InitStruct);	
	
	RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_AFIO, ENABLE);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinsSource2);
	
	EXTI_InitStruct.EXTI_Line = EXTI_Line2;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStruct.EXTI_LineEnable = ENABLE;
	EXTI_Init(&EXTI_InitStruct);	
		
	//
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitStruct.NVIC_IRQChannel = EXTI3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	
	RCC_APB2PeriphClockCmd(PWM2_GPIO_CLK, ENABLE);	
	GPIO_InitStruct.GPIO_Pins = PWM2_GPIO_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;		
	GPIO_Init(PWM2_GPIO_PORT, &GPIO_InitStruct);	
	
	RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_AFIO, ENABLE);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinsSource3);
		
	EXTI_InitStruct.EXTI_Line = EXTI_Line3;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStruct.EXTI_LineEnable = ENABLE;
	EXTI_Init(&EXTI_InitStruct);	
}

static void pwmExtiProc(PWM_S *pwmx, u8 Line)
{
	if ( PWM_HIGH == pwmx->state ){	//刚进入高电平
		if ( pwmx->fallCnt > pwmx->riseCnt ){
			pwmx->highTime = pwmx->ovHighTimes * 1000 + (pwmx->fallCnt - pwmx->riseCnt);
		} else {
			pwmx->highTime = pwmx->ovHighTimes * 1000 - (pwmx->riseCnt - pwmx->fallCnt);
		}
		pwmx->riseCnt = TMR5->CNT;
		if ( pwmx->riseCnt > pwmx->fallCnt ){
			pwmx->lowTime = pwmx->ovLowTimes * 1000 + (pwmx->riseCnt - pwmx->fallCnt);
		} else {
			pwmx->lowTime = pwmx->ovLowTimes * 1000 - (pwmx->fallCnt - pwmx->riseCnt);
		}

		pwmx->period = pwmx->highTime + pwmx->lowTime;
		pwmx->dutyCycle = ((float)pwmx->highTime)/((float)pwmx->period);
		pwmx->freq = (1 / (float)pwmx->period) * 1000000;
		
		EXTI->RTRSEL &= ~bit(Line);	//下降沿触发
		EXTI->FTRSEL |=  bit(Line);
		pwmx->ovHighTimes = 0;
		pwmx->ovLowTimes  = 0;
		pwmx->state = PWM_LOW;
		
	} else {
		EXTI->FTRSEL &= ~bit(Line);	//上升沿触发
		EXTI->RTRSEL |=  bit(Line);
		pwmx->state = PWM_HIGH;
		pwmx->fallCnt = TMR5->CNT;
	}
}


void EXTI2_IRQHandler (void)
{
	EXTI->INTEN &= ~PWM_EXTI_INT_BITS;	//失能所有pwm信号对应的中断
	pwmExtiProc(&pwm1,2);		
	EXTI->PND = EXTI_Line2;				//清除EXTI_Line2中断标志位
	EXTI->INTEN |= PWM_EXTI_INT_BITS;	//使能所有pwm信号对应的中断
}

void EXTI3_IRQHandler (void)
{
	EXTI->INTEN &= ~PWM_EXTI_INT_BITS;	//失能所有pwm信号对应的中断
	pwmExtiProc(&pwm2,3);
	EXTI->PND = EXTI_Line3;
	EXTI->INTEN |= PWM_EXTI_INT_BITS;	//使能所有pwm信号对应的中断
}

static void pwmTmrProc(PWM_S *pwmx)
{
	if ( PWM_HIGH == pwmx->state ){
		pwmx->ovLowTimes++;		//	实际上此时是高电平状态
	} else {
		pwmx->ovHighTimes++;	
	}	
}

//定时器设置为1ms进一次中断
void TMR5_GLOBAL_IRQHandler()
{
	if ( TMR_GetINTStatus( TMR5, TMR_INT_Overflow) != RESET ) 
	{		
		pwmTmrProc(&pwm1);
		pwmTmrProc(&pwm2);
		TMR_ClearITPendingBit(TMR5 , TMR_INT_Overflow);  		 
	}	
}

main函数只需添加初始化PWM_IC_Init();

实验结果:

37.5%和50%的占空比

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值