返回列表 发新帖我要提问本帖赏金: 100.00元(功能说明)

[MM32生态] 【MM32+模块】系列:04、按键检测

[复制链接]
3271|18
 楼主| xld0932 发表于 2022-4-6 14:00 | 显示全部楼层 |阅读模式
本帖最后由 xld0932 于 2022-4-6 14:08 编辑

#申请原创#   @21小跑堂

在项目中,按键检测是我们最常用的功能;对于芯片资源比较富裕时,我们可以用独立按键,在功能上既可以被独立检测,也可以实现组合检测的功能;如果按键比较多时,我们可以考虑矩阵按键,比如将之前需要16个引脚实现的独立按键,通过8个引脚实现4*4的按键矩阵,这样在按键数量保持不变的情况下,减小了MCU使用引脚的资源;当然在MCU资源很紧张,又要实现多个按键功能的时候,我们可以使用ADC来实现按键检测,这种通过1ADC通道的检测方式只能够实现每一个按键的独立检测,无法做按键组合的效果了;当然还有其它的按键检测方式,结合MCU资源和按键功能定义,总能找到一种适合你项目的按键检测方案。

本文结合淘宝上买到的3个常用的按键模块,来分别讲述一下基于MM32F0140在不同方式下按键检测的实现:
1、独立按键
2、矩阵按键
3ADC按键

独立按键

7.png

独立按键方式每一个按键需要占用一个MCU引脚资源,根据硬件设计可以配置成上拉或下拉输入,通过检测按键是否处于低/高电平来判断按键是否被按下,检测按键是否处于高/低电平来判断按键是否又被释放;每一个按键都可以独立被检测,每个按键可以实现独立的个体功能,也可以同时检测两个或者多个按键来实现组合按键的功能,实现比较灵活,缺点就是随着按键数量的增多,所占用的MCU也会同步递增。

2.jpg

独立按键实现代码1每个按键独立功能实现

  1. void KEY_Init(void)
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure;

  4.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);

  5.     GPIO_StructInit(&GPIO_InitStructure);
  6.     GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0  | GPIO_Pin_1  | GPIO_Pin_2 |
  7.                                    GPIO_Pin_10 | GPIO_Pin_11;
  8.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  9.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  10.     TASK_Append(TASK_ID_KEY, KEY_Scan, 10);
  11. }

  12. void KEY_SubScan(uint8_t *State, uint8_t *Count, uint8_t Value, char *Name)
  13. {
  14.     if(*State == 0)
  15.     {
  16.         if(Value != Bit_RESET) *Count += 1;
  17.         else                   *Count  = 0;

  18.         if(*Count > 5)
  19.         {
  20.             *Count = 0; *State = 1;
  21.             printf("\r\n%s Pressed", Name);
  22.         }
  23.     }
  24.     else
  25.     {
  26.         if(Value == Bit_RESET) *Count += 1;
  27.         else                   *Count  = 0;

  28.         if(*Count > 5)
  29.         {
  30.             *Count = 0; *State = 0;
  31.             printf("\r\n%s Release", Name);
  32.         }
  33.     }
  34. }

  35. void KEY_Scan(void)
  36. {
  37.     static uint8_t KeyState[KEY_NUMBER] = {0, 0, 0, 0, 0};
  38.     static uint8_t KeyCount[KEY_NUMBER] = {0, 0, 0, 0, 0};

  39.     KEY_SubScan(&KeyState[0], &KeyCount[0], GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0),  "BLACK  KEY");
  40.     KEY_SubScan(&KeyState[1], &KeyCount[1], GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1),  "RED    KEY");
  41.     KEY_SubScan(&KeyState[2], &KeyCount[2], GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2),  "GREEN  KEY");
  42.     KEY_SubScan(&KeyState[3], &KeyCount[3], GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10), "YELLOW KEY");
  43.     KEY_SubScan(&KeyState[4], &KeyCount[4], GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11), "BLUE   KEY");
  44. }

独立按键运行效果1

0.png

独立按键实现代码2每个按键独立功能实现,且支持长按、短按、连击上报功能

  1. #define KEY_NUMBER          5

  2. #define KEY_STATE_IDLE      0
  3. #define KEY_STATE_PRESSED   1
  4. #define KEY_STATE_RELEASE   2

  5. typedef struct
  6. {
  7.     uint32_t            RCCn;
  8.     GPIO_TypeDef       *GPIOn;
  9.     uint16_t            PINn;
  10.     GPIOMode_TypeDef    Mode;
  11.     BitAction           IDLE;
  12.     char               *Name;
  13. } KEY_GROUP_TypeDef;

  14. typedef struct
  15. {
  16.     uint8_t  State;
  17.     uint8_t  Value;
  18.     uint8_t  Count;
  19.     uint16_t Debounce;
  20.     uint16_t Interval;
  21.     uint8_t  Trigger;
  22. } KEY_TypeDef;

  23. KEY_GROUP_TypeDef KEY_GROUP[KEY_NUMBER] =
  24. {
  25.     {RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_0 , GPIO_Mode_IPD, Bit_RESET, "BLACK  KEY"},
  26.     {RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_1 , GPIO_Mode_IPD, Bit_RESET, "RED    KEY"},
  27.     {RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_2 , GPIO_Mode_IPD, Bit_RESET, "GREEN  KEY"},
  28.     {RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_10, GPIO_Mode_IPD, Bit_RESET, "YELLOW KEY"},
  29.     {RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_11, GPIO_Mode_IPD, Bit_RESET, "BLUE   KEY"},
  30. };


  31. /* Private variables ---------------------------------------------------------*/
  32. KEY_TypeDef UserKEY[KEY_NUMBER] =
  33. {
  34.     {0, 0, 0, 0, 0, 0},
  35.     {0, 0, 0, 0, 0, 0},
  36.     {0, 0, 0, 0, 0, 0},
  37.     {0, 0, 0, 0, 0, 0},
  38.     {0, 0, 0, 0, 0, 0},
  39. };

  40. void KEY_Init(void)
  41. {
  42.     GPIO_InitTypeDef GPIO_InitStructure;

  43.     for(uint8_t i = 0; i < KEY_NUMBER; i++)
  44.     {
  45.         RCC_AHBPeriphClockCmd(KEY_GROUP[i].RCCn, ENABLE);

  46.         GPIO_StructInit(&GPIO_InitStructure);
  47.         GPIO_InitStructure.GPIO_Pin  = KEY_GROUP[i].PINn;
  48.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  49.         GPIO_Init(KEY_GROUP[i].GPIOn, &GPIO_InitStructure);
  50.     }

  51.     TASK_Append(TASK_ID_KEY, KEY_Scan, 10);
  52. }

  53. uint8_t KEY_Read(uint8_t Index)
  54. {
  55.     return GPIO_ReadInputDataBit(KEY_GROUP[Index].GPIOn, KEY_GROUP[Index].PINn);
  56. }

  57. void KEY_SubScan(uint8_t Index)
  58. {
  59.     /* 读取当前的按键值 */
  60.     uint8_t Value = KEY_Read(Index);

  61.     switch(UserKEY[Index].State)
  62.     {
  63.         /*
  64.          * 在没有按键被按下的状态, 检测到有按键被按下, 进行消抖处理, 然后切换状态
  65.          */
  66.         case KEY_STATE_IDLE:
  67.             if(Value != KEY_GROUP[Index].IDLE)
  68.             {
  69.                 if(UserKEY[Index].Debounce++ == 1)
  70.                 {
  71.                     UserKEY[Index].State    = KEY_STATE_PRESSED;
  72.                     UserKEY[Index].Value    = Value;
  73.                     UserKEY[Index].Debounce = 0;
  74.                 }
  75.             }
  76.             else
  77.             {
  78.                 UserKEY[Index].Debounce = 0;
  79.             }
  80.             break;

  81.         /*
  82.          * 在确认有按键被按下的状态, 仍然检测到有按键被按下, 继续进行消抖处理, 然后切换状态
  83.          * 如果没有检测到有按键被按下, 说明上一个状态读取到的按键值是误触发, 返回到按键IDLE
  84.          */
  85.         case KEY_STATE_PRESSED:
  86.             if(Value == UserKEY[Index].Value)
  87.             {
  88.                 if(UserKEY[Index].Debounce++ == 1)
  89.                 {
  90.                     UserKEY[Index].State    = KEY_STATE_RELEASE;
  91.                     UserKEY[Index].Debounce = 0;
  92.                     UserKEY[Index].Interval = 100;     /* 长按触发时间 */
  93.                     UserKEY[Index].Trigger  = 0;
  94.                 }
  95.             }
  96.             else
  97.             {
  98.                 UserKEY[Index].State    = KEY_STATE_IDLE;
  99.                 UserKEY[Index].Debounce = 0;
  100.             }
  101.             break;

  102.         /*
  103.          * 在这个状态就是确认有按键被按下, 等待按键被释放的状态; 根据按键被按下的时间长短,
  104.          * 来判断当前是短按还是长按, 是否触发长按检测和处理
  105.          */
  106.         case KEY_STATE_RELEASE:
  107.             if(Value != UserKEY[Index].Value)
  108.             {
  109.                 if(UserKEY[Index].Trigger == 0)
  110.                 {
  111.                     printf("\r\n%s Short Click", KEY_GROUP[Index].Name);
  112.                 }

  113.                 UserKEY[Index].State    = KEY_STATE_IDLE;
  114.                 UserKEY[Index].Value    = 0;
  115.                 UserKEY[Index].Debounce = 0;
  116.                 UserKEY[Index].Interval = 0;
  117.                 UserKEY[Index].Trigger  = 0;
  118.             }
  119.             else
  120.             {
  121.                 if(UserKEY[Index].Debounce++ == UserKEY[Index].Interval)
  122.                 {
  123.                     printf("\r\n%s Long  Click", KEY_GROUP[Index].Name);
  124.                
  125.                     UserKEY[Index].Debounce = 0;
  126.                     UserKEY[Index].Interval = 25;      /* 长按上键时间 */
  127.                     UserKEY[Index].Trigger  = 1;
  128.                 }
  129.             }
  130.             break;

  131.         default: break;
  132.     }
  133. }

  134. void KEY_Scan(void)
  135. {
  136.     for(uint8_t i = 0; i < KEY_NUMBER; i++)
  137.     {
  138.         KEY_SubScan(i);
  139.     }
  140. }

独立按键运行效果2

1.png

矩阵按键

8.png

矩阵按键所使用的MCU资源相比于独立按键要节省很多,缺点就是在一个矩阵中的按键无法实现组合按键检测的功能,按键检测都需要逐一识别,如果真需要实现组合按键的功能,可以先按下某一按键松开后,再一定时间段内再按下其它按键的方式来实现,但这样做在检测单一按键功能的时候,肯定会增加检测单一按键的时长了,如何运用,需要结合项目来取舍了。

4.jpg

矩阵按键实现代码:
  1. void KEY_Init(void)
  2. {
  3.     TASK_Append(TASK_ID_KEY, KEY_Scan, 10);
  4. }

  5. uint8_t KEY_ScanX(void)
  6. {
  7.     uint8_t Value = 0;

  8.     GPIO_InitTypeDef GPIO_InitStructure;

  9.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

  10.     /* 配置X为下拉输入模式 */
  11.     GPIO_StructInit(&GPIO_InitStructure);
  12.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  13.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPD;
  14.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  15.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);

  16.     /* 配置Y为输出模式 */
  17.     GPIO_StructInit(&GPIO_InitStructure);
  18.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_10;
  19.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  20.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  21.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  22.     /* Y输出高电平 */
  23.     GPIO_WriteBit(GPIOB, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_10, Bit_SET);

  24.     if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4) == Bit_SET) Value |= 0x01;
  25.     if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5) == Bit_SET) Value |= 0x02;
  26.     if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) == Bit_SET) Value |= 0x04;
  27.     if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7) == Bit_SET) Value |= 0x08;

  28.     return Value;
  29. }

  30. uint8_t KEY_ScanY(void)
  31. {
  32.     uint8_t Value = 0;

  33.     GPIO_InitTypeDef GPIO_InitStructure;

  34.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

  35.     /* 配置X为输出模式 */
  36.     GPIO_StructInit(&GPIO_InitStructure);
  37.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  38.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  39.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  40.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  41.     /* X输出低电平 */
  42.     GPIO_WriteBit(GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7, Bit_RESET);

  43.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);

  44.     /* 配置Y为上拉输入模式 */
  45.     GPIO_StructInit(&GPIO_InitStructure);
  46.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_10;
  47.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
  48.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  49.     if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0 ) == Bit_RESET) Value |= 0x10;
  50.     if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1 ) == Bit_RESET) Value |= 0x20;
  51.     if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2 ) == Bit_RESET) Value |= 0x40;
  52.     if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) == Bit_RESET) Value |= 0x80;

  53.     return Value;
  54. }

  55. void KEY_Scan(void)
  56. {
  57.     uint8_t KEY_TABLE[16][2] =
  58.     {
  59.         {0x88, '1'}, {0x84, '2'}, {0x82, '3'}, {0x81, 'A'},
  60.         {0x48, '4'}, {0x44, '5'}, {0x42, '6'}, {0x41, 'B'},
  61.         {0x28, '7'}, {0x24, '8'}, {0x22, '9'}, {0x21, 'C'},
  62.         {0x18, '*'}, {0x14, '0'}, {0x12, '#'}, {0x11, 'D'},
  63.     };

  64.     uint8_t Value = KEY_ScanX() | KEY_ScanY();

  65.     for(uint8_t i = 0; i < 16; i++)
  66.     {
  67.         if(Value == KEY_TABLE[i][0])
  68.         {
  69.             printf("\r\nKEY[%c] : 0x%02x", KEY_TABLE[i][1], KEY_TABLE[i][0]);
  70.         }
  71.     }

  72.     while(KEY_ScanX() | KEY_ScanY());   /* 等待按键抬起 */
  73. }

矩阵按键运行效果:

3.png

ADC按键

9.png

ADC按键是最节省MCU资源的一种按键检测方式,在一条ADC通道上按键被按下后,通过改变分压电阻的方式来改变ADC通道的采样电压,不同的电压对应一个按键;ADC按键方式一个ADC通道只占用一个MCU引脚资源,但这种方式虽说节省MCU资源,但在一个ADC通道上也不可以挂载太多的按键,因为在系统运行过程中,ADC的值是存在波动的,为了能够准确的检测出是哪个按键被按下,就需要将分压电阻后的电压值明显的区分开,不能因为系统电压的波动导致按键检测的重叠;在电路设计和元器件选型上,分压电阻需要使用高精度的,在布板时需要考虑系统或者外界的干扰源,尽量减小对按键电压采样的影响,通过合理的分配按键电压节点,可以提升按键挂载数量,以及按键检测的准确度。

6.jpg

ADC按键实现代码:

  1. void KEY_Init(void)
  2. {
  3.     ADC_InitTypeDef  ADC_InitStructure;
  4.     GPIO_InitTypeDef GPIO_InitStructure;

  5.     RCC_APB2PeriphClockCmd(RCC_APB2ENR_ADC1, ENABLE);

  6.     ADC_StructInit(&ADC_InitStructure);
  7.     ADC_InitStructure.ADC_Resolution         = ADC_Resolution_12b;        
  8.     ADC_InitStructure.ADC_PRESCARE           = ADC_PCLK2_PRESCARE_16;         
  9.     ADC_InitStructure.ADC_Mode               = ADC_Mode_Imm;              
  10.     ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  11.     ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;         
  12.     ADC_Init(ADC1, &ADC_InitStructure);

  13.     ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 0, ADC_Samctl_240_5);

  14.     ADC_Cmd(ADC1, ENABLE);

  15.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

  16.     GPIO_StructInit(&GPIO_InitStructure);
  17.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3;
  18.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  19.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AIN;
  20.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  21.     TASK_Append(TASK_ID_KEY, KEY_Scan, 10);
  22. }

  23. uint8_t KEY_Read(void)
  24. {
  25.     uint16_t Value = 0, Delta = 50;

  26.     ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  27.     while(!ADC_GetFlagStatus(ADC1, ADC_IT_EOC));
  28.     ADC_ClearFlag(ADC1, ADC_FLAG_EOC);

  29.     Value = ADC_GetConversionValue(ADC1);

  30.     if(Value < (0 + Delta))
  31.     {
  32.         return 1;
  33.     }
  34.     else if((Value > (570  - Delta)) && (Value < (570  + Delta)))
  35.     {
  36.         return 2;
  37.     }
  38.     else if((Value > (1320 - Delta)) && (Value < (1370 + Delta)))
  39.     {
  40.         return 3;
  41.     }
  42.     else if((Value > (2020 - Delta)) && (Value < (2020 + Delta)))
  43.     {
  44.         return 4;
  45.     }
  46.     else if((Value > (2950 - Delta)) && (Value < (2950 + Delta)))
  47.     {
  48.         return 5;
  49.     }
  50.     else
  51.     {
  52.         return 0;
  53.     }
  54. }

  55. void KEY_Scan(void)
  56. {
  57.     static uint8_t KeyCount = 0;
  58.     static uint8_t KeyState = 0;
  59.     static uint8_t KeyValue = 0;

  60.     char *KEY_NAME[6] = {"NUL", "SW1", "SW2", "SW3", "SW4", "SW5"};

  61.     uint8_t Value = KEY_Read();

  62.     if(KeyState == 0)
  63.     {
  64.         if(Value != 0)
  65.         {
  66.             if(KeyCount++ > 5)
  67.             {
  68.                 KeyCount = 0;
  69.                 KeyState = 1;
  70.                 KeyValue = Value;
  71.             }
  72.         }
  73.         else
  74.         {
  75.             KeyCount = 0;
  76.         }
  77.     }
  78.     else
  79.     {
  80.         if(Value != KeyValue)
  81.         {
  82.             if(KeyCount++ > 5)
  83.             {
  84.                 printf("\r\n%s Clicked", KEY_NAME[KeyValue]);

  85.                 KeyCount = 0;
  86.                 KeyState = 0;
  87.                 KeyValue = 0;
  88.             }
  89.         }
  90.         else
  91.         {
  92.             KeyCount = 0;
  93.         }
  94.     }
  95. }

ADC按键运行效果:

5.png

附件
软件工程源代码: 04.KEY.zip (710.09 KB, 下载次数: 23)


   

打赏榜单

21小跑堂 打赏了 100.00 元 2022-04-08
理由:恭喜通过原创奖文章审核!请多多加油哦!

 楼主| xld0932 发表于 2022-4-7 22:08 | 显示全部楼层
基于MM32分享了3种比较常用的按键检测方式:独立按键检测、矩阵按键检测、ADC按键检测
chenqianqian 发表于 2022-4-9 10:10 来自手机 | 显示全部楼层
学习了,谢谢讲解。
 楼主| xld0932 发表于 2022-4-13 11:50 | 显示全部楼层
chenqianqian 发表于 2022-4-9 10:10
学习了,谢谢讲解。

点击头像“关注我”一起进步,在我的主页可以学习更多技术干货哦
王久强 发表于 2022-4-13 11:59 | 显示全部楼层
楼主,你经常用灵动的单片机做项目吗?有没有什么常规量大的芯片推荐啊?
 楼主| xld0932 发表于 2022-4-13 13:15 | 显示全部楼层
王久强 发表于 2022-4-13 11:59
楼主,你经常用灵动的单片机做项目吗?有没有什么常规量大的芯片推荐啊? ...

我们现在用的是MM32F0140系列的MCU做项目的,具体用哪个芯片根据你的功能需求,问一下灵动的代理了;一般官网上呈现出来的都是主推的吧……
王久强 发表于 2022-4-13 14:52 | 显示全部楼层
好的好的,谢谢
 楼主| xld0932 发表于 2022-4-14 08:45 | 显示全部楼层
本帖最后由 xld0932 于 2022-4-14 13:37 编辑

#申请原创#   @21小跑堂

另外还有几个常见的按键模块如下图所示:

五向控制模块:其中COM端可以连接VCC或者GND,在连接VCC时,GPIO需要设置成IPD模式,判断按下是应该是处于Bit_SET状态;在连接GND时,GPIO需要设置成IPU模式,判断按下时应该是处于Bit_RESET状态。
11.png

4*4矩阵按键:
15.png 16.png

3*4矩阵键盘:
12.png 13.png

4*4矩阵键盘:
12-1.png 14.png


更新软件工程源代码: 04.KEY.zip (710.78 KB, 下载次数: 3)

 楼主| xld0932 发表于 2022-4-29 14:54 | 显示全部楼层
突然想到,还有电容触摸按键在后面再安排分享
tpgf 发表于 2022-5-2 12:00 | 显示全部楼层
怎么去抖的呀
八层楼 发表于 2022-5-2 12:07 | 显示全部楼层
这样做比较节省引脚啊
观海 发表于 2022-5-2 13:09 | 显示全部楼层
一共需要多少个引脚啊
guanjiaer 发表于 2022-5-2 13:21 | 显示全部楼层
整个思路都非常清晰啊
heimaojingzhang 发表于 2022-5-2 14:04 | 显示全部楼层
一般这种使用寿命是多久啊
keaibukelian 发表于 2022-5-2 14:13 | 显示全部楼层
第一次了解ADC按键
 楼主| xld0932 发表于 2022-5-2 16:21 | 显示全部楼层
keaibukelian 发表于 2022-5-2 14:13
第一次了解ADC按键

嗯,用的还挺多的呢
mutable 发表于 2022-5-5 15:18 | 显示全部楼层
之前,还定制过按键了
koala889 发表于 2022-5-15 08:01 | 显示全部楼层
ADC按键,是不是一个adc端可以挂载多个按键
 楼主| xld0932 发表于 2022-5-15 08:13 | 显示全部楼层
koala889 发表于 2022-5-15 08:01
ADC按键,是不是一个adc端可以挂载多个按键

是的,在硬件上每个按键被按下之后所对应的ADC值,应有效的区分开来,不会因为ADC的采样波动而影响按键的误识别

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

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

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