[牛人杂谈] ECAP获取正交编码器频率

[复制链接]
 楼主| gejigeji521 发表于 2024-7-13 19:20 | 显示全部楼层 |阅读模式
  1. /**************************************************************************//**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V3.00
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]    Show how to use ECAP interface to get QEIA frequency
  5. *
  6. * [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2016 Nuvoton Technology Corp. All rights reserved.
  7. *
  8. ******************************************************************************/
  9. #include <stdio.h>
  10. #include "NuMicro.h"


  11. #define PLL_CLOCK       192000000


  12. /*---------------------------------------------------------------------------------------------------------*/
  13. /* Global variables                                                                                        */
  14. /*---------------------------------------------------------------------------------------------------------*/
  15. uint32_t u32Status;
  16. uint32_t u32IC0Hold;

  17. void TMR0_IRQHandler(void)
  18. {
  19.     if(TIMER_GetIntFlag(TIMER0) == 1)
  20.     {
  21.         /* Clear Timer0 time-out interrupt flag */
  22.         TIMER_ClearIntFlag(TIMER0);

  23.         /*PA.0 gpio toggle */
  24.         PA0 ^= 1;
  25.     }
  26. }

  27. void ECAP0_IRQHandler(void)
  28. {
  29.     /* Get input Capture status */
  30.     u32Status = ECAP_GET_INT_STATUS(ECAP0);

  31.     /* Check input capture channel 0 flag */
  32.     if((u32Status & ECAP_STATUS_CAPTF0_Msk) == ECAP_STATUS_CAPTF0_Msk)
  33.     {
  34.         /* Clear input capture channel 0 flag */
  35.         ECAP_CLR_CAPTURE_FLAG(ECAP0, ECAP_STATUS_CAPTF0_Msk);

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

  39.     /* Check input capture channel 1 flag */
  40.     if((u32Status & ECAP_STATUS_CAPTF1_Msk) == ECAP_STATUS_CAPTF1_Msk)
  41.     {
  42.         /* Clear input capture channel 1 flag */
  43.         ECAP_CLR_CAPTURE_FLAG(ECAP0, ECAP_STATUS_CAPTF1_Msk);
  44.     }

  45.     /* Check input capture channel 2 flag */
  46.     if((u32Status & ECAP_STATUS_CAPTF2_Msk) == ECAP_STATUS_CAPTF2_Msk)
  47.     {
  48.         /* Clear input capture channel 2 flag */
  49.         ECAP_CLR_CAPTURE_FLAG(ECAP0, ECAP_STATUS_CAPTF2_Msk);
  50.     }

  51.     /* Check input capture compare-match flag */
  52.     if((u32Status & ECAP_STATUS_CAPCMPF_Msk) == ECAP_STATUS_CAPCMPF_Msk)
  53.     {
  54.         /* Clear input capture compare-match flag */
  55.         ECAP_CLR_CAPTURE_FLAG(ECAP0,ECAP_STATUS_CAPCMPF_Msk);
  56.     }

  57.     /* Check input capture overflow flag */
  58.     if((u32Status & ECAP_STATUS_CAPOVF_Msk) == ECAP_STATUS_CAPOVF_Msk)
  59.     {
  60.         /* Clear input capture overflow flag */
  61.         ECAP_CLR_CAPTURE_FLAG(ECAP0,ECAP_STATUS_CAPOVF_Msk);
  62.     }
  63. }


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

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

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

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

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

  76.     /* Enable UART module clock */
  77.     CLK_EnableModuleClock(UART0_MODULE);

  78.     /* Enable ECAP0 module clock */
  79.     CLK_EnableModuleClock(ECAP0_MODULE);

  80.     /* Enable QEI0 module clock */
  81.     CLK_EnableModuleClock(QEI0_MODULE);

  82.     /* Enable TIMER0 module clock */
  83.     CLK_EnableModuleClock(TMR0_MODULE);

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

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

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

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

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

  96. }

  97. void UART0_Init(void)
  98. {

  99.     /* Configure UART0 and set UART0 Baudrate */
  100.     UART_Open(UART0, 115200);
  101. }

  102. void ECAP0_Init(void)
  103. {
  104.     /* Enable ECAP0*/
  105.     ECAP_Open(ECAP0, ECAP_DISABLE_COMPARE);

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

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

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

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

  114.     /* Input Channel 0 interrupt enabled */
  115.     ECAP_EnableINT(ECAP0, ECAP_CTL0_CAPIEN0_Msk);
  116. }

  117. void QEI0_Init(void)
  118. {
  119.     QEI_Open(QEI0,QEI_CTL_X4_FREE_COUNTING_MODE,0);
  120. }

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

  126.     /* Enable Timer0 NVIC */
  127.     NVIC_EnableIRQ(TMR0_IRQn);

  128. }

  129. int32_t main(void)
  130. {
  131.     uint32_t u32Hz=0, u32Hz_DET=0;

  132.     /* Unlock protected registers */
  133.     SYS_UnlockReg();

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

  136.     /* Lock protected registers */
  137.     SYS_LockReg();

  138.     /* Init UART0 for printf */
  139.     UART0_Init();

  140.     printf("\n");
  141.     printf("+----------------------------------------------+\n");
  142.     printf("|        M480 ECAP with QEI Sample Code        |\n");
  143.     printf("+----------------------------------------------+\n");
  144.     printf("\n");
  145.     printf("  !! GPIO PA.0 toggle periodically    !!\n");
  146.     printf("  !! Connect PA.0 --> PA.4(QEI0_A) !!\n\n");
  147.     printf("     Press any key to start test\n\n");
  148.     getchar();

  149.     /* Initial ECAP0 function */
  150.     ECAP0_Init();

  151.     /* Initial QEI0 function */
  152.     QEI0_Init();

  153.     /* Initial Timer0 function */
  154.     Timer0_Init();

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

  157.     /* Start Timer0 counting */
  158.     TIMER_Start(TIMER0);

  159.     /* Delay 200ms */
  160.     CLK_SysTickDelay(200000);

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

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

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

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

  174.             if(u32Hz != u32Hz_DET)
  175.             {
  176.                 /* If IC0 input frequency is changed, Update frequency */
  177.                 u32Hz = u32Hz_DET;
  178.             }
  179.             else
  180.             {
  181.                 printf("\nECAP0_IC0 input frequency is %d (Hz),u32IC0Hold=0x%08x\n", u32Hz,u32IC0Hold);
  182.                 TIMER_Stop(TIMER0); //Disable timer Counting.
  183.                 break;
  184.             }
  185.         }

  186.     }
  187.     /* Disable External Interrupt */
  188.     NVIC_DisableIRQ(ECAP0_IRQn);
  189.     NVIC_DisableIRQ(TMR0_IRQn);

  190.     /* Disable ECAP function */
  191.     ECAP_Close(ECAP0);

  192.     /* Disable Timer0 IP clock */
  193.     CLK_DisableModuleClock(TMR0_MODULE);

  194.     /* Disable ECAP IP clock */
  195.     CLK_DisableModuleClock(ECAP0_MODULE);

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

  197.     while(1);
  198. }



这段程序演示了如何使用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的捕获状态,获取旋转编码器输入的频率。计算公式与前一个例子类似:
84796692632d1da14.png
一旦检测到输入频率变化,更新并打印新的频率值。
最终,通过禁用中断和关闭模块的方式结束测试。
这段程序允许您连接一个旋转编码器的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机床和自动化设备中,正交编码器通常用于跟踪和控制机器或工具的位置和运动。

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

本版积分规则

195

主题

2460

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部

195

主题

2460

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部