写在前面——
《STM32单片机开发应用教程(HAL库版)—基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第四章4.3 按键控制实验,讲述按键控制的编程方法
官方例程下载:https://pan.baidu.com/s/1QC5BnDgY1m1me6-ihQ_OUQ?pwd=nqb1
提取码:nqb1

目录

  • 4.3 按键控制实验
    • 4.3.1. 实验任务
    • 4.3.2. 硬件连接
    • 4.3.3. GPIO初始化配置(STM32CubeMX)
    • 4.3.4. 应用程序设计(KEIL5)
      • 1. 按键控制LED显示
      • 2. 通用函数---按键扫描函数(含消抖)
      • 3. 按键控制程序设计(长/短按之分)
        • (1)无长/短按之分
        • (2)有长/短按之分
      • 4 .小练习
    • 4.3.5. 小结

4.3 按键控制实验

4.3.1. 实验任务

  1. 简单按键控制:官方例程HAL_02_KEY_TEST,实现4个按键控制对应的LED亮/灭。
  2. 拓展功能:编写按键扫描函数Key_scan、按键服务函数Key_proc,实现按键长/短按之分。

4.3.2. 硬件连接



  开发板上共配备了4个按键,分别连接在PB0,PB1,PB2,PA0引脚上,引脚通过10K的电阻连接在电源正极VDD,按键的另一端连接在电源负极GND。
  可知,在没有按键按下时,对应的GPIO输入高电平,有按键按下时,输入低电平。

4.3.3. GPIO初始化配置(STM32CubeMX)

  参看2.3.1节所述步骤,配置STM32CubeMX相关选项(GPIO、RCC、SYS)。其中, LED涉及的GPIO(PD2、PC8 ~ PC15)全部设置为输出模式。按键对应的GPIO(PB0,PB1,PB2,PA0)全部设置为输入模式。

4.3.4. 应用程序设计(KEIL5)

1. 按键控制LED显示

  参考官方例程2(HAL_02_KEY_TEST),编程思路:

  • 先LED全灭
  • 按键值判别
    根据按键电路原理,按下时则能检测到输入值为0,否则为1,进行各个按键判别。
    因此,先HAL_GPIO_ReadPin()读取某个按键值,再用if语句将读取值与0比较
  • 对应的LED显示控制:某按键值为0,则置对应的LED控制引脚为0(亮)
    关键程序设计如下:
/* USER CODE END 2 */HAL_GPIO_WritePin(GPIOC, GPIO_PIN_All, GPIO_PIN_SET);// GPIO_PIN_All,灯全灭HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);/* Infinite loop *//* USER CODE BEGIN WHILE */while (1){//B1,PB0if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET){HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8 | GPIO_PIN_9, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}//B2,PB1if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == GPIO_PIN_RESET){HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10 | GPIO_PIN_11, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}//B3,PB2if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == GPIO_PIN_RESET){HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12 | GPIO_PIN_13, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}//B4,PA0if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14 | GPIO_PIN_15, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);}}
}

2. 通用函数—按键扫描函数(含消抖)

   上述HAL_02_KEY_TEST例程编程方法,适合简单的按键控制操作。稍复杂的按键控制,一般采用按键扫描方式实现采样按键值。
  按键扫描函数为通用函数,只要涉及有KEY的题目,都需要编写此函数。
  以下按键扫描函数,包含消抖功能(短暂延时前后两次读取按键引脚状态,通过两次按键值是否一致,判断按键是否被正确按下),实现4个按键按下后,输出值分别为0/1/2/3/4。
  在main.c中用户添加代码区添加以下代码:

uint8_t Key_Scan(void) //按键扫描函数
{   if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == 0) //PB0 (按键B1)被按下{HAL_Delay(10);//延时消抖if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == 0){//while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == 1); //等待按键抬起return 1;//返回1}}if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0) //PB1 (按键B2)被按下{HAL_Delay(10);//延时消抖if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0){//while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 1); //等待按键抬起return 2;//返回2}}if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == 0) //PB2 (按键B3)被按下{HAL_Delay(10);//延时消抖if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == 0){//while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == 1); //等待按键抬起return 3; //返回3}}if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0) //PA0 (按键B4)被按下{HAL_Delay(10);//延时消抖if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0){//while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 1); //等待按键抬起return 4; //返回4}}return 0; //没有按键按下返回0
}

  该程序代码较长,但是简单易懂。建议新手使用。
  其中while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == 1)判断按键是否抬起(未按时按键值为1),看实际情况是否添加它。通常无需判断按键是否抬起。
  为简化代码,可以采用以下程序设计,请自行理解:

uint8_t Key_Scan()
{uint8_t ucVal;if(~HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_All)&0x07){HAL_Delay(10);// 判断B1 B2和B3是否按下if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0))ucVal = 1;if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1))ucVal = 2;if(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2))ucVal =3;}// 判断B4是否按下if(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)){HAL_Delay(10);if(!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0))ucVal = 4;}return ucVal;
}

3. 按键控制程序设计(长/短按之分)

  在按键扫描函数的基础上,根据所得的按键值,再实现相应的控制要求,按键1按下时点亮LED1,按键2按下时点亮LED2,等等。
  这里,看题目要求,是否有长按、短按之分的要求。

(1)无长/短按之分

  在main.c中用户添加代码区编辑按键服务函数KEY_Proc():

uint8_t ucKey,ucKeyLong;    //全局变量定义
void KEY_Proc()
{ucKey = Key_Scan();//将按键扫描函数的返回值传递给全局变量ucKeyif(ucKey != ucKeyLong)//键值改变ucKeyLong = ucKey;//保存键值elseucKey = 0;//清除键值switch(ucKey){case 1:
//在短按时不加松手检测,长按就会不断触发短按的程序while(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0));//等待B1按键抬起
/*这里添加 B1短按操作程序*/
break;/*case 2 ,其他按键控制程序,同上  */}
}

最后在while(1)中调用KEY_Proc();

(2)有长/短按之分

  蓝桥杯赛题中,通常需要长按、短按实现不同按键功能。
  在4.2节阐述sysTICK原理中,我们知道有个全局变量uwTick。当单片机上电后,uwTick自动累加计算(每1ms 自动累加1),数据类型为uint32_t。它是实现延时函数HAL_Delay()的关键变量。
  这里使用全局变量uwTick,进行按键动作的计时,实现长短按键之分。
  在main.c中用户添加代码区编辑按键服务函数KEY_Proc():

uint8_t ucKey,ucKeyLong;    //全局变量定义
uint32_t ulTick_ms;
void KEY_Proc(void)
{ucKey = Key_Scan();ucKey = Key_Scan();      //按键扫描if(ucKey != ucKeyLong)   //该if语句的作用是避免多次重复运行下面的switch语句,可省略{ucKeyLong = ucKey;//ucKeyLong的作用,保存键值ulTick_ms = uwTick;//记录下按键刚被按下时的时间,不能省略}     elseucKey = 0;  /*短按*/switch(ucKEY) { case 1: //添加松手检测,避免长按时不断触发短按的控制程序while(!HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin));    /*这里添加 B1短按的控制程序*/break;/*case 2 ,其他按键短按控制程序  */}
/*长按*/if(uwTick - ulTick_ms > 800)//按下时间超过 0.8s { switch(ucKeyLong) { case 1: while(!HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin)); //松手检测/*这里添加 B1长按操作程序*/break; /*case 2 ,其他按键长按控制程序  */}}
}

  该程序中添加松手检测while(!HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin)),可有效避免长按时不断触发短按的操作任务。
  在此程序框架下,自行添加其他按键控制程序,实现题目的任务要求。

4 .小练习

设置两个电压参数的变量:Max_Volt 和Min_Volt ,取值范围为 0-3.3V,且Max_Volt > Min_Volt 。
B3:定义为“加”按键,当前选择的电压参数加 0.3V。
B4:定义为“减”按键,当前选择的电压参数减 0.3V。

程序设计:按键扫描函数Key_Scan同上,按键控制函数设计如下:

uint8_t ucKey,ucKeyLong,ucPara;    //全局变量定义
void KEY_Proc()
{ucKey = Key_Scan();if(ucKey != ucKeyLong)ucKeyLong = ucKey;elseucKey = 0;switch(ucKey)    {    case 3:if(ucPara == 1)//选中Max_Volt这个参数{if(Max_Volt < 3.3f) //最大值加时考虑上限值3.3Max_Volt += 0.3f;}if(ucPara == 2)    //选中Min_Volt这个参数{Min_Volt += 0.3f;if(Max_Volt - Min_Volt < 0.3f) //最小值加时考虑上限值<Max_voltMin_Volt -= 0.3f;}   break;  case 4:if(ucPara == 1)//选中Max_Volt这个参数{Max_Volt -= 0.3f;if(Max_Volt - Min_Volt < 0.3f) //最大值减时考虑下限值>Min_VoltMax_Volt += 0.3f;}if(ucPara == 2)  //选中Min_Volt这个参数{if(Min_Volt > 0) //最小值减时考虑下限值为0Min_Volt -= 0.3f;   }break;}
}

  最后在while(1)中调用KEY_Proc()。
  注意先给ucPara赋值1或者2,就可对两个电压参数的变量:Max_Volt 和Min_Volt进行按键控制。

4.3.5. 小结

  • 引脚
    PB0 ------> B0
    PB1 ------> B1
    PB2 ------> B2
    PA0 ------> B3
  • 编写按键扫描(含消抖)通用函数Key_scan();
  • 编写按键服务函数Key_proc(),实现各个按键按下对应的功能实现程序。
    注意长按/短按之分、松手判定
    1)按键读取函数:HAL_GPIO_ReadPin();
    2)按键消抖5~10ms即可
    3)检测按键松开
    while(!HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin));

《STM32单片机开发应用教程(HAL库版)—基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第四章4.3 按键控制实验相关推荐

  1. 《STM32单片机开发应用教程(HAL库版)—基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第四章4.9 TIM---输入捕获(脉冲频率测量)实验

    写在前面-- <STM32单片机开发应用教程(HAL库版)-基于国信长天嵌入式竞赛实训平台(CT117E-M4)>第四章4.9 TIM-输入捕获(脉冲频率测量)实验,讲解TIM输入捕获的原 ...

  2. 《STM32单片机开发应用教程(HAL库版)---基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第二章 软件安装与使用

    写在前面-- 作为<STM32单片机开发应用教程(HAL库版)-基于国信长天嵌入式竞赛实训平台(CT117E-M4)>系列之第二章,本章节将介绍开发软件STM32CubeMX和KEIL5的 ...

  3. 《STM32单片机开发应用教程(HAL库版)—基于国信长天嵌入式竞赛实训平台(CT117E-M4)》第四章4.1 LED显示控制实验

    写在前面-- <STM32单片机开发应用教程(HAL库版)-基于国信长天嵌入式竞赛实训平台(CT117E-M4)>第四章4.1,本节将通过LED显示控制实验,学习STM32G431的开发技 ...

  4. STM32单片机开发应用教程 (HAL库版) ---基于国信长天嵌入式竞赛实训平台(CT117E-M4)教程汇总 与第一章 硬件平台简介

    写在前面-- 作为<STM32单片机开发应用教程(HAL库版)-基于国信长天嵌入式竞赛实训平台(CT117E-M4)>教程汇总,第一章将介绍国信长天嵌入式竞赛实训平台(CT117E-M4) ...

  5. HAL库版STM32双轮自平衡车(四) ———— 原理图以及PCB绘制

    系列文章目录 HAL库版STM32双轮自平衡车(一) ---代码思路和PID基础精讲 HAL库版STM32双轮自平衡车(二) --- CubeMX的配置.原理图接线.物料准备 HAL库版STM32双轮 ...

  6. HAL库版STM32双轮自平衡车(三) ———代码精讲

    系列文章目录 编码电机测速 HAL库OLED的使用 HAL库版STM32双轮自平衡车(一) ---代码思路和PID基础精讲 HAL库版STM32双轮自平衡车(二) --- CubeMX的配置.原理图接 ...

  7. HAL库版STM32双轮自平衡车(一) ———代码思路和PID基础精讲

    系列文章目录 HAL库版STM32双轮自平衡车(一) ---代码思路和PID的简单介绍(本篇) HAL库版STM32双轮自平衡车(二) --- CubeMX的配置.原理图接线.物料准备 HAL库版ST ...

  8. HAL库版STM32双轮自平衡车(五) ———— 调参

    系列文章目录 HAL库版STM32双轮自平衡车(一) ---代码思路和PID基础精讲 HAL库版STM32双轮自平衡车(二) --- CubeMX的配置.原理图接线.物料准备 HAL库版STM32双轮 ...

  9. HAL库版STM32双轮自平衡车(二) ——— CubeMX的配置、原理图接线、物料准备

    系列文章目录 编码电机测速 HAL库版 0.96'OLED的使用 HAL库版STM32双轮自平衡车(一) ---代码思路和PID的简单介绍 HAL库版STM32双轮自平衡车(二) --- CubeMX ...

最新文章

  1. 什么是 Design System
  2. Dictionary Serializer(Dictionary 序列化)
  3. mysql按周统计_MySQL按周统计 WEEK 实例
  4. 在一个.net sln中包含多个project,project引用同一个dll导致的错误
  5. 磁盘分区原理:从MBR到GPT
  6. python 整除的数组_计算和可被整除的所有子数组
  7. telnet收发邮件
  8. SQLServer如何在批量插入后,获取批量插入的自增列的值
  9. 打开计算机任务栏有桌面没,打开的窗口在任务栏上显示不出来?解决办法
  10. High-Sierra,MacOS10.13,增加IntelHD3000显存的方法
  11. 智能车学习(2)—— 舵机、电机
  12. 怎么在html中加校验,如何通过W3C验证?
  13. 倪光南华为鸿蒙,院士倪光南谈华为鸿蒙:国产操作系统需要生态支持
  14. 物联网智能家居系统解决方案
  15. 6612345免费网页打印浏览器
  16. 零钱通项目 - 韩老师
  17. 分享应用于桌面闹钟的超低成本MG127蓝牙射频前端芯片
  18. 在贷款行业中,运营商大数据精准获客,是否真实有效呢
  19. 秋招干货|给面试官满分的自我介绍
  20. Windows 下安装 Xdebug 受难记之(1)

热门文章

  1. zutuanxue.com-linux磁盘管理基本管理
  2. Recuva破解版|recuva恢复工具破解免费版下载
  3. OPhone动态壁纸探究
  4. IMX6UL串口RS485半双工模式设置调试过程
  5. 短视频app源码出售swiper.js制作酷炫轮播图
  6. 3.3.14 电压-电流转换电路
  7. FPGA——如何学习FPGA
  8. 51单片机(动态数码管,静态数码管,led交通灯全部点亮)小白试图进阶菜鸟
  9. 循循渐进详解内部类和Lambda表达式
  10. javascript继承实现