S32K1XX_基于PIT定时器中断的PWM采集

提及到PWM的采集,我会想到K3里面的EMIOS模块,用起来较为方便,且节省资源,待完成K1XX系列芯片的介绍,后续会继续更新K3的介绍。
基于K144芯片的PWM采集,在此介绍一种基于PIT定时器中断的采集方法。

PWM采集思路

采集即需要采样,可以定时去采集输入的波形,只需要采集到一个PWM周期内的高低电平的持续时间,就可以得出周期,频率和正负占空比。关于PWM输入信号的采集,我们可以用到单片机的数字输入采集功能,就可以采集到高低电平,关于时间的计算,可以借助到定时器的计时功能,但是需要定时器的去采集,就需要定义采集的频率,采集的频率要尽可能的大,这样计算出来的采集的频率与占空比才会尽量的准确。

在这里插入图片描述

如果采样的频率较低,PWM的高低电平切换时,就会有较大误差,这样就会导致计算出来的值有较大误差
在这里插入图片描述
同时,也可能间隔一个甚至多个周期才会采集到高低跳变的情况,这也会导致计算有误
在这里插入图片描述
同时也有可能一直采集到高或者采集到低。
在这里插入图片描述
综上,总之采集频率要尽可能的大,采集频率越大,计算出的值越准确。

软件流程

1、使用PIT模块,最小的1个计数单位周期触发中断,实际根据具体情况拟定,会定义一个CNT进行自加,同时会去采集一次输入引脚的状态。
2、当前一个周期采集的电平状态与当前电平状态相反时,即不同时,就需要需要判定当前采集到的是高电平还是低电平,如果采集到的是高电平,则是上升沿,如果是低电平,则是下降沿
在这里插入图片描述
在这里插入图片描述
3、如果采集到上升沿,我们就可以知道低电平的持续时间,低电平的持续时间 = 采样周期 * 采样次数。
采样周期为定时器中断触发周期,采样次数为CNT的计数。当得到采样次数后,就需要把CNT清0,就下继续下一次计数采集了。
同理,如果采集到下降沿,就可以计算出高电平的持续时间
4、在定义低电平时间变量高电平时间变量 时,需要初始化为0。当高低电平的时间变量都被CNT赋值了,即高低电平的持续时间都不为0,代表已经采样了一个周期,我们就可以知道PWM周期、频率和周期。
周期 = (低电平时间 + 高电平时间)采样周期 * 采样次数
频率 = 1/周期
正占空比 = 高电平时间 / (低电平时间 + 高电平时间)
负占空比 = 低电平时间 / (低电平时间 + 高电平时间)

5、计算完成之后,需要
把高电平时间和低电平时间清0*,将继续下一个周期的采集
在这里插入图片描述

代码

以下是代码部分

#include "sdk_project_config.h"

#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include"CLOCK_S32K1xx.h"
#include "interrupt_manager.h"
#include"lpit_driver.h"

extern void LPIT0_Ch0_IRQHandler(void);

static int Cnt_125ns= 0;
unsigned int old_sta = 0;
unsigned int new_sta = 0;
unsigned int up_time = 0;
unsigned int down_time = 0;
double period = 0;
double fre= 0;
double  Pos_duty= 0;
double  Neg_duty= 0;
double cali_period = 0 ;
int main(void)
{
    double temp = (double)lpit1_ChnConfig0.period;  //计算采样时间周期
    cali_period =temp/ 8000000.0;  //周期 单位S
    CLOCK_SYS_Init(g_clockManConfigsArr,   CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
    CLOCK_SYS_UpdateConfiguration(0U, 1);    // 时钟初始化

    PINS_DRV_Init(NUM_OF_CONFIGURED_PINS0, g_pin_mux_InitConfigArr0);      //GPIO初始化

    LPIT_DRV_Init(0,&lpit1_InitConfig);                         //LPIT初始化
    LPIT_DRV_InitChannel(0,0,&lpit1_ChnConfig0);    //配置计数模式,定时时间
    LPIT_DRV_StartTimerChannels(0, (1 << 0));         //启动计数
    LPIT_DRV_EnableTimerChannelInterrupt(0,1<<0);   //允许定时器生成中断

    while(1)
    {

    }
}


void LPIT0_Ch0_IRQHandler(void)
{
	LPIT0->MSR  = 1 ;       /* 也可以用 LPIT_DRV_ClearInterruptFlagTimerChannels(0, (1 << 0)); */       /*  清除中断响应标志位  */
	Cnt_125ns++;            //计数单位自加,
	old_sta = new_sta;     //获取上一个采集周期的电平状态
	new_sta = (PTC->PDIR >> 14) & 0X01;     //获取当前采集的电平状态
	if(old_sta != new_sta)     //当上一个采样周期的电平状态与当前的采集电平状态不符合,则有跳变沿产生
	{
		if(new_sta == 1) //如果采集到高电平,则此处为上升沿
		{
			down_time = Cnt_125ns;		//计算低电平时间
			Cnt_125ns = 0;                  //低电平时间已经得到,计数清0 ,下一个周期继续计数
		}
		else      //如果采集到低电平,则此处为下升沿
		{
			up_time = Cnt_125ns;		//计算高电平时间
			Cnt_125ns = 0;		             //高电平时间已经得到,计数清0 ,下一个周期继续计数
		}
	}
	if(up_time > 0 && down_time > 0)   //当高低电平的时间都已经得到,就可以计算了
	{

		Pos_duty = (double)up_time / ((double)up_time + (double)down_time) * 100;             //正占空比
		Neg_duty= (double)down_time / ((double)up_time + (double)down_time) * 100;        //负占空比

		period =(((double)up_time + (double)down_time) ) * cali_period;
		fre = (double)1.0/period;
		up_time = 0;        //高电平时间清0
		down_time = 0;    //低电平时间清0
	}
    if(Cnt_125ns > 8000000/lpit1_ChnConfig0.period) //超过1S钟未检测到跳变沿,PWM频率小于1HZ,则一直为高电平或者低电平
    {
    	period = 0;
    	fre = 0;
    	if(new_sta == 1 )
    	{
    		Pos_duty = 100;
    		Neg_duty = 0.0000;
    	}
    	else
    	{
    		Pos_duty = 0.0000;
    		Neg_duty = 100;
    	}
    }
}

测试结果

采用外部设备输出PWM信号,采样出来的值与预期符合。
在这里插入图片描述

在这里插入图片描述

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值