硬件部分

从按键的原理图可知,这些按键在没有被按下的时候, GPIO 引脚的输入状态为低电平(按键所在的电路不通,引脚接地),当按键按下时, GPIO 引脚的输入状态为高电平(按键所
在的电路导通,引脚接到电源)。只要我们检测引脚的输入电平,即可判断按键是否被按下。 image.png
使用按键时会产生带波纹信号,需要用软件消抖处理滤波,不方便输入检测。本实验板连接的按键带硬件消抖功能,见图 ,它利用电容充放电的延时,消除了波纹,从而简化软件的处理,软件只需要直接检测引脚的电平即可。

从按键的原理图可知,这些按键在没有被按下的时候, GPIO 引脚的输入状态为低电平(按键所在的电路不通,引脚接地),当按键按下时, GPIO 引脚的输入状态为高电平(按键所在的电路导通,引脚接到电源)。只要我们检测引脚的输入电平,即可判断按键是否被按下。
image.png

软件部分

新建工程

在工程模板中,uesr文件夹下,新建key文件夹。在其中新建.c 和.h文件
image.png
打开程序,在user目录下添加.c文件,并编写#include “bsp_key.h”,魔术棒中添加.h文件,编译。

key.h添加条件编译

  1. #ifndef __BSP_KEY_H
  2. #define __BSP_KEY_H
  3. #endif /*__BSP_KEY_H */

程序

bsp_led.h

  1. #ifndef __BSP_LED_H
  2. #define __BSP_LED_H
  3. #include "stm32f10x.h"
  4. #define LED_G_GPIO_Pin GPIO_Pin_0
  5. #define LED_G_GPIO_PORT GPIOB
  6. #define LED_G_GPIO_CLK RCC_APB2Periph_GPIOB
  7. #define LED_B_GPIO_Pin GPIO_Pin_1
  8. #define LED_B_GPIO_PORT GPIOB
  9. #define LED_B_GPIO_CLK RCC_APB2Periph_GPIOB
  10. #define LED_R_GPIO_Pin GPIO_Pin_5
  11. #define LED_R_GPIO_PORT GPIOB
  12. #define LED_R_GPIO_CLK RCC_APB2Periph_GPIOB
  13. #define ON 1
  14. #define OFF 0
  15. #define LED_G(a) if(a) \
  16. GPIO_ResetBits(LED_G_GPIO_PORT, LED_G_GPIO_Pin); \
  17. else GPIO_SetBits(LED_G_GPIO_PORT, LED_G_GPIO_Pin);
  18. #define LED_B(a) if(a) \
  19. GPIO_ResetBits(LED_B_GPIO_PORT, LED_B_GPIO_Pin); \
  20. else GPIO_SetBits(LED_B_GPIO_PORT, LED_B_GPIO_Pin);
  21. #define LED_R(a) if(a) \
  22. GPIO_ResetBits(LED_R_GPIO_PORT, LED_R_GPIO_Pin); \
  23. else GPIO_SetBits(LED_R_GPIO_PORT, LED_R_GPIO_Pin);
  24. #define LED_G_TOGGLE {LED_G_GPIO_PORT->ODR ^= LED_G_GPIO_Pin;}
  25. #define LED_B_TOGGLE {LED_B_GPIO_PORT->ODR ^= LED_B_GPIO_Pin;}
  26. #define LED_R_TOGGLE {LED_R_GPIO_PORT->ODR ^= LED_R_GPIO_Pin;}
  27. void LED_G_GPIO_Config(void);
  28. void LED_B_GPIO_Config(void);
  29. void LED_R_GPIO_Config(void);
  30. #endif /* __BSP_LED_H */

bsp_key.c

  1. #include "bsp_key.h"
  2. void KEY1_GPIO_Config(void)
  3. {
  4. GPIO_InitTypeDef GPIO_InitStruct;
  5. RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK , ENABLE);
  6. GPIO_InitStruct.GPIO_Pin = KEY1_GPIO_Pin;
  7. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  8. GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStruct);
  9. }
  10. void KEY2_GPIO_Config(void)
  11. {
  12. GPIO_InitTypeDef GPIO_InitStruct;
  13. RCC_APB2PeriphClockCmd(KEY2_GPIO_CLK , ENABLE);
  14. GPIO_InitStruct.GPIO_Pin = KEY2_GPIO_Pin;
  15. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  16. GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStruct);
  17. }
  18. uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
  19. {
  20. if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON)
  21. {
  22. //松手检测
  23. while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
  24. return KEY_ON;
  25. }
  26. else return KEY_OFF;
  27. }

bsp_key.h

  1. #ifndef __BSP_KEY_H
  2. #define __BSP_KEY_H
  3. #include "stm32f10x.h"
  4. #define KEY_ON 1
  5. #define KEY_OFF 0
  6. #define KEY1_GPIO_Pin GPIO_Pin_0
  7. #define KEY1_GPIO_PORT GPIOA
  8. #define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA
  9. #define KEY2_GPIO_Pin GPIO_Pin_13
  10. #define KEY2_GPIO_PORT GPIOC
  11. #define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC
  12. void KEY1_GPIO_Config(void);
  13. void KEY2_GPIO_Config(void);
  14. uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
  15. #endif /*__BSP_KEY_H */

bsp_led.c

  1. //bsp:board support package
  2. #include "bsp_led.h"
  3. void LED_G_GPIO_Config(void)
  4. {
  5. GPIO_InitTypeDef GPIO_InitStruct;
  6. RCC_APB2PeriphClockCmd(LED_G_GPIO_CLK , ENABLE);
  7. GPIO_InitStruct.GPIO_Pin = LED_G_GPIO_Pin;
  8. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  9. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  10. GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct);
  11. }
  12. void LED_B_GPIO_Config(void)
  13. {
  14. GPIO_InitTypeDef GPIO_InitStruct;
  15. GPIO_InitStruct.GPIO_Pin = LED_B_GPIO_Pin;
  16. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  17. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  18. GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct);
  19. }
  20. void LED_R_GPIO_Config(void)
  21. {
  22. GPIO_InitTypeDef GPIO_InitStruct;
  23. GPIO_InitStruct.GPIO_Pin = LED_R_GPIO_Pin;
  24. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  25. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  26. GPIO_Init(LED_G_GPIO_PORT, &GPIO_InitStruct);
  27. }

main.c

  1. #include "stm32f10x.h"
  2. #include "bsp_led.h"
  3. #include "bsp_key.h"
  4. void Delay( uint32_t count)
  5. {
  6. for(;count != 0;count--);
  7. }
  8. //void GreenLed(uint32_t t)
  9. //{
  10. // LED_G(ON);
  11. // LED_B(OFF);
  12. // LED_R(OFF);
  13. // Delay(t);
  14. //}
  15. //void BlueLed(uint32_t t)
  16. //{
  17. // LED_G(OFF);
  18. // LED_B(ON);
  19. // LED_R(OFF);
  20. // Delay(t);
  21. //}
  22. //void RedLed(uint32_t t)
  23. //{
  24. // LED_G(OFF);
  25. // LED_B(OFF);
  26. // LED_R(ON);
  27. // Delay(t);
  28. //}
  29. int main(void)
  30. {
  31. LED_G_GPIO_Config();
  32. LED_B_GPIO_Config();
  33. KEY1_GPIO_Config();
  34. KEY2_GPIO_Config();
  35. while(1)
  36. {
  37. if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_Pin) == KEY_ON)
  38. {
  39. LED_G_TOGGLE;
  40. }
  41. if(Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_Pin) == KEY_ON)
  42. {
  43. LED_B_TOGGLE;
  44. }
  45. }
  46. }

宏定义注意点

定义语句

define LED_G_TOGGLE {LED_G_GPIO_PORT->ODR ^= LED_G_GPIO_Pin;} //大括号,括号内有英文分号

续行符

define LED_R(a) if(a) \
GPIO_ResetBits(LED_R_GPIO_PORT, LED_R_GPIO_Pin); \
else GPIO_SetBits(LED_R_GPIO_PORT, LED_R_GPIO_Pin);

代码中的“\”是 C 语言中的续行符语法,表示续行符的下一行与续行符所在的代码是同一行。代码中因为宏定义关键字“#define”只是对当前行有效,所以我们使用续行符来连接起来,以下的代码是等效的:

define LED_R(a) if(a) GPIO_ResetBits(LED_R_GPIO_PORT, LED_R_GPIO_Pin); \else GPIO_SetBits(LED_R_GPIO_PORT, LED_R_GPIO_Pin);

应用续行符的时候要注意,在“\”后面不能有任何字符(包括注释、空格),只能直接回车。
见玩转stm32第110页