雅特力AT32A403开发板评测 04 GPIO输入输出 数码管显示 按键检测Multibutton移植

04 雅特力AT32A403开发板评测 GPIO输入输出 数码管显示 按键检测Multibutton移植

GPIO输出典型应用——点灯

GPIO输入典型应用——按键

1. 软硬件平台

  1. AT32A403A Board开发板

  2. MDK-ARM Keil

  3. 4-bit 数码管

    在这里插入图片描述

2.GPIO

AT32A403A 支持多达80 个双向I/O 管脚,这些管脚分为5 组,分别为PA、PB、PC、PD 和PE,每组
最多包含16 个管脚,每个管脚都可以实现与外部的通讯、控制以及数据采集的功能。
每个管脚都支持通用功能输入输出(GPIO)或复用功能输入输出(IOMUX)。本章节详细介绍GPIO 功
能,IOMUX 功能详见复用功能输入输出章节。
每个管脚都可以软件配置成浮空输入、上拉/下拉输入、模拟输入/输出、通用推挽/开漏输出、复用推挽/开
漏输出。
每个管脚都可以软件配置输出驱动能力。
每个管脚都可以配置为外部中断输入。
每个管脚都支持配置锁定功能。

GPIO端口结构

在这里插入图片描述

在AT32A403A固件库BSP&Pack应用指南.pdf中可以查看固件库函数api

在这里插入图片描述

3.GPIO 输出模式案例 数码管

数码管:是一种可以显示数字和其他信息的电子设备,可以看成是多个二极管的组成。

数码管显示原理:通过点亮内部的发光二极管来发光。

数码管根据其公共端所接的阳极和阴极的不同,分为了共阴极数码管和共阳极数码管。

共阳极接法:几个二极管的阳极接在一起,接到VCC(高电平),我们要想点亮,只要在在对应的二极管的阴极接上低电平即可。

共阴极接法:几个二极管的阴极接在一起,接到GND(低电平),我们要想点亮,只要在在对应的二极管的阳极接上高电平即可。

驱动代码 drv_smg.c

#include "main.h"

unsigned char smg_code[] =![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/def358fe57324fff971a4002c0c327b0.jpeg#pic_center)

{
    // 0	 1	  2	   3	4	 5	  6	   7	8	 9	  A	   b	C    d	  E    F    -
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x8C, 0xBF, 0xC6, 0xA1, 0x86, 0xFF, 0xbf
};//段码


void module_smg_gpio_iint(void)
{
  
  gpio_init_type gpio_init_struct;

  /* enable the gpioa clock */
  crm_periph_clock_enable(smg_port_clock, TRUE);

  /* set default parameter */
  gpio_default_para_init(&gpio_init_struct);

  /* configure the gpio */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
  gpio_init_struct.gpio_pins = smg_rclk_pin|smg_sclk_pin|smg_dio_pin;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(smg_port, &gpio_init_struct);
  
    
    gpio_bits_reset(smg_port, smg_rclk_pin|smg_sclk_pin|smg_dio_pin);  //将数码管端口拉高
 
}



void module_smg_data_output(uint8_t data)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        if (data & 0x80)//按位与,先发送高位
        {
            //SMG_DIO = 1;//SMG_DIO 端口置1
            gpio_bits_set(smg_dio_port, smg_dio_pin);
        }
        else
        {
            //SMG_DIO = 0;//SMG_DIO 端口置0
            gpio_bits_reset(smg_dio_port, smg_dio_pin);
        }
        data <<= 1;
        //SMG_SCLK = 0;
        //SMG_SCLK = 1;
        gpio_bits_reset(smg_sclk_port, smg_sclk_pin);;  //SMG_SCLK 端口置0
        gpio_bits_set(smg_sclk_port, smg_sclk_pin);;    //SMG_SCLK产生一个上升沿
    }
}
 
void module_smg_display(int num)
{
    uint8_t digit[digit_num], i, j;
    
    //将传入的数字转换为数组的元素
    for (i = 1; i <= digit_num; i++)
    {
        digit[digit_num - i] = num % 10;
        num /= 10;
    }
    
    for (j = i = 1; i <= digit_num; i++, j *= 2)
    {
        module_smg_data_output(smg_code[digit[digit_num - i]]); //发送显示数据
        module_smg_data_output(j);                              //发送显示位数
        gpio_bits_reset(smg_rclk_port, smg_rclk_pin);;  //SMG_RCLK 端口置0
        gpio_bits_set(smg_rclk_port, smg_rclk_pin);;    //SMG_RCLK产生一个上升沿
        delay_ms(2);  //保持一定时间,否则数码管亮度较低
    }

}

驱动代码 drv_smg.h

#ifndef __DRV_SMG_H
#define __DRV_SMG_H

#include "main.h"

#define digit_num 4

//适用于同一个gpio系列下
#define smg_port_clock      CRM_GPIOD_PERIPH_CLOCK
#define smg_port            GPIOD

//适用于不同gpio系列下
#define smg_dio_port            GPIOD
#define smg_dio_pin             GPIO_PINS_15
#define smg_dio_port_clock      CRM_GPIOD_PERIPH_CLOCK

#define smg_sclk_port           GPIOD
#define smg_sclk_pin            GPIO_PINS_11
#define smg_sclk_port_clock     CRM_GPIOD_PERIPH_CLOCK

#define smg_rclk_port           GPIOD
#define smg_rclk_pin            GPIO_PINS_13
#define smg_rclk_port_clock     CRM_GPIOD_PERIPH_CLOCK



//位带操作
//#define SMG_DIO  PDout(9)
//#define SMG_RCLK PDout(11)
//#define SMG_SCLK PDout(13)



void module_smg_gpio_iint(void);
void module_smg_data_output(uint8_t data);
void module_smg_display(int num);

#endif

测试代码

#include "main.h"


/** @addtogroup AT32A403A_periph_examples
  * @{
  */

/** @addtogroup 403A_USART_printf USART_printf
  * @{
  */

__IO uint32_t time_cnt = 0;

/**
  * @brief  main function.
  * @param  none
  * @retval none
  */
int main(void)
{
  unsigned char count_num; 
  system_clock_config();
  at32_board_init();
  uart_print_init(115200);
  module_smg_gpio_iint();
  /* output a message on hyperterminal using printf function */
  //printf("usart printf example: retarget the c library printf function to the usart\r\n");
  printf("Hardware_Init [ok] \r\n");
  printf("at_start_a403a board testing 2024-02-11\r\n");
  printf("at_start_a403a board module drv_smg\r\n");
    

  while(1)
  {
     printf("at32_module_smg example start [ok] \r\n");
    for(count_num=0;count_num<=99;count_num++)
    {	
        module_smg_display(count_num);
        delay_ms(10);
    }
    printf("at32_module_smg example end [ok] \r\n");
    printf("usart printf counter: %u\r\n",time_cnt++);
  }
}
测试效果

在这里插入图片描述
在这里插入图片描述

4.GPIO 输入模式案例 按键检测Multibutton移植

在雅特力AT32A403A开发板中,一共有2个按键,一个是复位按键 ,应该用户User按键,但是只有一个user_key可以去控制。

在这里插入图片描述

按键机械触点断开、闭合时,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开, 使用按键时会产生图 按键抖动说明图中的带波纹信号,需要用软件消抖处理滤波,不方便输入检测。

在这里插入图片描述

接下来就是按键key端口初始化的函数简单分析。

typedef enum
{
  USER_BUTTON                            = 0,
  NO_BUTTON                              = 1
} button_type;

#define USER_BUTTON_PIN                  GPIO_PINS_0
#define USER_BUTTON_PORT                 GPIOA
#define USER_BUTTON_CRM_CLK              CRM_GPIOA_PERIPH_CLOCK
void at32_button_init(void)
{
  gpio_init_type gpio_init_struct;

  /* enable the button clock */
  crm_periph_clock_enable(USER_BUTTON_CRM_CLK, TRUE);

  /* set default parameter */
  gpio_default_para_init(&gpio_init_struct);

  /* configure button pin as input with pull-up/pull-down */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  gpio_init_struct.gpio_pins = USER_BUTTON_PIN;
  gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
  gpio_init(USER_BUTTON_PORT, &gpio_init_struct);
}

/**
  * @brief  returns the selected button state
  * @param  none
  * @retval the button gpio pin value
  */
uint8_t at32_button_state(void)
{
  return gpio_input_data_bit_read(USER_BUTTON_PORT, USER_BUTTON_PIN);
}

/**
  * @brief  returns which button have press down
  * @param  none
  * @retval the button have press down
  */
button_type at32_button_press()
{
  static uint8_t pressed = 1;
  /* get button state in at_start board */
  if((pressed == 1) && (at32_button_state() != RESET))
  {
    /* debounce */
    pressed = 0;
    delay_ms(10);
    if(at32_button_state() != RESET)
      return USER_BUTTON;
  }
  else if(at32_button_state() == RESET)
  {
    pressed = 1;
  }
  return NO_BUTTON;
}

at32_button_init 端口初始化函数,(at32_button_state,at32_button_press函数在multibutton没有使用到)

void at32_button_init(void)
{
  gpio_init_type gpio_init_struct;

  /* enable the button clock */
  crm_periph_clock_enable(USER_BUTTON_CRM_CLK, TRUE);

  /* set default parameter */
  gpio_default_para_init(&gpio_init_struct);

  /* configure button pin as input with pull-up/pull-down */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  gpio_init_struct.gpio_pins = USER_BUTTON_PIN;
  gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
  gpio_init(USER_BUTTON_PORT, &gpio_init_struct);
}

/**
  * @brief  returns the selected button state
  * @param  none
  * @retval the button gpio pin value
  */
uint8_t at32_button_state(void)
{
  return gpio_input_data_bit_read(USER_BUTTON_PORT, USER_BUTTON_PIN);
}

/**
  * @brief  returns which button have press down
  * @param  none
  * @retval the button have press down
  */
button_type at32_button_press()
{
  static uint8_t pressed = 1;
  /* get button state in at_start board */
  if((pressed == 1) && (at32_button_state() != RESET))
  {
    /* debounce */
    pressed = 0;
    delay_ms(10);
    if(at32_button_state() != RESET)
      return USER_BUTTON;
  }
  else if(at32_button_state() == RESET)
  {
    pressed = 1;
  }
  return NO_BUTTON;
}
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间隔的定时器循环调用后台处理函数。

//按键状态读取接口
unsigned char btn0_id = 0;
struct Button button0;

uint8_t  read_button0_GPIO(void)
{
    return (GPIO_ReadPin(BSP_PB_GPIO, BSP_PB_PIN));
}

void button_callback(void *button)
{
    uint32_t btn_event_val; 
    
    btn_event_val = get_button_event((struct Button *)button); 
    
    switch(btn_event_val)
    {
      case PRESS_DOWN:
          printf("---> key1 press down! <---\r\n"); 
      break; 
 
      case PRESS_UP: 
          printf("***> key1 press up! <***\r\n");
      break; 
 
      case PRESS_REPEAT: 
          printf("---> key1 press repeat! <---\r\n");
      break; 
 
      case SINGLE_CLICK: 
          printf("---> key1 single click! <---\r\n");
      break; 
 
      case DOUBLE_CLICK: 
          printf("***> key1 double click! <***\r\n");
      break; 
 
      case LONG_PRESS_START: 
          printf("---> key1 long press start! <---\r\n");
      break; 
 
      case LONG_PRESS_HOLD: 
          printf("***> key1 long press hold! <***\r\n");
      break; 
    }
}
特性

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

struct Button {

	uint16_t ticks;
	uint8_t  repeat: 4;
	uint8_t  event : 4;
	uint8_t  state : 3;
	uint8_t  debounce_cnt : 3;
	uint8_t  active_level : 1;
	uint8_t  button_level : 1;
	uint8_t  (*hal_button_Level)(void);
	BtnCallback  cb[number_of_event];
	struct Button* next;
};

这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。

按键事件
事件说明
PRESS_DOWN按键按下,每次按下都触发
PRESS_UP按键弹起,每次松开都触发
PRESS_REPEAT重复按下触发,变量repeat计数连击次数
SINGLE_CLICK单击按键事件
DOUBLE_CLICK双击按键事件
LONG_PRESS_START达到长按时间阈值时触发一次
LONG_PRESS_HOLD长按期间一直触发
#include "main.h"


/** @addtogroup AT32A403A_periph_examples
  * @{
  */

/** @addtogroup 403A_USART_printf USART_printf
  * @{
  */

__IO uint32_t time_cnt = 0;

//按键状态读取接口

uint8_t  read_button0_GPIO(void)
{
    return (gpio_input_data_bit_read(USER_BUTTON_PORT, USER_BUTTON_PIN));
}


unsigned char btn0_id = 0;
struct Button button0;
void button_callback(void *button)
{
    uint32_t btn_event_val; 
    
    btn_event_val = get_button_event((struct Button *)button); 
    
    switch(btn_event_val)
    {
      case PRESS_DOWN:
          printf("---> key1 press down! <---\r\n"); 
      break; 
 
      case PRESS_UP: 
          printf("***> key1 press up! <***\r\n");
      break; 
 
      case PRESS_REPEAT: 
          printf("---> key1 press repeat! <---\r\n");
      break; 
 
      case SINGLE_CLICK: 
          printf("---> key1 single click! <---\r\n");
      break; 
 
      case DOUBLE_CLICK: 
          printf("***> key1 double click! <***\r\n");
      break; 
 
      case LONG_PRESS_START: 
          printf("---> key1 long press start! <---\r\n");
      break; 
 
      case LONG_PRESS_HOLD: 
          printf("***> key1 long press hold! <***\r\n");
      break; 
    }
}

/**
  * @brief  main function.
  * @param  none
  * @retval none
  */
int main(void)
{
//  unsigned char count_num; 
  system_clock_config();
  at32_board_init();
  uart_print_init(115200);
  module_smg_gpio_iint();
  /* output a message on hyperterminal using printf function */
  //printf("usart printf example: retarget the c library printf function to the usart\r\n");
  printf("Hardware_Init [ok] \r\n");
  printf("at_start_a403a board testing 2024-02-11\r\n");
  printf("at_start_a403a board module multi-button\r\n");
    
  //初始化按键对象
    button_init(&button0, read_button0_GPIO, 0);
    button_attach(&button0, PRESS_DOWN,       button_callback);
    button_attach(&button0, PRESS_UP,         button_callback);
    button_attach(&button0, PRESS_REPEAT,     button_callback);
    button_attach(&button0, SINGLE_CLICK,     button_callback);
    button_attach(&button0, DOUBLE_CLICK,     button_callback);
    button_attach(&button0, LONG_PRESS_START, button_callback);
    button_attach(&button0, LONG_PRESS_HOLD,  button_callback);
   //启动按键
   button_start(&button0);
  while(1)
  {
        button_ticks();
        delay_ms(5);
  }
}

测试效果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值