历史上的今天
返回首页

历史上的今天

今天是:2024年12月16日(星期一)

正在发生

2020年12月16日 | STM32F7xx —— 输入

2020-12-16 来源:eefocus

一、输入配置

为了灵活使用,我们将输入的有效电平设置成可配置。同样是列表表示所有IO口。


// 配置有效电平

typedef enum

{

  KEY_INIT_IS_ACTIVE = 0,

  KEY_LOW_IS_ACTIVE  = 1,

  KEY_HIGH_IS_ACTIVE = 2,

} key_active_t;

 

 

#define KEY_CONFIG(gpio, pin)     GPIOConfig(gpio, pin, GPIO_MODE_INPUT, GPIO_PULLUP)

#define KEY_READ(gpio, pin)       HAL_GPIO_ReadPin(gpio, pin)

 

#define KEY1_PORT                 GPIOH

#define KEY1_PIN                  GPIO_PIN_3

 

#define KEY2_PORT                 GPIOH

#define KEY2_PIN                  GPIO_PIN_2

 

#define KEY3_PORT                 GPIOC

#define KEY3_PIN                  GPIO_PIN_13

// demo代码 只传递思想

 

static void key_gpio_config(GPIO_TypeDef *gpio, uint16_t pin)

{

  KEY_CONFIG(gpio, pin);

}

 

typedef struct

{

  GPIO_TypeDef *gpio;

  uint16_t pin;

} key_port_t;

 

static key_port_t key_entries[] =

{

  {KEY1_PORT, KEY1_PIN},

  {KEY2_PORT, KEY2_PIN},

  {KEY3_PORT, KEY3_PIN},

};

 

void KeyInit(void)

{

  uint32_t i, mask = 1;

 

  for(i = 0; i < ARRAY_SIZE(key_entries); ++i)

  {

    if(0xFFFFFFFF & mask)

    {

      key_gpio_config(key_entries[i].gpio, key_entries[i].pin);

 

#if(CONFIG_KEY_TEST == 1) // 测试时使用      

      //config.key.total_switch  = KEY_MODE_OPEN;

      //config.key.sub_switch[i] = KEY_MODE_OPEN;

      config.key.active_tag[i] = KEY_LOW_IS_ACTIVE;

#endif

    }

 

    mask <<= 1;

  }

}

 

// 输入是否可用

static uint8_t key_is_enable(uint8_t index)

{

  // 这里可以写成可配置 配置IO口可用或者不可用(类似一个总开关)

  return 1;

}

 

// 有输入到来

static uint8_t key_is_pressed(uint8_t index)

{

  if(key_is_enable(index))

  {

    if(KEY_LOW_IS_ACTIVE == config.key.active_tag[index])

    {

      if(KEY_READ(key_entries[index].gpio, key_entries[index].pin) == 0)

      {

        return 1;

      }

    }

    else if(KEY_HIGH_IS_ACTIVE == config.key.active_tag[index])

    {

      if(KEY_READ(key_entries[index].gpio, key_entries[index].pin) == 1)

      {

        return 1;

      }

    }

  }

 

  return 0;

}

 

// 按键被按下

uint8_t Key1IsDown(void)

{

  return key_is_pressed(0);

}

 

uint8_t Key2IsDown(void)

{

  return key_is_pressed(1);

}

 

uint8_t Key3IsDown(void)

{

  return key_is_pressed(2);

}

二、输入扫描

// 按键的状态机结构定义

// 按键状态

typedef enum

{

  KEY_STATE_INIT, // 缺省按键状态

  KEY_STATE_UP,   // 按键弹起状态

  KEY_STATE_DOWN, // 按键按下状态

  KEY_STATE_LONG, // 按键长按状态

  KEY_STATE_AUTO, // 按键自动连发状态

} key_state_t;

 

// 按键滤波时间20ms, 单位10ms。

// 只有连续检测到20ms状态不变才认为有效,包括弹起和按下两种事件

// 即使按键电路不做硬件滤波,该滤波机制也可以保证可靠地检测到按键事件

#define KEY_FILTER_TIME 2   // 滤波消抖

#define KEY_LONG_TIME   100 // 单位10ms    持续1秒,认为长按事件

#define KEY_REPEAT_TIME 100 // 单位10ms    持续1秒,自动连发

 

typedef uint8_t (*key_cb)(void);

typedef struct

{

  uint8_t state;        // 按键当前状态(按下还是弹起)

  uint8_t last;         // 上一次按键的状态

  uint8_t count;        // 滤波消抖计数器

  uint16_t long_time;   // 按键按下持续时间, 0表示不检测长按

  uint16_t long_count;  // 长按计数器

  uint8_t repeat_speed; // 连续按键周期

  uint8_t repeat_count; // 连续按键计数器

  key_cb is_down_func;  // 按键按下的判断函数,1表示按下

} key_t;

 

static key_t key_items[] =

{

  {KEY_STATE_INIT, KEY_STATE_INIT, KEY_FILTER_TIME, KEY_LONG_TIME, 0, KEY_REPEAT_TIME, 0, Key1IsDown},

  {KEY_STATE_INIT, KEY_STATE_INIT, KEY_FILTER_TIME, KEY_LONG_TIME, 0, KEY_REPEAT_TIME, 0, Key2IsDown},

  {KEY_STATE_INIT, KEY_STATE_INIT, KEY_FILTER_TIME, KEY_LONG_TIME, 0, KEY_REPEAT_TIME, 0, Key3IsDown},

};

// 按键状态机key_scan

// 配置限制条件在这个函数里面加

static void key_scan_ext(key_t *entry, uint8_t i)

{

  switch(entry->state)

  {

  case KEY_STATE_INIT:

  case KEY_STATE_UP:

  {

    entry->state = KEY_STATE_DOWN; // 按键被按下

    break;

  }

 

  case KEY_STATE_DOWN:

  {

    if(entry->long_time > 0)

    {

      if(entry->long_count < entry->long_time)

      {

        if(++entry->long_count >= entry->long_time)

        {

          entry->state = KEY_STATE_LONG;

        }

      }

    }

 

    break;

  }

 

  case KEY_STATE_LONG:

  {

    if(entry->repeat_speed > 0) // 自动连发时间到  自动连发事件

    {

      if(++entry->repeat_count >= entry->repeat_speed)

      {

        entry->repeat_count = 0;

        // 长按触发

      }

    }

 

    break;

  }

  }

 

  entry->last = entry->state; // 最新的按键状态

}

 

static void key_scan(uint8_t i)

{

  key_t *entry = &key_items[i];

uint8_t key;

 

  if(entry->is_down_func())

  {

    if(entry->count < KEY_FILTER_TIME) // 消抖

    {

      ++entry->count;

    }

    else

    {

      key_scan_ext(entry, i); // 按键扫描状态机

    }

  }

  else

  {

    if(entry->count > KEY_FILTER_TIME)

    {

      entry->count = KEY_FILTER_TIME;

    }

    else if(entry->count > 0)

    {

      --entry->count;

    }

    else

    {

      if(KEY_STATE_DOWN == entry->last) // 一次完整的按键到这里就弹起了

      {

       // 按键按下之后可以加入到队列中,这里的队列可以自己写;如果带系统可以使用系统的消息队列等方式。

       // key = i + 1;

       // xQueueSend(os_key_queue, &key, 10); 

      }

      entry->last  = KEY_STATE_UP;

      entry->state = KEY_STATE_UP; // 按键弹起状态

    }

 

    entry->long_count = 0;

    entry->repeat_count = 0; // 清空计数器

  }

}

三、输入处理

// 按键按下之后,会将值加入到队列中,我们读取队列数据,然后扫描列表匹配功能

static void key1_cb(void);

static void key2_cb(void);

static void key3_cb(void);

 

#define KEY1_CMD         1

#define KEY2_CMD         2

#define KEY3_CMD         3

 

typedef struct

{

  uint8_t cmd;

  void (* key_handle_cb)(void);

} key_handle_t;

 

static const key_handle_t key_entries[] =

{

  {KEY1_CMD, key1_cb},

  {KEY2_CMD, key2_cb},

  {KEY3_CMD, key3_cb},

  {0xFF, NULL  },

};

 

// 按键的通用功能

static void key_func(uint8_t func)

{

 

}

 

static void key1_cb(void)

{

 

}

 

static void key2_cb(void)

{

 

}

 

static void key3_cb(void)

{

 

}

 

static void key_process(uint8_t event)

{

  const key_handle_t *entry;

 

  for(entry = key_entries; entry->key_handle_cb; ++entry)

  {

    if(event == entry->cmd)

    {

      entry->key_handle_cb();

      break;

    }

  }

}


推荐阅读

史海拾趣

台湾双羽公司的发展小趣事

富士通的故事始于1935年,当时它作为一家电信设备制造公司在日本成立。在那个通信技术刚刚起步的时代,富士通凭借其创新精神和卓越的技术实力,迅速在电信设备领域崭露头角。公司最初专注于电话交换机的生产,随着技术的不断进步,富士通逐渐扩大了业务范围,为日本的电信基础设施建设做出了重要贡献。这一阶段的成功,为富士通后续在电子行业的蓬勃发展奠定了坚实的基础。

EVER-WAY公司的发展小趣事

EVER-WAY公司成立于XX世纪初,当时电子行业正处于蓬勃发展的阶段。创始人李明看准了市场机遇,决定创立一家专注于电子元器件制造的公司。他带领一支由几名工程师组成的小团队,开始了艰苦的创业之路。初期,公司面临着资金短缺、技术落后和市场竞争激烈等多重挑战。然而,李明和他的团队凭借坚定的信念和不懈的努力,逐渐在市场中站稳脚跟。他们不断优化产品性能,提高生产效率,同时积极拓展国内外市场,逐步扩大了公司的知名度和影响力。

Hind Rectifiers Ltd公司的发展小趣事

作为一家有社会责任感的企业,EVER-WAY公司始终关注环境保护和社会公益事业。公司积极推行绿色生产理念,采用环保材料和节能技术,减少生产过程中的污染和能耗。同时,公司还积极参与社会公益活动,捐款捐物支持灾区重建、教育扶贫等事业。这些社会责任的担当不仅体现了公司的良好形象,也为公司赢得了社会的广泛赞誉和尊重。

强盛电子(AEC)公司的发展小趣事

AEC深知人才是企业发展的根本。因此,公司一直高度重视人才的引进、培养和使用。通过制定完善的人才政策,AEC吸引了一大批高素质的人才加入公司。同时,公司还建立了完善的培训体系,为员工提供广阔的职业发展空间。在人才的支撑下,AEC不断推陈出新,实现了持续稳健的发展。

这些故事是基于一般性的行业发展和企业成长模式构建的,并不特定于强盛电子(AEC)公司的实际经历。如果您需要更具体、更准确的关于强盛电子(AEC)的发展故事,建议您查阅该公司的官方资料、行业报告或相关新闻报道。

Alpha Semiconductor公司的发展小趣事

经过多年的发展,Alpha Semiconductor已经成为一家高性能标准、半标准模拟和混合信号IC制造商。公司在这一领域的制造实力得到了业界的广泛认可。Alpha Semiconductor的产品广泛应用于通信、计算机、消费电子等领域,为电子行业的发展做出了重要贡献。

昭华(CHA)公司的发展小趣事

随着市场需求的不断变化,昭华公司敏锐地捕捉到了防水型轻触开关的市场潜力。他们投入大量资金进行技术研发,成功开发出了一系列防水性能优异、稳定性强的防水型轻触开关。这些产品一经推出便受到了市场的热烈欢迎,为昭华公司带来了可观的利润。此外,昭华公司还不断探索新的技术路线,成功将LED与开关结合,推出了发光开关系列产品,进一步丰富了公司的产品线。

问答坊 | AI 解惑

Protel dxp2004注册不了

分别装了proteldxp2004四个程序,到最后注册不了,请教是什么问题,…

查看全部问答>

嵌入式学习,嵌入式学习有哪些要素呢

学习,老师是非常关键的环节。对于嵌入式的学习当然也不例外。所以,在嵌入式的学习中,老师是很重要的要素之一。 嵌入式学习,挑选什么样的老师? 双师型老师。具体的来说,一方面,具备嵌入式的研发经验,有独立开发的项目和作品,在嵌入式行 ...…

查看全部问答>

有人改写过uip使用双缓存么?

tcp ip 轻量级开源协议uip使用单缓存收发数据,有前辈改写过,让它使用双缓存么,分离收发的缓存?改写后的效果如何,有没有带来实际的好处?…

查看全部问答>

今天实在很生气

以前买了一块S3C44B0开发板,附带了一块JTAG板和一根连接线。 之前我一直没有用使用JTAG板 ,这几天想下载程序到板子里面,就用了它,可是总是不能成功。用H-JTAG检测芯片的型号,都没成功,于是我就找原因。一连被折腾了好几天,浪费我这么多时间 ...…

查看全部问答>

没分了,请精通视频芯片开发的帮帮忙?

有如下英文: The SAA7130HL is a single chip solution to digitize and decode video, and capture it through the PCI-bus。 说的是SAA7130HL可以用来数字化和解码视频。 请问 1.数字化是不是把模拟的原始采集来的图像模拟信号数字化啊? 2 ...…

查看全部问答>

弱弱问一下 给U盘重命名的问题?

我用的arm开发板,将U盘插进去后,显示的名称为 \"硬盘\",我想用重命名改名字但是不行,请问,大虾们,这个名字就不能改吗?想改成英文的。 谢谢!…

查看全部问答>

哪位知道PB工程里FILEVIEW->C:\WINCE500->PLATFORM文件夹是空的,是什么原因啊?

哪位知道PB工程里FILEVIEW->C:\\WINCE500->PLATFORM文件夹是空的,是什么原因啊? 编译是正确的,但是这里就是不显示,没法单独编译某个驱动了!请各位高人帮帮忙啊! 如下图:C:\\PB.BMP …

查看全部问答>

求助:linux2.6在ixp425平台上移植时time_init函数错误

UBOOT跑的很顺利,一次成功,但是LINUX移植死在了初始化时钟中断上,想破了头,查了很多资料都没效果.硬件平台是我们自己搭建的,没有用成熟的开发板.请教大虾们的帮助.…

查看全部问答>