打印
[牛人杂谈]

ECAP获取正交编码器频率

[复制链接]
467|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     main.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
* [url=home.php?mod=space&uid=247401]@brief[/url]    Show how to use ECAP interface to get QEIA frequency
*
* [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2016 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#include <stdio.h>
#include "NuMicro.h"


#define PLL_CLOCK       192000000


/*---------------------------------------------------------------------------------------------------------*/
/* Global variables                                                                                        */
/*---------------------------------------------------------------------------------------------------------*/
uint32_t u32Status;
uint32_t u32IC0Hold;

void TMR0_IRQHandler(void)
{
    if(TIMER_GetIntFlag(TIMER0) == 1)
    {
        /* Clear Timer0 time-out interrupt flag */
        TIMER_ClearIntFlag(TIMER0);

        /*PA.0 gpio toggle */
        PA0 ^= 1;
    }
}

void ECAP0_IRQHandler(void)
{
    /* Get input Capture status */
    u32Status = ECAP_GET_INT_STATUS(ECAP0);

    /* Check input capture channel 0 flag */
    if((u32Status & ECAP_STATUS_CAPTF0_Msk) == ECAP_STATUS_CAPTF0_Msk)
    {
        /* Clear input capture channel 0 flag */
        ECAP_CLR_CAPTURE_FLAG(ECAP0, ECAP_STATUS_CAPTF0_Msk);

        /* Get input capture counter hold value */
        u32IC0Hold = ECAP0->HLD0;
    }

    /* Check input capture channel 1 flag */
    if((u32Status & ECAP_STATUS_CAPTF1_Msk) == ECAP_STATUS_CAPTF1_Msk)
    {
        /* Clear input capture channel 1 flag */
        ECAP_CLR_CAPTURE_FLAG(ECAP0, ECAP_STATUS_CAPTF1_Msk);
    }

    /* Check input capture channel 2 flag */
    if((u32Status & ECAP_STATUS_CAPTF2_Msk) == ECAP_STATUS_CAPTF2_Msk)
    {
        /* Clear input capture channel 2 flag */
        ECAP_CLR_CAPTURE_FLAG(ECAP0, ECAP_STATUS_CAPTF2_Msk);
    }

    /* Check input capture compare-match flag */
    if((u32Status & ECAP_STATUS_CAPCMPF_Msk) == ECAP_STATUS_CAPCMPF_Msk)
    {
        /* Clear input capture compare-match flag */
        ECAP_CLR_CAPTURE_FLAG(ECAP0,ECAP_STATUS_CAPCMPF_Msk);
    }

    /* Check input capture overflow flag */
    if((u32Status & ECAP_STATUS_CAPOVF_Msk) == ECAP_STATUS_CAPOVF_Msk)
    {
        /* Clear input capture overflow flag */
        ECAP_CLR_CAPTURE_FLAG(ECAP0,ECAP_STATUS_CAPOVF_Msk);
    }
}


void SYS_Init(void)
{
    /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */
    PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

    /* Enable external XTAL 12MHz clock */
    CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk);

    /* Waiting for external XTAL clock ready */
    CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk);

    /* Set core clock as PLL_CLOCK from PLL */
    CLK_SetCoreClock(PLL_CLOCK);

    /* Set PCLK0/PCLK1 to HCLK/2 */
    CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2);

    /* Enable UART module clock */
    CLK_EnableModuleClock(UART0_MODULE);

    /* Enable ECAP0 module clock */
    CLK_EnableModuleClock(ECAP0_MODULE);

    /* Enable QEI0 module clock */
    CLK_EnableModuleClock(QEI0_MODULE);

    /* Enable TIMER0 module clock */
    CLK_EnableModuleClock(TMR0_MODULE);

    /* Select UART module clock source */
    CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HXT, CLK_CLKDIV0_UART0(1));

    /* Select TMR0 module clock source */
    CLK_SetModuleClock(TMR0_MODULE, CLK_CLKSEL1_TMR0SEL_HXT, 0);

    /* Set GPB multi-function pins for UART0 RXD and TXD */
    SYS->GPB_MFPH &= ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk);
    SYS->GPB_MFPH |= (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);

    /* Set PA.10 for ECAP0_IC0*/
    SYS->GPA_MFPH = (SYS->GPA_MFPL & ~SYS_GPA_MFPH_PA10MFP_Msk) |SYS_GPA_MFPH_PA10MFP_ECAP0_IC0;

    /* Set PA multi-function pins for QEI0_A, QEI0_B, QEI0_INDEX */
    SYS->GPA_MFPL &= ~(SYS_GPA_MFPL_PA4MFP_Msk | SYS_GPA_MFPL_PA3MFP_Msk | SYS_GPA_MFPL_PA5MFP_Msk);
    SYS->GPA_MFPL |= (SYS_GPA_MFPL_PA4MFP_QEI0_A | SYS_GPA_MFPL_PA3MFP_QEI0_B | SYS_GPA_MFPL_PA5MFP_QEI0_INDEX);

}

void UART0_Init(void)
{

    /* Configure UART0 and set UART0 Baudrate */
    UART_Open(UART0, 115200);
}

void ECAP0_Init(void)
{
    /* Enable ECAP0*/
    ECAP_Open(ECAP0, ECAP_DISABLE_COMPARE);

    /* Select Reload function */
    ECAP_SET_CNT_CLEAR_EVENT(ECAP0, (ECAP_CTL1_CAP0RLDEN_Msk|ECAP_CTL1_CAP1RLDEN_Msk));

    /* Enable ECAP0 Input Channel 0*/
    ECAP_ENABLE_INPUT_CHANNEL(ECAP0, ECAP_CTL0_IC0EN_Msk);

    /* Enable ECAP0 source from IC0 */
    ECAP_SEL_INPUT_SRC(ECAP0, ECAP_IC0, ECAP_CAP_INPUT_SRC_FROM_CH);

    /* Select IC0 detect rising edge */
    ECAP_SEL_CAPTURE_EDGE(ECAP0, ECAP_IC0, ECAP_RISING_EDGE);

    /* Input Channel 0 interrupt enabled */
    ECAP_EnableINT(ECAP0, ECAP_CTL0_CAPIEN0_Msk);
}

void QEI0_Init(void)
{
    QEI_Open(QEI0,QEI_CTL_X4_FREE_COUNTING_MODE,0);
}

void Timer0_Init(void)
{
    /* Open Timer0 in periodic mode, enable interrupt and 1 interrupt tick per second */
    TIMER_Open(TIMER0,TIMER_PERIODIC_MODE,10000);
    TIMER_EnableInt(TIMER0);

    /* Enable Timer0 NVIC */
    NVIC_EnableIRQ(TMR0_IRQn);

}

int32_t main(void)
{
    uint32_t u32Hz=0, u32Hz_DET=0;

    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Init System, IP clock and multi-function I/O */
    SYS_Init();

    /* Lock protected registers */
    SYS_LockReg();

    /* Init UART0 for printf */
    UART0_Init();

    printf("\n");
    printf("+----------------------------------------------+\n");
    printf("|        M480 ECAP with QEI Sample Code        |\n");
    printf("+----------------------------------------------+\n");
    printf("\n");
    printf("  !! GPIO PA.0 toggle periodically    !!\n");
    printf("  !! Connect PA.0 --> PA.4(QEI0_A) !!\n\n");
    printf("     Press any key to start test\n\n");
    getchar();

    /* Initial ECAP0 function */
    ECAP0_Init();

    /* Initial QEI0 function */
    QEI0_Init();

    /* Initial Timer0 function */
    Timer0_Init();

    /* Configure PA.0 as output mode */
    GPIO_SetMode(PA, BIT0, GPIO_MODE_OUTPUT);

    /* Start Timer0 counting */
    TIMER_Start(TIMER0);

    /* Delay 200ms */
    CLK_SysTickDelay(200000);

    /* Init & clear ECAP interrupt status flags */
    u32Status = ECAP_GET_INT_STATUS(ECAP0);
    ECAP0->STATUS = u32Status;

    /* ECAP_CNT starts up-counting */
    ECAP_CNT_START(ECAP0);

    while(1)
    {
        if(u32Status != 0)
        {
            /* Input Capture status is changed, and get a new hold value of input capture counter */
            u32Status = 0;

            /* Calculate the IC0 input frequency */
            u32Hz_DET = (SystemCoreClock/2) / (u32IC0Hold + 1);

            if(u32Hz != u32Hz_DET)
            {
                /* If IC0 input frequency is changed, Update frequency */
                u32Hz = u32Hz_DET;
            }
            else
            {
                printf("\nECAP0_IC0 input frequency is %d (Hz),u32IC0Hold=0x%08x\n", u32Hz,u32IC0Hold);
                TIMER_Stop(TIMER0); //Disable timer Counting.
                break;
            }
        }

    }
    /* Disable External Interrupt */
    NVIC_DisableIRQ(ECAP0_IRQn);
    NVIC_DisableIRQ(TMR0_IRQn);

    /* Disable ECAP function */
    ECAP_Close(ECAP0);

    /* Disable Timer0 IP clock */
    CLK_DisableModuleClock(TMR0_MODULE);

    /* Disable ECAP IP clock */
    CLK_DisableModuleClock(ECAP0_MODULE);

    printf("\nExit ECAP sample code\n");

    while(1);
}



这段程序演示了如何使用NuMicro系列微控制器的ECAP(Enhanced Capture)接口和QEI(Quadrature Encoder Interface)接口来获取旋转编码器的输入频率。下面是主要功能和流程解析:

初始化和系统设置:

设置系统时钟和UART接口,配置用于调试输出的UART0。
启用和配置ECAP0、QEI0和TIMER0模块的时钟。
ECAP模块初始化:

打开ECAP0模块并禁用比较功能。
配置ECAP0的输入捕获通道(IC0),选择从通道输入源获取输入信号(这里与前一个例子不同)。
设置IC0检测上升沿触发,并启用IC0的输入捕获功能。
启用ECAP0的中断,用于处理捕获事件。
QEI模块初始化:

配置QEI0模块为X4自由计数模式,用于读取旋转编码器的计数值。
TIMER0定时器初始化:

配置TIMER0为周期模式,并启用定时器中断,每秒钟产生一次中断。
中断处理函数:

TMR0_IRQHandler():处理TIMER0定时器的中断事件,实现定时器中PA0引脚的周期性翻转。
ECAP0_IRQHandler():处理ECAP0模块的捕获事件,获取并处理输入捕获的状态和数据。

使用特权

评论回复
沙发
gejigeji521|  楼主 | 2024-7-13 19:21 | 只看该作者
主函数循环:

等待用户按下任意键开始测试。
初始化ECAP0、QEI0和TIMER0。
在循环中,通过检测ECAP0的捕获状态,获取旋转编码器输入的频率。计算公式与前一个例子类似:

一旦检测到输入频率变化,更新并打印新的频率值。
最终,通过禁用中断和关闭模块的方式结束测试。
这段程序允许您连接一个旋转编码器的A、B通道到PA.4和PA.3引脚,并通过ECAP0模块获取旋转编码器的输入频率,并通过UART输出显示。

使用特权

评论回复
板凳
gejigeji521|  楼主 | 2024-7-13 19:22 | 只看该作者
你了解正交编码器吗,获取它的频率可以用于什么知道吗?
正交编码器(Quadrature Encoder),简称QEI,是一种用于测量旋转或线性位置的设备。它通常由两个光电传感器组成,每个传感器位于旋转装置上,输出两个相位差90度的正交信号。这些信号被称为A相和B相。

获取正交编码器的频率可以用于以下几个方面:
位置测量: 正交编码器可以通过计数A相和B相信号的脉冲数来测量旋转的角度或线性位置。频率的变化反映了旋转速度或运动的速度。

速度测量: 通过对正交编码器的脉冲频率进行计数,可以实时测量旋转的速度或线性运动的速度。速度的变化可以通过频率的变化来表示。

方向感知: 正交编码器不仅提供了脉冲的数量,还可以通过A相和B相的相位关系来确定旋转的方向。这种信息对于控制系统中的方向判断非常重要。

闭环控制系统: 在闭环控制系统中,正交编码器的反馈可以用于校准电机或执行器的位置和速度,以实现精确的位置控制和运动控制。

机器人和自动化应用: 在机器人、CNC机床和自动化设备中,正交编码器通常用于跟踪和控制机器或工具的位置和运动。

总之,正交编码器的频率信息不仅用于测量位置和速度,还可以用于方向感知和精确的闭环控制,因此在许多工业和自动化应用中都有广泛的应用。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

172

主题

2194

帖子

8

粉丝