S32k3 eMios输入捕获(SAIC模式)测量信号周期、频率、占空比

8 篇文章 10 订阅

S32K3的PWM输出和输入捕获基本使用方式请参考:
S32K3 eMIOS使用介绍(PWM输出与输入捕获)——基于MCAL


本文进一步讨论输入捕获的使用,以SAIC(Single Action Input Capture)模式为例
图一
我们使用both edged triggering的方式来触发,即引脚的每一次边沿变化都会产生一个interrupt,AS2寄存器会记录下当前counter bus的值。

EB中上升沿、下降沿、双边沿触发方式的配置如下图:
图二

counter bus可以有多种选择,如图所示:
图三

EB中的配置
图四
其时钟来源为system clock,如图所示
图五
在Master Bus Prescaler中可以对系统时钟分频,最大可以16分频。
比如当前MCU的system clock为120MHz,16分频后则为7.5MHz,也就是说我们图一中的counter bus每产生一个counter所需的时间为7.5M分之一。
可以看到图四中我们设置的Default period为65535,即我们counter bus的一个测量周期的时间为65535乘以7.5M分之一(结果为0.008738s)
根据以上分析,若我们测量一个周期大于8.738ms的方波信号,我们counter bus的采样值就会溢出。而在nxp提供的SW32K3_RTD_4.4_2.0.0这版驱动中,并没有对溢出做处理,nxp的驱动代码如下:

static inline void Emios_Icu_Ip_SignalMeasurementWithSAICMode
(
    const uint8 instance,
    const uint8 hwChannel,
    boolean bOverflow
)
{
    uint16 activePulseWidth;
    uint16 IcuPeriod;
    uint16 Bus_Period;
    eMios_Icu_Ip_MeasType nMeasurement_property = eMios_Icu_Ip_ChState[instance][hwChannel].measurement;
    uint16 IcuTempA = (uint16)Emios_Icu_Ip_GetCaptureRegA(instance, hwChannel);

#ifdef EMIOS_ICU_IP_SIGNAL_MEASUREMENT_USES_SAIC_MODE
    uint16 Previous_Value;
    uint16 Pulse_Width;
#endif /* EMIOS_ICU_IP_SIGNAL_MEASUREMENT_USES_SAIC_MODE */
 
    Emios_Icu_Ip_SetActivation (instance, hwChannel, EMIOS_OPPOSITE_EDGES);

    if (EMIOS_ICU_MEASUREMENT_PENDING == eMios_Icu_Ip_aeInt_Counter[instance][hwChannel])
    {
        /* store the first value */
        eMios_Icu_Ip_u16aTimeStart[instance][hwChannel] = IcuTempA;
        eMios_Icu_Ip_aeInt_Counter[instance][hwChannel] = EMIOS_ICU_MEASUREMENT_DUTY;
    }
    else
    {
        Previous_Value = eMios_Icu_Ip_u16aTimeStart[instance][hwChannel];
        /* if first value is greater than the second value */
        if (IcuTempA < Previous_Value)
        {
            Bus_Period = (uint16)Emios_Icu_Ip_ReadCounterBus(instance, hwChannel);
            Pulse_Width = (Bus_Period - Previous_Value) + IcuTempA + 1U;
        }
        else
        {
            Pulse_Width = IcuTempA - Previous_Value;
        }

        /* HIGH TIME or LOW TIME measurement */
        if ((EMIOS_ICU_HIGH_TIME == nMeasurement_property) ||   \
            (EMIOS_ICU_LOW_TIME == nMeasurement_property)
           )
        {
            activePulseWidth = Pulse_Width;
            /* clear to measure next LOW/HIGH pulse */
            eMios_Icu_Ip_aeInt_Counter[instance][hwChannel] = EMIOS_ICU_MEASUREMENT_PENDING;
            Emios_Icu_Ip_SignalMeasurementStore(instance, hwChannel, activePulseWidth, (uint16)0U, bOverflow);
        }
        /* Duty Cycle */
        else
        {
            /* DUTYCYCLE or PERIOD measurement */
            if (EMIOS_ICU_MEASUREMENT_DUTY == eMios_Icu_Ip_aeInt_Counter[instance][hwChannel])
            {
                eMios_Icu_Ip_u16aCapturedActivePulseWidth[instance][hwChannel] = Pulse_Width;
                eMios_Icu_Ip_aeInt_Counter[instance][hwChannel] = EMIOS_ICU_MEASUREMENT_PERIOD;
                if(eMios_Icu_Ip_ChState[instance][hwChannel].callback != NULL_PTR)
                {
                    eMios_Icu_Ip_ChState[instance][hwChannel].callback(eMios_Icu_Ip_ChState[instance][hwChannel].callbackParam, bOverflow);
                }
            }
            else
            {
                /* eMios_Icu_Ip_aeInt_Counter is for period */
                IcuPeriod = eMios_Icu_Ip_u16aCapturedActivePulseWidth[instance][hwChannel] + Pulse_Width;
                activePulseWidth = eMios_Icu_Ip_u16aCapturedActivePulseWidth[instance][hwChannel];
                
                /* set to Duty to find active pulse width next time */
                eMios_Icu_Ip_aeInt_Counter[instance][hwChannel] = EMIOS_ICU_MEASUREMENT_DUTY;
                if (EMIOS_ICU_DUTY_CYCLE == nMeasurement_property)
                {
                    Emios_Icu_Ip_SignalMeasurementStore(instance, hwChannel, activePulseWidth, IcuPeriod, bOverflow);
                }
                else if (EMIOS_ICU_PERIOD_TIME == nMeasurement_property)
                {
                    Emios_Icu_Ip_SignalMeasurementStore(instance, hwChannel, (uint16)0U, IcuPeriod, bOverflow);
                }
                else
                {
                    /**/
                }
            }
            /* store for next time */
            eMios_Icu_Ip_u16aTimeStart[instance][hwChannel] = IcuTempA;
        }
    }
}
```c
在这里插入代码片

如下图所示:在这里插入图片描述

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
s32k312是一款NXP公司的汽车MCU,而emios是其内置的一个模块,用于实现高级定时器、PWM、输入捕获和输出比较等功能。emios捕获功能可以用于测量外部信号频率占空比等参数,常用于汽车电子中的发动机控制、电机控制等场景。 在s32k312中,使用emios进行输入捕获的步骤如下: 1. 配置emios模块为输入捕获模式; 2. 配置捕获通道的输入引脚和触发条件; 3. 在中断服务函数中读取捕获寄存器的值,计算出捕获的参数值。 例如,以下代码实现了使用emios通道0进行输入捕获,并在中断服务函数中打印出捕获的频率占空比: ```c void emios_input_capture_init(void) { EMIOS.MCR.B.MDIS = 1; // 禁止emios模块 EMIOS.MCR.B.GPRE = 0; // 设置时钟分频系数为1 EMIOS.MCR.B.GPREN = 1; // 使能时钟分频 EMIOS.CH[0].CCR.B.MODE = 0x10; // 设置通道0为输入捕获模式 EMIOS.CH[0].CCR.B.UCPRE = 0; // 设置上升沿计数器的分频系数为1 EMIOS.CH[0].CCR.B.UCPREN = 1; // 使能上升沿计数器的分频 EMIOS.CH[0].CCR.B.FREN = 1; // 使能捕获寄存器的FIFO EMIOS.CH[0].CCR.B.FCAP = 1; // 捕获寄存器的FIFO模式为一次性捕获 EMIOS.CH[0].CCR.B.EDPOL = 0; // 设置上升沿触发 EMIOS.CH[0].CCR.B.EDSEL = 0; // 设置上升沿触发 EMIOS.CH[0].CCR.B.BSL = 0x01; // 设置输入引脚为通用输入引脚0 EMIOS.MCR.B.MDIS = 0; // 使能emios模块 } void emios_input_capture_isr(void) { uint32_t capture_value = EMIOS.CH[0].CADR.R; // 读取捕获寄存器的值 float frequency = (float)EMIOS_CLOCK_FREQUENCY / capture_value; // 计算频率 float duty_cycle = (float)EMIOS.CH[0].CBDR.R / capture_value; // 计算占空比 printf("Frequency: %f Hz, Duty Cycle: %f%%\n", frequency, duty_cycle * 100); } int main(void) { emios_input_capture_init(); EMIOS.CH[0].CCR.B.FEN = 1; // 使能通道0的中断 EMIOS.CH[0].CCR.B.EN = 1; // 启动通道0 while (1); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值