[活动] 极海APM32F411V开发板评测 按键、串口、定时器简测

[复制链接]
 楼主| lemonhub 发表于 2024-5-6 20:14 | 显示全部楼层 |阅读模式
本帖最后由 lemonhub 于 2024-5-6 20:14 编辑

极海APM32F411V开发板评测 按键、串口、定时器简测
串口简测
从数据手册可以看出,APM32F411共有6个USART串口。
apm32-uart-01.jpg
apm32-uart-02.jpg
apm32-uart-03.jpg

结合官方例程和STM32的经验,对APM32进行串口接收中断初始化。
  1. #include "main.h"
  2. #include "Bsp_Usart.h"

  3. #define DATA_BUF_SIZE       (32)
  4. /** USART1 receive buffer*/
  5. uint8_t rxDataBufUSART1[DATA_BUF_SIZE] = {0};

  6. uint32_t rxCountUSART1 = 0;
  7. /*!
  8. * <a href="home.php?mod=space&uid=247401" target="_blank">@brief</a>       Delay
  9. *
  10. * @param       count:  delay count
  11. *
  12. * @retval      None
  13. */
  14. void Delay(uint32_t count)
  15. {
  16.     volatile uint32_t delay = count;
  17.     while(delay--);
  18. }

  19. /*!
  20. * [url=home.php?mod=space&uid=247401]@brief[/url]       USARTS Initialization
  21. *
  22. * @param       None
  23. *
  24. * @retval      None
  25. */
  26. void USART1_Init(void)
  27. {
  28.     GPIO_Config_T GPIO_configStruct;
  29.     GPIO_ConfigStructInit(&GPIO_configStruct);
  30.     USART_Config_T usartConfigStruct;

  31.     /*使能GPIO时钟*/
  32.     RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
  33.    
  34.     /*连接PA9至USART1_TX*/
  35.     GPIO_ConfigPinAF(GPIOA,GPIO_PIN_SOURCE_9, GPIO_AF_USART1);
  36.     /* 配置PA9 USART1_TX 推拉模式 */
  37.     GPIO_configStruct.mode = GPIO_MODE_AF;
  38.     GPIO_configStruct.pin = GPIO_PIN_9;
  39.     GPIO_configStruct.speed = GPIO_SPEED_50MHz;
  40.     GPIO_Config(GPIOA, &GPIO_configStruct);
  41.    
  42.    /*连接PA10至USART1_RX*/
  43.     GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_10,GPIO_AF_USART1);
  44.     /* 配置PA10 USART1_RX 推拉模式 */
  45.     GPIO_configStruct.mode = GPIO_MODE_AF;
  46.     GPIO_configStruct.pin = GPIO_PIN_10;
  47.     GPIO_Config(GPIOA, &GPIO_configStruct);
  48.    
  49.     /*使能USART1时钟*/
  50.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);

  51.     usartConfigStruct.baudRate = 115200;
  52.     usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
  53.     usartConfigStruct.mode = USART_MODE_TX_RX;
  54.     usartConfigStruct.parity = USART_PARITY_NONE;
  55.     usartConfigStruct.stopBits = USART_STOP_BIT_1;
  56.     usartConfigStruct.wordLength = USART_WORD_LEN_8B;
  57.     USART_Config(USART1, &usartConfigStruct);

  58.     /* 使能USART1 */
  59.     USART_Enable(USART1);
  60.     Delay(0x7FFF);//例程中进行了延时

  61.     /* 配置USART1中断 */
  62.     USART_EnableInterrupt(USART1, USART_INT_RXBNE);//接收中断
  63.     USART_ClearStatusFlag(USART1, USART_FLAG_RXBNE);//清楚中断标志位
  64.     NVIC_EnableIRQRequest(USART1_IRQn,1,0);
  65. }


  66. /*!
  67. * [url=home.php?mod=space&uid=247401]@brief[/url]       This function handles USART1 RX interrupt Handler
  68. *
  69. * @param       None
  70. *
  71. * @retval      None
  72. *
  73. * <a href="home.php?mod=space&uid=536309" target="_blank">@NOTE</a>        This function need to put into  void USART1_IRQHandler(void)
  74. */
  75. void  USART_Receive_Isr(void)
  76. {
  77.     /* USART1 Recieve Data */
  78.     if(USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == SET)
  79.     {
  80.         rxDataBufUSART1[rxCountUSART1++] = (uint8_t)USART_RxData(USART1);
  81.     }

  82. }

  83. void USART_Write(USART_T* usart,uint8_t *dat,uint32_t count)
  84. {
  85.     while(count--)
  86.     {
  87.         while(USART_ReadStatusFlag(usart, USART_FLAG_TXBE) == RESET);//在接收空闲时,再发送
  88.             USART_TxData(usart, *dat++);
  89.         //Delay(0x5FFFF);//例程中有,但去掉后,少量发送暂时未发现影响
  90.     }   
  91. }


  92. /*!
  93. * @brief        This function handles USART1 RX interrupt Handler
  94. *
  95. * @param        None
  96. *
  97. * @retval       None
  98. *
  99. * @note
  100. */
  101. void USART1_IRQHandler(void)
  102. {
  103.     USART_Receive_Isr();
  104. }

按键检测
按键代码直接迁移了例程部分,通过原理图可看出,当按下时,引脚状态为0。
apm32-key-01.jpg
  1. #include "main.h"
  2. #include "Bsp_Key.h"

  3. #define BUTTONn                          2

  4. /**
  5. * @brief Key1 push-button
  6. */
  7. #define KEY1_BUTTON_PIN                   GPIO_PIN_1
  8. #define KEY1_BUTTON_GPIO_PORT             GPIOA
  9. #define KEY1_BUTTON_GPIO_CLK              RCM_AHB1_PERIPH_GPIOA
  10. #define KEY1_BUTTON_EINT_LINE             EINT_LINE_1
  11. #define KEY1_BUTTON_EINT_PORT_SOURCE      SYSCFG_PORT_GPIOA
  12. #define KEY1_BUTTON_EINT_PIN_SOURCE       SYSCFG_PIN_1
  13. #define KEY1_BUTTON_EINT_IRQn             EINT1_IRQn
  14. /**
  15. * @brief Key2 push-button
  16. */
  17. #define KEY2_BUTTON_PIN                   GPIO_PIN_0
  18. #define KEY2_BUTTON_GPIO_PORT             GPIOA
  19. #define KEY2_BUTTON_GPIO_CLK              RCM_AHB1_PERIPH_GPIOA
  20. #define KEY2_BUTTON_EINT_LINE             EINT_LINE_0
  21. #define KEY2_BUTTON_EINT_PORT_SOURCE      SYSCFG_PORT_GPIOA
  22. #define KEY2_BUTTON_EINT_PIN_SOURCE       SYSCFG_PIN_0
  23. #define KEY2_BUTTON_EINT_IRQn             EINT0_IRQn


  24. #define BUTTONn                          2

  25. GPIO_T* BUTTON_PORT[BUTTONn] = {KEY1_BUTTON_GPIO_PORT, KEY2_BUTTON_GPIO_PORT};

  26. const uint16_t BUTTON_PIN[BUTTONn] = {KEY1_BUTTON_PIN, KEY2_BUTTON_PIN};

  27. const uint32_t BUTTON_CLK[BUTTONn] = {KEY1_BUTTON_GPIO_CLK, KEY2_BUTTON_GPIO_CLK};

  28. const EINT_LINE_T BUTTON_EINT_LINE[BUTTONn] = {KEY1_BUTTON_EINT_LINE, KEY2_BUTTON_EINT_LINE};

  29. const SYSCFG_PORT_T BUTTON_PORT_SOURCE[BUTTONn] = {KEY1_BUTTON_EINT_PORT_SOURCE, KEY2_BUTTON_EINT_PORT_SOURCE};

  30. const SYSCFG_PIN_T BUTTON_PIN_SOURCE[BUTTONn] = {KEY1_BUTTON_EINT_PIN_SOURCE, KEY2_BUTTON_EINT_PIN_SOURCE};

  31. const IRQn_Type BUTTON_IRQn[BUTTONn] = {KEY1_BUTTON_EINT_IRQn, KEY2_BUTTON_EINT_IRQn};


  32. /*!
  33. * @brief       Configures Button GPIO and EINT Line.
  34. *
  35. * @param       Button: Specifies the Button to be configured.
  36. *              This parameter can be one of following parameters:
  37. *              <a href="home.php?mod=space&uid=2817080" target="_blank">@ARG</a> BUTTON_KEY1: Key1 Push Button
  38. *              [url=home.php?mod=space&uid=2817080]@ARG[/url] BUTTON_KEY2: Key2 Push Button
  39. * @param       Button_Mode: Specifies Button mode.
  40. *              This parameter can be one of following parameters:
  41. *              [url=home.php?mod=space&uid=2817080]@ARG[/url] BUTTON_MODE_GPIO: Button will be used as simple IO
  42. *              @arg BUTTON_MODE_EINT: Button will be connected to EINT line
  43. *                   with interrupt generation capability
  44. *
  45. * @retval      None
  46. */
  47. void APM_PBInit(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode)
  48. {
  49.     GPIO_Config_T     GPIO_configStruct;
  50.     EINT_Config_T     EINT_configStruct;

  51.     /* Enable the BUTTON Clock */
  52.     RCM_EnableAHB1PeriphClock(BUTTON_CLK[Button]);

  53.     /* Configure Button pin as input floating */
  54.     GPIO_ConfigStructInit(&GPIO_configStruct);
  55.     GPIO_configStruct.mode = GPIO_MODE_IN;
  56.     GPIO_configStruct.pin = BUTTON_PIN[Button];
  57.     GPIO_configStruct.pupd  = GPIO_PUPD_UP;
  58.     GPIO_Config(BUTTON_PORT[Button], &GPIO_configStruct);

  59.     if (Button_Mode == BUTTON_MODE_EINT)
  60.     {
  61.         /* Enable the SYSCFG Clock */
  62.         RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);

  63.         /* Connect Button EINT Line to Button GPIO Pin */
  64.         SYSCFG_ConfigEINTLine(BUTTON_PORT_SOURCE[Button], BUTTON_PIN_SOURCE[Button]);

  65.         /* Configure Button EINT line */
  66.         EINT_configStruct.line = BUTTON_EINT_LINE[Button];
  67.         EINT_configStruct.mode = EINT_MODE_INTERRUPT;
  68.         EINT_configStruct.trigger = EINT_TRIGGER_FALLING;
  69.         EINT_configStruct.lineCmd = ENABLE;
  70.         EINT_Config(&EINT_configStruct);

  71.         /* Enable and set Button EINT Interrupt to the lowest priority */
  72.         NVIC_EnableIRQRequest(BUTTON_IRQn[Button], 0x0f, 0x0f);
  73.     }
  74. }
  75. /*!
  76. * @brief       Returns the selected Button state.
  77. *
  78. * @param       Button: Specifies the Button to be configured.
  79. *              This parameter can be one of following parameters:
  80. *              @arg BUTTON_KEY1: Key1 Push Button
  81. *              @arg BUTTON_KEY2: Key2 Push Button
  82. *
  83. * @retval      The Button GPIO pin value.
  84. */
  85. uint32_t APM_PBGetState(Button_TypeDef Button)
  86. {
  87.     return GPIO_ReadInputBit(BUTTON_PORT[Button], BUTTON_PIN[Button]);
  88. }
  89. /*!
  90. * @brief   This function handles External line 0 Handler
  91. *
  92. * @param   None
  93. *
  94. * @retval  None
  95. *
  96. */
  97. void EINT0_IRQHandler(void)
  98. {
  99.     if(EINT_ReadIntFlag(EINT_LINE_0))
  100.     {
  101.         APM_LEDToggle(LED2);

  102.         /*Clear EINT_LINE0 interrupt flag*/
  103.         EINT_ClearIntFlag(EINT_LINE_0);
  104.     }
  105. }
  106. /*!
  107. * @brief   This function handles External lines 1 Handler
  108. *
  109. * @param   None
  110. *
  111. * @retval  None
  112. *
  113. */
  114. void EINT1_IRQHandler(void)
  115. {
  116.     if(EINT_ReadIntFlag(EINT_LINE_1))
  117.     {
  118.         APM_LEDToggle(LED3);

  119.         /*Clear EINT_LINE0 interrupt flag*/
  120.         EINT_ClearIntFlag(EINT_LINE_1);
  121.     }

}MultiButton按键检测
MultiButton开源框架仓库 https://github.com/0x1abin/MultiButton
参考博客https://blog.csdn.net/qq_36075612/article/details/115901032
MultiButton | 一个小巧简单易用的事件驱动型按键驱动模块 https://zhuanlan.zhihu.com/p/128961191
本次使用的是博客中的版本,仓库版本的代码可能与下面代码不一样,应该是更新了代码和api。
一、使用方法
1.先申请一个按键结构。
2.初始化按键对象,绑定按键的GPIO电平读取接口read_button_pin() ,后一个参数设置有效触发电平。
3.注册按键事件。
4.启动按键。
5.设置一个5ms间隔的定时器循环调用后台处理函数。
  1. //按键状态读取接口
  2. unsigned char btn0_id = 0;
  3. struct Button button0;

  4. uint8_t  read_button0_GPIO(void)
  5. {
  6.     return (GPIO_ReadPin(BSP_PB_GPIO, BSP_PB_PIN));
  7. }

  8. void button_callback(void *button)
  9. {
  10.     uint32_t btn_event_val;
  11.    
  12.     btn_event_val = get_button_event((struct Button *)button);
  13.    
  14.     switch(btn_event_val)
  15.     {
  16.       case PRESS_DOWN:
  17.           printf("---> key1 press down! <---\r\n");
  18.       break;

  19.       case PRESS_UP:
  20.           printf("***> key1 press up! <***\r\n");
  21.       break;

  22.       case PRESS_REPEAT:
  23.           printf("---> key1 press repeat! <---\r\n");
  24.       break;

  25.       case SINGLE_CLICK:
  26.           printf("---> key1 single click! <---\r\n");
  27.       break;

  28.       case DOUBLE_CLICK:
  29.           printf("***> key1 double click! <***\r\n");
  30.       break;

  31.       case LONG_PRESS_START:
  32.           printf("---> key1 long press start! <---\r\n");
  33.       break;

  34.       case LONG_PRESS_HOLD:
  35.           printf("***> key1 long press hold! <***\r\n");
  36.       break;
  37.     }
  38. }

特性
MultiButton 使用C语言实现,基于面向对象方式设计思路,每个按键对象单独用一份数据结构管理:
  1. struct Button {

  2.     uint16_t ticks;
  3.     uint8_t  repeat: 4;
  4.     uint8_t  event : 4;
  5.     uint8_t  state : 3;
  6.     uint8_t  debounce_cnt : 3;
  7.     uint8_t  active_level : 1;
  8.     uint8_t  button_level : 1;
  9.     uint8_t  (*hal_button_Level)(void);
  10.     BtnCallback  cb[number_of_event];
  11.     struct Button* next;
  12. };

这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。
按键事件[td]
事件
说明
PRESS_DOWN按键按下,每次按下都触发
PRESS_UP按键弹起,每次松开都触发
PRESS_REPEAT重复按下触发,变量repeat计数连击次数
SINGLE_CLICK单击按键事件
DOUBLE_CLICK双击按键事件
LONG_PRESS_START达到长按时间阈值时触发一次
LONG_PRESS_HOLD长按期间一直触发
  1. #include "main.h"


  2. //按键状态读取接口

  3. uint8_t  read_button0_GPIO(void)
  4. {
  5.     return (GPIO_ReadInputBit(KEY1_BUTTON_GPIO_PORT, KEY1_BUTTON_PIN));
  6. }


  7. unsigned char btn0_id = 0;
  8. struct Button button0;

  9. void button_callback(void *button)
  10. {
  11.     uint32_t btn_event_val;
  12.    
  13.     btn_event_val = get_button_event((struct Button *)button);
  14.    
  15.     switch(btn_event_val)
  16.     {
  17.       case PRESS_DOWN:
  18.           printf("---> key1 press down! <---\r\n");
  19.       break;

  20.       case PRESS_UP:
  21.           printf("***> key1 press up! <***\r\n");
  22.       break;

  23.       case PRESS_REPEAT:
  24.           printf("---> key1 press repeat! <---\r\n");
  25.       break;

  26.       case SINGLE_CLICK:
  27.           printf("---> key1 single click! <---\r\n");
  28.       break;

  29.       case DOUBLE_CLICK:
  30.           printf("***> key1 double click! <***\r\n");
  31.       break;

  32.       case LONG_PRESS_START:
  33.           printf("---> key1 long press start! <---\r\n");
  34.       break;

  35.       case LONG_PRESS_HOLD:
  36.           printf("***> key1 long press hold! <***\r\n");
  37.       break;
  38.     }
  39. }

  40. /**
  41.   * @brief  main function.
  42.   * @param  none
  43.   * @retval none
  44.   */
  45. int main(void)
  46. {
  47.   //....初始化配置
  48.   printf("Hardware_Init [ok] \r\n");
  49.   printf("apm32f411 board  testing 2024-05-06\r\n");
  50.   printf("apm32f411 board  module multi-button\r\n");
  51.    
  52.   //初始化按键对象
  53.     button_init(&button0, read_button0_GPIO, 0);
  54.     button_attach(&button0, PRESS_DOWN,       button_callback);
  55.     button_attach(&button0, PRESS_UP,         button_callback);
  56.     button_attach(&button0, PRESS_REPEAT,     button_callback);
  57.     button_attach(&button0, SINGLE_CLICK,     button_callback);
  58.     button_attach(&button0, DOUBLE_CLICK,     button_callback);
  59.     button_attach(&button0, LONG_PRESS_START, button_callback);
  60.     button_attach(&button0, LONG_PRESS_HOLD,  button_callback);
  61.    //启动按键
  62.    button_start(&button0);
  63.   while(1)
  64.   {
  65.         button_ticks();
  66.         Delay_ms(5);
  67.   }
  68. }

测试效果
apm32-key-02.jpg
定时器简测
模仿例程和STM32进行了定时器中断试验。
  1. #include "main.h"
  2. #include "Bsp_Timer.h"

  3. volatile uint32_t tick = 0;
  4. unsigned int TIM2_LED=0;

  5. /*
  6. arr:自动重装值。
  7. psc:时钟预分频数
  8. 定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft
  9. Ft=定时器工作频率,单位:Mhz
  10. 例如:
  11. APM_Timer1_Init(1000-1,84-1);/*定时器时钟84M,分频系数84,所以84M/84=100kHZ,计数1000次为1ms*/
  12. */

  13. void APM_Timer1_Init(unsigned int arr,unsigned int psc)
  14. {
  15.     TMR_BaseConfig_T TMR_BaseConfigStruct;
  16.    /* Enable TMR1 Periph Clock */
  17.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1);

  18.     /* 配置TIM1 向上计数模式*/
  19.     TMR_BaseConfigStruct.clockDivision = TMR_CLOCK_DIV_1;
  20.     TMR_BaseConfigStruct.countMode = TMR_COUNTER_MODE_UP;
  21.     TMR_BaseConfigStruct.division = arr;
  22.     TMR_BaseConfigStruct.period = psc;
  23.     TMR_BaseConfigStruct.repetitionCounter = 0;
  24.     TMR_ConfigTimeBase(TMR1, &TMR_BaseConfigStruct);

  25.     /* Enable TMR1 Interrupt */
  26.     TMR_EnableInterrupt(TMR1, TMR_INT_UPDATE);
  27.     NVIC_EnableIRQRequest(TMR1_UP_TMR10_IRQn, 0, 0);

  28.     TMR_Enable(TMR1);
  29. }

  30. void APM_Timer2_Init(unsigned int arr,unsigned int psc)
  31. {
  32.     TMR_BaseConfig_T TMR_BaseConfigStruct;
  33.    /* Enable TMR1 Periph Clock */
  34.     RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR2);

  35.     /* Config TMR2 */
  36.     TMR_BaseConfigStruct.clockDivision = TMR_CLOCK_DIV_1;
  37.     TMR_BaseConfigStruct.countMode = TMR_COUNTER_MODE_UP;
  38.     TMR_BaseConfigStruct.division = arr;
  39.     TMR_BaseConfigStruct.period = psc;
  40.     TMR_BaseConfigStruct.repetitionCounter = 0;
  41.     TMR_ConfigTimeBase(TMR2, &TMR_BaseConfigStruct);

  42.     /* Enable TMR2 Interrupt */
  43.     TMR_EnableInterrupt(TMR2, TMR_INT_UPDATE);
  44.     NVIC_EnableIRQRequest(TMR2_IRQn, 0, 0);

  45.     TMR_Enable(TMR2);
  46. }
  47. /*!
  48. * @brief   This function handles TMR1 Update Handler
  49. *
  50. * @param   None
  51. *
  52. * @retval  None
  53. *
  54. */
  55. void TMR1_UP_TMR10_IRQHandler(void)
  56. {
  57.     if(TMR_ReadIntFlag(TMR1, TMR_INT_UPDATE) == SET)
  58.     {
  59. //        tick++;
  60.         TMR_ClearIntFlag(TMR1, TMR_INT_UPDATE);
  61.     }
  62. }
  63. void TMR2_IRQHandler(void)
  64. {
  65.     if(TMR_ReadIntFlag(TMR2, TMR_INT_UPDATE) == SET)
  66.     {
  67.         tick++;
  68.         if(tick==1000)
  69.         {
  70.             TIM2_LED=1;
  71.             tick=0;
  72.         }
  73.         TMR_ClearIntFlag(TMR2, TMR_INT_UPDATE);
  74.     }   
  75. }




  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

80

帖子

0

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