你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F7xx —— 输入

[复制链接]
STMCU小助手 发布时间:2021-12-13 22:56
一、输入配置
为了灵活使用,我们将输入的有效电平设置成可配置。同样是列表表示所有IO口。

  1. // 配置有效电平
  2. typedef enum
  3. {
  4.   KEY_INIT_IS_ACTIVE = 0,
  5.   KEY_LOW_IS_ACTIVE  = 1,
  6.   KEY_HIGH_IS_ACTIVE = 2,
  7. } key_active_t;


  8. #define KEY_CONFIG(gpio, pin)     GPIOConfig(gpio, pin, GPIO_MODE_INPUT, GPIO_PULLUP)
  9. #define KEY_READ(gpio, pin)       HAL_GPIO_ReadPin(gpio, pin)

  10. #define KEY1_PORT                 GPIOH
  11. #define KEY1_PIN                  GPIO_PIN_3

  12. #define KEY2_PORT                 GPIOH
  13. #define KEY2_PIN                  GPIO_PIN_2

  14. #define KEY3_PORT                 GPIOC
  15. #define KEY3_PIN                  GPIO_PIN_13
复制代码
  1. // demo代码 只传递思想

  2. static void key_gpio_config(GPIO_TypeDef *gpio, uint16_t pin)
  3. {
  4.   KEY_CONFIG(gpio, pin);
  5. }

  6. typedef struct
  7. {
  8.   GPIO_TypeDef *gpio;
  9.   uint16_t pin;
  10. } key_port_t;

  11. static key_port_t key_entries[] =
  12. {
  13.   {KEY1_PORT, KEY1_PIN},
  14.   {KEY2_PORT, KEY2_PIN},
  15.   {KEY3_PORT, KEY3_PIN},
  16. };

  17. void KeyInit(void)
  18. {
  19.   uint32_t i, mask = 1;

  20.   for(i = 0; i < ARRAY_SIZE(key_entries); ++i)
  21.   {
  22.     if(0xFFFFFFFF & mask)
  23.     {
  24.       key_gpio_config(key_entries<span style="font-style: italic;">.gpio, key_entries.pin);

  25. <span style="font-style: normal;">#if(CONFIG_KEY_TEST == 1) // 测试时使用      
  26.       //config.key.total_switch  = KEY_MODE_OPEN;
  27.       //config.key.sub_switch = KEY_MODE_OPEN;
  28.       config.key.active_tag = KEY_LOW_IS_ACTIVE;
  29. #endif
  30.     }

  31.     mask <<= 1;
  32.   }
  33. }

  34. // 输入是否可用
  35. static uint8_t key_is_enable(uint8_t index)
  36. {
  37.   // 这里可以写成可配置 配置IO口可用或者不可用(类似一个总开关)
  38.   return 1;
  39. }

  40. // 有输入到来
  41. static uint8_t key_is_pressed(uint8_t index)
  42. {
  43.   if(key_is_enable(index))
  44.   {
  45.     if(KEY_LOW_IS_ACTIVE == config.key.active_tag[index])
  46.     {
  47.       if(KEY_READ(key_entries[index].gpio, key_entries[index].pin) == 0)
  48.       {
  49.         return 1;
  50.       }
  51.     }
  52.     else if(KEY_HIGH_IS_ACTIVE == config.key.active_tag[index])
  53.     {
  54.       if(KEY_READ(key_entries[index].gpio, key_entries[index].pin) == 1)
  55.       {
  56.         return 1;
  57.       }
  58.     }
  59.   }

  60.   return 0;
  61. }

  62. // 按键被按下
  63. uint8_t Key1IsDown(void)
  64. {
  65.   return key_is_pressed(0);
  66. }

  67. uint8_t Key2IsDown(void)
  68. {
  69.   return key_is_pressed(1);
  70. }

  71. uint8_t Key3IsDown(void)
  72. {
  73.   return key_is_pressed(2);
  74. }</span></span>
复制代码

二、输入扫描
  1. // 按键的状态机结构定义
  2. // 按键状态
  3. typedef enum
  4. {
  5.   KEY_STATE_INIT, // 缺省按键状态
  6.   KEY_STATE_UP,   // 按键弹起状态
  7.   KEY_STATE_DOWN, // 按键按下状态
  8.   KEY_STATE_LONG, // 按键长按状态
  9.   KEY_STATE_AUTO, // 按键自动连发状态
  10. } key_state_t;

  11. // 按键滤波时间20ms, 单位10ms。
  12. // 只有连续检测到20ms状态不变才认为有效,包括弹起和按下两种事件
  13. // 即使按键电路不做硬件滤波,该滤波机制也可以保证可靠地检测到按键事件
  14. #define KEY_FILTER_TIME 2   // 滤波消抖
  15. #define KEY_LONG_TIME   100 // 单位10ms    持续1秒,认为长按事件
  16. #define KEY_REPEAT_TIME 100 // 单位10ms    持续1秒,自动连发

  17. typedef uint8_t (*key_cb)(void);
  18. typedef struct
  19. {
  20.   uint8_t state;        // 按键当前状态(按下还是弹起)
  21.   uint8_t last;         // 上一次按键的状态
  22.   uint8_t count;        // 滤波消抖计数器
  23.   uint16_t long_time;   // 按键按下持续时间, 0表示不检测长按
  24.   uint16_t long_count;  // 长按计数器
  25.   uint8_t repeat_speed; // 连续按键周期
  26.   uint8_t repeat_count; // 连续按键计数器
  27.   key_cb is_down_func;  // 按键按下的判断函数,1表示按下
  28. } key_t;

  29. static key_t key_items[] =
  30. {
  31.   {KEY_STATE_INIT, KEY_STATE_INIT, KEY_FILTER_TIME, KEY_LONG_TIME, 0, KEY_REPEAT_TIME, 0, Key1IsDown},
  32.   {KEY_STATE_INIT, KEY_STATE_INIT, KEY_FILTER_TIME, KEY_LONG_TIME, 0, KEY_REPEAT_TIME, 0, Key2IsDown},
  33.   {KEY_STATE_INIT, KEY_STATE_INIT, KEY_FILTER_TIME, KEY_LONG_TIME, 0, KEY_REPEAT_TIME, 0, Key3IsDown},
  34. };
复制代码
  1. // 按键状态机key_scan
  2. // 配置限制条件在这个函数里面加
  3. static void key_scan_ext(key_t *entry, uint8_t i)
  4. {
  5.   switch(entry->state)
  6.   {
  7.   case KEY_STATE_INIT:
  8.   case KEY_STATE_UP:
  9.   {
  10.     entry->state = KEY_STATE_DOWN; // 按键被按下
  11.     break;
  12.   }

  13.   case KEY_STATE_DOWN:
  14.   {
  15.     if(entry->long_time > 0)
  16.     {
  17.       if(entry->long_count < entry->long_time)
  18.       {
  19.         if(++entry->long_count >= entry->long_time)
  20.         {
  21.           entry->state = KEY_STATE_LONG;
  22.         }
  23.       }
  24.     }

  25.     break;
  26.   }

  27.   case KEY_STATE_LONG:
  28.   {
  29.     if(entry->repeat_speed > 0) // 自动连发时间到  自动连发事件
  30.     {
  31.       if(++entry->repeat_count >= entry->repeat_speed)
  32.       {
  33.         entry->repeat_count = 0;
  34.         // 长按触发
  35.       }
  36.     }

  37.     break;
  38.   }
  39.   }

  40.   entry->last = entry->state; // 最新的按键状态
  41. }

  42. static void key_scan(uint8_t i)
  43. {
  44.   key_t *entry = &key_items<span style="font-style: italic;"><span style="font-style: normal;">;
  45.         uint8_t key;

  46.   if(entry->is_down_func())
  47.   {
  48.     if(entry->count < KEY_FILTER_TIME) // 消抖
  49.     {
  50.       ++entry->count;
  51.     }
  52.     else
  53.     {
  54.       key_scan_ext(entry, i); // 按键扫描状态机
  55.     }
  56.   }
  57.   else
  58.   {
  59.     if(entry->count > KEY_FILTER_TIME)
  60.     {
  61.       entry->count = KEY_FILTER_TIME;
  62.     }
  63.     else if(entry->count > 0)
  64.     {
  65.       --entry->count;
  66.     }
  67.     else
  68.     {
  69.       if(KEY_STATE_DOWN == entry->last) // 一次完整的按键到这里就弹起了
  70.       {
  71.        // 按键按下之后可以加入到队列中,这里的队列可以自己写;如果带系统可以使用系统的消息队列等方式。
  72.        // key = i + 1;
  73.        // xQueueSend(os_key_queue, &key, 10);
  74.       }
  75.       entry->last  = KEY_STATE_UP;
  76.       entry->state = KEY_STATE_UP; // 按键弹起状态
  77.     }

  78.     entry->long_count = 0;
  79.     entry->repeat_count = 0; // 清空计数器
  80.   }
  81. }</span></span>
复制代码

三、输入处理
  1. // 按键按下之后,会将值加入到队列中,我们读取队列数据,然后扫描列表匹配功能
  2. static void key1_cb(void);
  3. static void key2_cb(void);
  4. static void key3_cb(void);

  5. #define KEY1_CMD         1
  6. #define KEY2_CMD         2
  7. #define KEY3_CMD         3

  8. typedef struct
  9. {
  10.   uint8_t cmd;
  11.   void (* key_handle_cb)(void);
  12. } key_handle_t;

  13. static const key_handle_t key_entries[] =
  14. {
  15.   {KEY1_CMD, key1_cb},
  16.   {KEY2_CMD, key2_cb},
  17.   {KEY3_CMD, key3_cb},
  18.   {0xFF, NULL  },
  19. };

  20. // 按键的通用功能
  21. static void key_func(uint8_t func)
  22. {

  23. }

  24. static void key1_cb(void)
  25. {

  26. }

  27. static void key2_cb(void)
  28. {

  29. }

  30. static void key3_cb(void)
  31. {

  32. }

  33. static void key_process(uint8_t event)
  34. {
  35.   const key_handle_t *entry;

  36.   for(entry = key_entries; entry->key_handle_cb; ++entry)
  37.   {
  38.     if(event == entry->cmd)
  39.     {
  40.       entry->key_handle_cb();
  41.       break;
  42.     }
  43.   }
  44. }
复制代码

裸机:按键扫描20ms执行一次,按键处理直接丢在主函数中。(自己写队列)

系统:在任务中执行按键扫描和按键处理。(系统自带队列或者邮箱)


收藏 评论0 发布时间:2021-12-13 22:56

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版