[DemoCode下载] 如何使用 GPIO 外部中断功能和去抖动功能

[复制链接]
1855|6
 楼主| heisexingqisi 发表于 2024-2-19 22:58 | 显示全部楼层 |阅读模式
  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 the usage of GPIO external interrupt function and de-bounce function.
  5. *
  6. * SPDX-License-Identifier: Apache-2.0
  7. * [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2018 Nuvoton Technology Corp. All rights reserved.
  8. ******************************************************************************/
  9. #include <stdio.h>
  10. #include "NuMicro.h"


  11. /**
  12. * @brief       External INT024 IRQ
  13. *
  14. * @param       None
  15. *
  16. * [url=home.php?mod=space&uid=266161]@return[/url]      None
  17. *
  18. * [url=home.php?mod=space&uid=1543424]@Details[/url]     The External INT024 default IRQ, declared in startup_M031Series.s.
  19. */
  20. void EINT024_IRQHandler(void)
  21. {
  22.     /* To check if PA.6 external interrupt occurred */
  23.     if(PA->INTSRC & BIT6)
  24.     {
  25.         PA->INTSRC = BIT6;
  26.         printf("PA.6 EINT0 occurred.\n");
  27.     }

  28.     /* To check if PB.5 external interrupt occurred */
  29.     if(PB->INTSRC & BIT5)
  30.     {
  31.         PB->INTSRC = BIT5;
  32.         printf("PB.5 EINT0 occurred.\n");
  33.     }
  34. }

  35. /**
  36. * @brief       External INT135 IRQ
  37. *
  38. * @param       None
  39. *
  40. * @return      None
  41. *
  42. * @details     The External INT135 default IRQ, declared in startup_M031Series.s.
  43. */
  44. void EINT135_IRQHandler(void)
  45. {
  46.     /* To check if PA.7 external interrupt occurred */
  47.     if(PA->INTSRC & BIT7)
  48.     {
  49.         PA->INTSRC = BIT7;
  50.         printf("PA.7 EINT1 occurred.\n");
  51.     }

  52.     /* To check if PB.4 external interrupt occurred */
  53.     if(PB->INTSRC & BIT4)
  54.     {
  55.         PB->INTSRC = BIT4;
  56.         printf("PB.4 EINT1 occurred.\n");
  57.     }
  58. }

  59. void SYS_Init(void)
  60. {
  61.     /* Unlock protected registers */
  62.     SYS_UnlockReg();

  63.     /* Enable HIRC */
  64.     CLK->PWRCTL |= CLK_PWRCTL_HIRCEN_Msk;

  65.     /* Waiting for HIRC clock ready */
  66.     while((CLK->STATUS & CLK_STATUS_HIRCSTB_Msk) != CLK_STATUS_HIRCSTB_Msk);

  67.     /* Switch HCLK clock source to HIRC */
  68.     CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_HCLKSEL_Msk) | CLK_CLKSEL0_HCLKSEL_HIRC;
  69.     CLK->CLKDIV0 = (CLK->CLKDIV0 & ~CLK_CLKDIV0_HCLKDIV_Msk) | CLK_CLKDIV0_HCLK(1);

  70.     /* Set both PCLK0 and PCLK1 as HCLK/2 */
  71.     CLK->PCLKDIV = (CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2);

  72.     /* Switch UART0 clock source to HIRC */
  73.     CLK->CLKSEL1 = (CLK->CLKSEL1 & ~CLK_CLKSEL1_UART0SEL_Msk) | CLK_CLKSEL1_UART0SEL_HIRC;
  74.     CLK->CLKDIV0 = (CLK->CLKDIV0 & ~CLK_CLKDIV0_UART0DIV_Msk) | CLK_CLKDIV0_UART0(1);

  75.     /* Enable UART0 peripheral clock */
  76.     CLK->APBCLK0 |= CLK_APBCLK0_UART0CKEN_Msk;

  77.     /* Update System Core Clock */
  78.     /* User can use SystemCoreClockUpdate() to calculate PllClock, SystemCoreClock and CycylesPerUs automatically. */
  79.     SystemCoreClockUpdate();

  80.     /*----------------------------------------------------------------------*/
  81.     /* Init I/O Multi-function                                              */
  82.     /*----------------------------------------------------------------------*/
  83.     /* Set GPB multi-function pins for UART0 RXD and TXD */
  84.     SYS->GPB_MFPH = (SYS->GPB_MFPH & ~(SYS_GPB_MFPH_PB12MFP_Msk | SYS_GPB_MFPH_PB13MFP_Msk)) |
  85.                     (SYS_GPB_MFPH_PB12MFP_UART0_RXD | SYS_GPB_MFPH_PB13MFP_UART0_TXD);

  86.     /* Set PA multi-function pin for EINT0(PA.6) and EINT1(PA.7) */
  87.     SYS->GPA_MFPL = (SYS->GPA_MFPL & ~(SYS_GPA_MFPL_PA6MFP_Msk | SYS_GPA_MFPL_PA7MFP_Msk)) |
  88.                     (SYS_GPA_MFPL_PA6MFP_INT0 | SYS_GPA_MFPL_PA7MFP_INT1);

  89.     /* Set PB multi-function pin for EINT0(PB.5) and EINT1(PB.4) */
  90.     SYS->GPB_MFPL = (SYS->GPB_MFPL & ~(SYS_GPB_MFPL_PB5MFP_Msk | SYS_GPB_MFPL_PB4MFP_Msk)) |
  91.                     (SYS_GPB_MFPL_PB5MFP_INT0 | SYS_GPB_MFPL_PB4MFP_INT1);

  92.     /* Lock protected registers */
  93.     SYS_LockReg();
  94. }

  95. /*----------------------------------------------------------------------*/
  96. /* Init UART0                                                           */
  97. /*----------------------------------------------------------------------*/
  98. void UART0_Init(void)
  99. {
  100.     /* Reset UART0 */
  101.     SYS->IPRST1 |=  SYS_IPRST1_UART0RST_Msk;
  102.     SYS->IPRST1 &= ~SYS_IPRST1_UART0RST_Msk;

  103.     /* Configure UART0 and set UART0 baud rate */
  104.     UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__HIRC, 115200);
  105.     UART0->LINE = UART_WORD_LEN_8 | UART_PARITY_NONE | UART_STOP_BIT_1;
  106. }

  107. int main(void)
  108. {
  109.     /* Init System, IP clock and multi-function I/O. */
  110.     SYS_Init();

  111.     /* Init UART0 for printf */
  112.     UART0_Init();

  113.     printf("\n\nCPU [url=home.php?mod=space&uid=72445]@[/url] %d Hz\n", SystemCoreClock);
  114.     printf("+------------------------------------------------------------+\n");
  115.     printf("|    GPIO EINT0/EINT1 Interrupt and De-bounce Sample Code    |\n");
  116.     printf("+------------------------------------------------------------+\n\n");

  117.     /*-----------------------------------------------------------------------------------------------------*/
  118.     /* GPIO External Interrupt Function Test                                                               */
  119.     /*-----------------------------------------------------------------------------------------------------*/
  120.     printf("EINT0(PA.6 and PB.5) and EINT1(PA.7 and PB.4) are used to test interrupt\n");
  121.     printf("    PA.6 is falling edge trigger.\n");
  122.     printf("    PB.5 is rising edge trigger.\n");
  123.     printf("    PA.7 and PB.4 are both falling edge and rising edge trigger.\n");

  124.     /* Configure PA.6 as EINT0 pin and enable interrupt by falling edge trigger */
  125.     /* Configure PA.7 as EINT1 pin and enable interrupt by falling and rising edge trigger */
  126.     PA->MODE = (PA->MODE & ~(GPIO_MODE_MODE6_Msk | GPIO_MODE_MODE7_Msk)) |
  127.                ((GPIO_MODE_INPUT << GPIO_MODE_MODE6_Pos) | (GPIO_MODE_INPUT << GPIO_MODE_MODE7_Pos));

  128.     /* Configure interrupt mode of specified pin */
  129.     PA->INTTYPE = (PA->INTTYPE & ~(BIT6 | BIT7));       /* set PA6 and PA7 to edge trigger interrupt */
  130.     /* Enable interrupt function of specified pin */
  131.     PA->INTEN = (PA->INTEN & ~(BIT6<<GPIO_INTEN_RHIEN0_Pos)) |  /* PA.6 disable rising  edge trigger interrupt */
  132.                 (BIT6 | (BIT7<<GPIO_INTEN_RHIEN0_Pos) | BIT7);  /* PA.6 enable  falling edge trigger interrupt */
  133.     /* PA.7 enable  rising  edge trigger interrupt */
  134.     /* PA.7 enable  falling edge trigger interrupt */

  135.     /* Configure PB.5 as EINT0 pin and enable interrupt by rising edge trigger */
  136.     /* Configure PB.4 as EINT0 pin and enable interrupt by rising edge trigger */
  137.     PB->MODE = (PB->MODE & ~(GPIO_MODE_MODE5_Msk | GPIO_MODE_MODE4_Msk)) |
  138.                ((GPIO_MODE_INPUT << GPIO_MODE_MODE5_Pos) | (GPIO_MODE_INPUT << GPIO_MODE_MODE4_Pos));

  139.     /* Configure interrupt mode of specified pin */
  140.     PB->INTTYPE &= ~BIT5;   /* set PB5 to edge trigger interrupt */
  141.     /* Enable interrupt function of specified pin */
  142.     PB->INTEN = (PB->INTEN & ~(BIT5)) |                         /* PB.5 disable falling edge trigger interrupt */
  143.                 ((BIT5<<GPIO_INTEN_RHIEN0_Pos) | BIT4 | (BIT4<<GPIO_INTEN_RHIEN0_Pos));
  144.     /* PB.5 enable  rising  edge trigger interrupt */
  145.     /* PB.4 enable  falling edge trigger interrupt */
  146.     /* PB.4 enable  rising  edge trigger interrupt */

  147.     NVIC_EnableIRQ(EINT024_IRQn);
  148.     NVIC_EnableIRQ(EINT135_IRQn);

  149.     /* Enable interrupt de-bounce function and select de-bounce sampling cycle time is 1024 clocks of LIRC clock */
  150.     GPIO->DBCTL = GPIO_DBCTL_ICLKON_Msk | GPIO_DBCTL_DBCLKSRC_LIRC | GPIO_DBCTL_DBCLKSEL_1024;
  151.     PA->DBEN |= (BIT6 | BIT7);
  152.     PB->DBEN |= (BIT5 | BIT4);

  153.     /* Waiting for interrupts */
  154.     while(1);
  155. }


 楼主| heisexingqisi 发表于 2024-2-19 22:59 | 显示全部楼层
初始化设置:

使用 SYS_Init() 函数初始化系统时钟和 GPIO 多功能引脚。
初始化 UART0 以便后续打印调试信息。
外部中断处理函数:

定义了两个外部中断处理函数 EINT024_IRQHandler() 和 EINT135_IRQHandler(),分别处理外部中断 0 和外部中断 1。
在中断处理函数中,通过检查 PA->INTSRC 和 PB->INTSRC 寄存器来确定是哪个引脚触发了中断,并进行相应的处理。
主函数:

初始化系统和 UART0。
配置外部中断:
配置 PA.6 和 PB.5 为外部中断 0,PA.7 和 PB.4 为外部中断 1。
分别设置中断触发方式为下降沿、上升沿、双边沿。
开启相应的中断使能。
配置外部中断去抖动功能:
使能中断去抖动功能并设置去抖动采样周期为 1024 个 LIRC 时钟周期。
通过 NVIC_EnableIRQ() 函数开启外部中断的中断向量。
进入主循环等待中断事件的发生。
 楼主| heisexingqisi 发表于 2024-2-19 22:59 | 显示全部楼层
整体来说,这段代码实现了通过外部中断检测特定 GPIO 引脚的状态变化,并通过去抖动功能确保信号稳定性。当引脚状态发生变化时,通过中断处理函数进行相应的处理和响应。
对于高可靠性系统还是推荐用硬件去抖动方式,比如使用104电容。
 楼主| heisexingqisi 发表于 2024-2-27 21:09 | 显示全部楼层
内置的去抖动功能,真是强大。
xixi2017 发表于 2024-2-28 11:45 | 显示全部楼层
MCU设计者考虑的真全面。
LEDyyds 发表于 2024-2-28 20:28 | 显示全部楼层
去抖一般都是延时等待抖动消失吧
黑心单片机 发表于 2024-2-28 20:49 | 显示全部楼层
用延时来消抖吧
您需要登录后才可以回帖 登录 | 注册

本版积分规则

157

主题

2770

帖子

2

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