iTOP-STM32MP157开发板采用ST推出的双核cortex-A7+单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板+底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐用,可满足高速信号环境下使用。共240PIN,CPU功能全部引出:底板扩展接口丰富底板板载4G接口(选配)、千兆以太网、WIFI蓝牙模块HDMI、CAN、RS485、LVDS接口、温湿度传感器(选配)光环境传感器、六轴传感器、2路USB OTG、3路串口,CAMERA接口、ADC电位器、SPDIF、SDIO接口等
第二十七章Cortex-M4按键实验
本章节最终所完成的实验例程存放路径为“iTOP- STM32MP157开发板网盘资料汇总\06_Cortex-M4实验例程\03_KEY.zip”。
27.1 什么是按键
按键是一种电子开关,使用时轻轻按开关按钮就可使开关接通,当松开手时, 开关断开。我们开发板上使用的按键及内部简易图如下图所示:
按键管脚两端距离长的表示默认是导通状态,距离短的默认是断开状态,如果按键按下,初始导通状态变为断开,初始断开状态变为导通。
通常的按键所用开关为机械弹性开关,当机械触点断开 、闭合时,电压信号如下图所示:
由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的,一般为 5ms 到 10ms。按键稳定闭合时间的长短则由操作人员的按键动作决定的,一般为零点几秒至数秒。按键抖动会引起按键被误读多次。为了确保 CPU 对按键的一次闭合仅作一次处理,必须进行消抖。
按键消抖有两种方式,一种是硬件消抖,另一种是软件消抖。
软件消抖般来说一个简单的按键消抖就是先读取按键的状态,如果得到按键按下之后,延时 10ms,再次读取按键的状态,如果按键还是按下状态,那么说明按键已经按下。
硬件消抖就是在按键上并联一个电容,如下图所示,利用电容的充放电特性来对抖动过程中产生的电压毛刺进行平滑处理,从而实现消抖。
在我们的开发板上两种消抖方式都有采用,如下图所示:
PWRON1、PWRON2、PWRON3使用的为软件消抖,而B1使用的为硬件消抖。由于B1对应的功能为核心板的电源管理的逻辑控制,所以我们在此不将B1作为用户按键来使用。
27.2 实验目的
1)STM32CubeIDE工具软件的熟悉
2)GPIO口读取按键状态
27.3 按键电路的分析
iTOP-STM32MP157开发板板载了5个输入按键,默认为高电平,按下去的时候为低电平(这里并没有列出复位按键和B1),原理如下图所示:
我们以PWRON3为例,默认状态下按键为弹起状态,IO口和3.3V的电位相同,为高电平,当按键 PWRON3按下时,+3.3V 通过电阻 R22 然后再通过按键PWRON3最终进入 GND 形成一条通路,那么这条线路的全部电压都加到了R22这个电阻上,DCMI_D8这个引脚就是个低电平。当松开按键后,线路断开,就不会有电流通过,那么 PWRON3和+3.3V 又恢复为等电位,是一个高电平。我们就可以通过 DCMI_D8这个 IO 口的高低电平来判断是否有按键按下。
三个用户按键原理图对应的控制引脚为:
原理图名称 | PWRON2 | PWRON1 | PWRON3 |
按键名称 | BACK | VOL-UP | VOL-DN |
引脚名称 | PI2 | DCMI_D10 | DCMI_D8 |
对应引脚 | PI2 | PI3 | PI1 |
在本小节所要实现功能为,通过三个输入按键来分别控制LED2、LED3和BEEP的状态,当按下VOL-UP按键时会使LED2的状态反转,当按下VOL-DN按键时会使LED3的状态反转,当按下BACK按键时会使蜂鸣器的状态反转,以下为LED和蜂鸣器对应的控制引脚:
BEEP | LED2 | LED3 |
PI11 | PE14 | PE1 |
27.4 实验步骤
27.4.1建立KEY工程
首先我们打开STM32CubeIDE软件,进入软件界面之后,我们点击File属性,选择NEW下的STM32 Project的选项,如下图所示:
然后我们会进入下图所示界面:在Part Number选择框输入STM32MP157A,然后在右边的选择界面选择STM32MP157AAA,然后点击Next选项
在Project Name框中输入工程名字KEY,然后点击Finish选项即可,如下图所示:
等待工程创建完毕,会询问我们是否要安装OpenSTLinux ,由于我们是在windows环境下,所以我们不需要安装,点击NO即可
至此我们的工程创建完毕,进入工程界面如下图所示界面:
27.4.2 GPIO功能引脚配置
27.4.2.1输出引脚的配置(LED和蜂鸣器)
首先我们在下面的搜索框之中输入我们要配置的引脚,我们在这里以PE1为例进行搜索,输入名称之后,对应的引脚在工程中会闪烁,如下图所示:
然后我们使用鼠标左键点击对应的引脚会弹出PE1的复用功能选择,我们在这里选择复用为GPIO_Output功能,如下图所示:
配置完复用功能之后,我们还要配置 Pin Reserved 选项,如果不配置此项,在生成工程代码的时候将不会看到有关这个 Pin 的初始化代码。继续选中 PE1,右键弹出设置项,我们选择Pin ReservedàCortex-M4。如下图所示:
第二个LED的控制管脚PE14按同样的方法进行配置。
配置完成之后打开左侧菜单的 System CoreàGPIO 进入 GPIO 模式配置界面:如下图所示:
点击对应的引脚配置之后会弹出右下方的管脚配置界面,如上图所示:
在下方会列出要配置选项的具体说明和我们要进行的配置。
1)选项 GPIO output level 用来设置IO口的输出电平的高低,这这里我们选择LOW
2)选项 GPIO mode 用来设置 IO 口输出模式为 Output Push Pull(推挽)还是 Output Open Drain(开漏)。本实验我们设置为推挽输出 Output Push Pull。
3)选项 GPIO Pull-up/Pull-down 用来设置 IO 口是上拉/下拉/没有上下拉。本实验我们设置为上拉(Pull-up)。
4)选项 Mzximum ouput speed 用来设置 IO 口输出速度为低速(Low)/中速(Medium)/高速 (Hign)/快速(Very High)。我们设置为高速 High 。
5)选项 User Label 是用来设置初始化的 IO 口 Pin 值为我们自定义的宏,这里我们填写为 LED3。按照如上要求设置后的界面如下(由于PE14的配置相同,只是最后的Label值不同,也在下方列了出来):
然后我们继续在搜索框之中输入PI11进行搜索,输入名称之后,对应的引脚在工程中会闪烁,如下图所示:
然后我们使用鼠标左键点击对应的引脚会弹出PI11的复用功能选择,我们在这里选择复用为GPIO_Output功能,如下图所示:
配置完复用功能之后,我们还要配置 Pin Reserved 选项,如果不配置此项,在生成工程代码的时候将不会看到有关这个 Pin 的初始化代码。继续选中 PI11,右键弹出设置项,我们选择Pin ReservedàCortex-M4。如下图所示:
配置完成之后打开左侧菜单的 System CoreàGPIO 进入 GPIO 模式配置界面,跟配置LED的步骤相同,配置完成如下图所示:
27.4.2.2输入引脚的配置(按键)
首先我们在下面的搜索框之中输入我们要配置的引脚,我们在这里以PI2为例进行搜索(由于三个按键的配置相同,在这里我们只是列出了BACK按键的配置步骤),输入名称之后,对应的引脚在工程中会闪烁,如下图所示:
然后我们使用鼠标左键点击对应的引脚会弹出PI2的复用功能选择,我们在这里选择复用为GPIO_Input功能,如下图所示:
配置完复用功能之后,我们还要配置 Pin Reserved 选项,如果不配置此项,在生成工程代码的时候将不会看到有关这个 Pin 的初始化代码。继续选中 PI2,右键弹出设置项,我们选择Pin ReservedàCortex-M4。如下图所示:
VOL-UP和VOL-DN对应的PI3和PI1引脚按同样的方法进行配置。在此就不一一展示。
配置完成之后打开左侧菜单的 System CoreàGPIO 进入 GPIO 模式配置界面:如下图所示:
选项 GPIO Pull-up/Pull-down 用来设置 IO 口是上拉/下拉/没有上下拉。本实验我们设置为上拉(Pull-up)。
选项 User Label 是用来设置初始化的 IO 口 Pin 值为我们自定义的宏,这里我们填写为VOL-DN。按照如上要求设置后的界面如下(由于PI2和PI3的配置相同,只是最后的Label值不同,也在下方列了出来):
配置完成之后我们需要在Project Manage下的Code Generator选项下勾选 Generate peripheral initialization as a pair of ".c/.h' files per peripheral 选项,这样可以独立生成对应外设的初始化.h 和.c 文件(方便配置的查看),如下图所示:
27.4.3工程的生成与完善
在上述的步骤完成之后,按下键盘的“Ctrl+S”组合键保存保存 KEY.ioc 文件,系统开始生成初始化代码,工程生成之后如下图所示:
然后我们进行工程的完善,以及添加对应的逻辑代码。
27.4.3.1 对应文件与文件夹的添加
首先在左侧的工程浏览页之中通过鼠标右键在KEY_CM4的Core目录下创建名字为BSP的文件,具体步骤如下图所示:
由于我们前两个章节已经完善了对应的LED和BEEP的文件,所以我们将iTOP-STM32MP157开发板网盘资料汇总\06_Cortex-M4实验例程\01_LED\LED\CM4\Core\BSP目录下和iTOP-STM32MP157开发板网盘资料汇总\06_Cortex-M4实验例程\02_BEEP\BEEP\CM4\Core\BSP目录下对应的.c、.h文件拷贝到当前工程的BSP目录下,拷贝完成如下下图所示:
然后在BSP目录下以创建key.c文件,在Include目录下的key.h文件,创建完成如下图所示:
27.4.3.2 key.h文件的完善
我们对key.h文件进行代码的添加,将以下内容复制到key.h文件之中如下图所示:
#ifndef __KEY_H
#define __KEY_H
#include "gpio.h"
#define BACK HAL_GPIO_ReadPin(BACK_GPIO_Port, BACK_Pin)
#define VOL_DN HAL_GPIO_ReadPin(VOL_DN_GPIO_Port, VOL_DN_Pin)
#define VOL_UP HAL_GPIO_ReadPin(VOL_UP_GPIO_Port, VOL_UP_Pin)
#define BACK_PRES 1
#define VOL_DN_PRES 2
#define VOL_UP_PRES 3
uint8_t key_scan();
#endif
下面我们将对该文件进行简单的讲解:
在第4行,我们引用了gpio.h文件,我们进入gpio.c文件之中,文件路径如下图所示:
在对应的位置下会看到MX_GPIO_Init()函数,很明显的可以看出该函数正是我们在5.4.2小节之中所配置的功能。
返回key.h文件之中,在6-8行便是三个宏定义,作用是用来读取对应引脚的电平值,具体功能的实现是通过函数HAL_GPIO_ReadPin。
在stm32mp1xx_hal_gpio.c文件之中可以找到HAL_GPIO_ReadPin的定义如下图所示
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIO_PinState bitstatus;
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
{
bitstatus = GPIO_PIN_SET;
}
else
{
bitstatus = GPIO_PIN_RESET;
}
return bitstatus;
}
HAL_GPIO_ReadPin函数所实现的功能就是读取对应引脚的高低电平。
27.4.3.3 key.c文件的完善
在key.c文件下,添加以下内容,以下内容实现的功能为定义key_scan函数,该函数用来实现按键的扫描,每一个按键按下后,会有不同的返回值,以此来确定按下的按键。
#include "./Include/key.h"
#include "./Include/led.h"
#include "./Include/beep.h"
uint8_t key_scan()
{
static uint8_t key_up = 1;
uint8_t keyval = 0;
if (key_up && (BACK == 0 || VOL_DN == 0 || VOL_UP == 0))
{
HAL_Delay(10);
key_up = 0;
if (BACK == 0) keyval = BACK_PRES;
if (VOL_DN == 0) keyval = VOL_DN_PRES;
if (VOL_UP == 0) keyval = VOL_UP_PRES;
}
else if (BACK == 1 && VOL_UP == 1 && VOL_DN == 1)
{
key_up = 1;
}
return keyval;
}
27.4.3.4 main.c文件的完善
我们要修改的main.c文件路径如下图所示:
打开main.c文件,为了规范我们在/* USER CODE BEGIN Includes */和/* USER CODE END Includes */之间添加以下内容
#include "../BSP/Include/led.h"
#include "../BSP/Include/beep.h"
#include "../BSP/Include/key.h"
添加完成如下图所示:
然后在 /* USER CODE BEGIN 1*/和/* USER CODE END 1 */之间添加以下内容:
uint8_t key;
定义变量key,用来接收按键的返回值。
然后在 /* USER CODE BEGIN 2 */和/* USER CODE END 2 */之间添加以下内容:
beep_init();
led_init();
通过调用led_init()函数来使LED2和LED3的初始状态分别为亮和灭。
通过调用beep_init()函数来使BEEP的初始状态分别为不发声。
然后在/* USER CODE BEGIN 3 */下添加以下逻辑代码
key = key_scan();
if (key)
{
switch (key)
{
case VOL_UP_PRES:
LED2_TOGGLE();
break;
case VOL_DN_PRES:
LED3_TOGGLE();
break;
case BACK_PRES:
BEEP_TOGGLE();
break;
}
}
添加完成如下图所示:
该逻辑代码所实现的功能为当按下VOL-UP按键时会使LED2的状态反转,当按下VOL-DN按键时会使LED3的状态反转,当按下BACK按键时会使蜂鸣器的状态反转
27.4.4工程的编译
在完成以上步骤之后我们点击工具栏的小锤子进行编译,编译图标如下图所示:
编译完成会在下方的终端中显示打印信息,如下图所示:
如果报错,需要自己根据错误的提示信息来进行问题的寻找和改正。
27.4.5工程的调试
由于STM32MP157的裸机部分和一般的单片机有些区别,他没有内部的存储,所以只能在程序编译成功之后,通过debug的方式来进行调试(将程序放在内存之中),调试过程如下:
首先,点击菜单栏中的小甲虫Debug调试按钮,弹出以下界面,
在弹出来的界面,按步骤,选择响应的属性(该步骤为Jlink的步骤,如果是STLink,调试探头选择对应的即可)。如下图所示:
选择完成之后,点击右下角的Debug按钮,点击之后,会进行再一次的编译,编译完成之后会弹出如下内容(作者用的是J-LinK),这里弹出的是J-link关于设备的选择,不同调试器的弹窗可能会不同
在弹出来的界面中,选择Accept接受,会弹出以下内容,继续点击下方的OK。
之后会来到设备选择界面,我们选择Cortex-M4,如下图所示:
选择Cortex-M4之后,点击右下角的OK,会弹出以下界面,选择右下角Switch.
然后会弹出一个新的页面,选择菜单栏的 resume按钮开始调试。
此时,当按下VOL-UP按键时会使LED2的状态反转,当按下VOL-DN按键时会使LED3的状态反转,当按下BACK按键时会使蜂鸣器的状态反转。
如果想关闭调试,则点击菜单栏的终止按钮即可。