|
汽车零部件采购、销售通信录 填写你的培训需求,我们帮你找 招募汽车专业培训老师
1. 环境准备
正点原子探索者 V2 (STM32F407ZGT6)
STM32CubeMX 6.2.0
STM32CubeIDE 1.14.0
ST-Link V2
2. GPIO功能概述
STM32F407ZG有8个16引脚的GPIO端口,从PA到PH,还有一个12引脚的PI端口,这些GPIO端口都链接在AHB1总线上,最高时钟频率可以达到168MHz(如下图时钟树),GPIO引脚能承受5V电压。
一个端口的16个GPIO引脚的功能可以单独配置,每个引脚的输入/输出数据可以单独读取或输出。一个GPIO引脚的内部结构如下图所示,其内部有双向保护二极管,有可配置的上拉或下拉电阻。每个GPIO引脚可以配置为多种工作模式。
根据数据表中列出的每个I/O端口的具体硬件特性,通用IO(GPIO)端口的每个端口位,可以通过软件在以下几种模式下单独配置:
输入模式
模拟模式
输出模式
复用功能模式
外部中断/事件线
在复位期间和刚好复位后,备用功能和外部中断线不活跃,I/O端口配置为输入浮点模式。 所有GPIO引脚都有微弱的内部上拉和下拉电阻,可以激活或不激活。 在输出或备用模式下,每个IO可以配置为开漏或推挽类型,IO速度可以根据VDD值选择。 所有端口都有外部中断/事件功能。要使用外部中断线,端口必须配置为输入模式。所有可用的GPIO引脚都连接到16个外部中断/事件线,从EXTI0到EXTI15。 外部中断/事件控制器由多达23个边缘检测器(16条线连接到GPIO)组成,用于生成事件/中断请求(每个输入线可以独立配置,以选择类型 ) 。(中断或事件)和相应的触发器事件(上升或下降或两者)。每行也可以被独立屏蔽。
3. 正点原子探索者原理图模块选择
从正点原子的原理图中,选择4个按键,2个LED灯作为本次实验的对象,用4个按键来控制2个LED灯实现不同功能的开关LED灯的效果。
下图所示是4个按键KEY对应的原理图,及相应的配置功能
名称 | 端口 | 引脚功能 | 特性 | 初始电平 | KEY_UP | PA0 | Input mode | Pull-down 下拉 | N/A | KEY2 | PE2 | Input mode | Pull-up 上拉 | N/A | KEY1 | PE3 | Input mode | Pull-up 上拉 | N/A | KEY0 | PE4 | Input mode | Pull-up 上拉 | N/A | Buzzer | PF8 | Output | Pushpull推挽输出, | 初始低电平 | LED1 | PF9 | Output | Pushpull推挽输出, | 初始低电平 | LED2 | PF10 | Output | Pushpull推挽输出, | 初始低电平 |
4. STM32CubeMX配置过程
创建工程:选择STM32F407/417,MCU类型STM32F407ZGTx,封装Package选择LQFP144
找到需要配置的端口PF8,鼠标右键写入自定义的名称
写入Buzzer,作为自定义名称
鼠标左键点击该端口,选择为GPIO_Output,作为输入引脚
同理,按照上述操作,一次吸入名称LED1,LED2,并且将他们选为GPIO_Output
点开左侧System Core选项,找到GPIO功能,按照下图说是方法依次配置输出和输入的GPIO端口
根据原理图,设置按键的GPIO类型,由于KEY0,1,2都是上拉电阻,因此初始时为了保持开关断开,选择上拉电阻,KEY_UP则为下拉电阻
RCC模块配置:高速时钟选择外部晶振。
调试口本例中选用ST-Link,则选择JTAG(4 PIN)
时钟配置:在Input frequency出填写外部晶振8M,在HCLK处填写168MHz,即可自动计算时钟的分频和倍频系数
选择CubeIDE进行编译和调试,如果选用Keil进行调试和编译,则选用MDK-ARM
设置堆栈大小
配置代码生成
5. 代码实现
下面我们用STM32官方IDE(继承开发环境)--STM32CubeIDE来进行代码编写,编译和调试,它集成了STM32CubeMX配置工具和Eclipse集成开发环境,为开发人员提供了一个全面的工具套件来编写、编译和调试STM32微控制器的应用程序。2017年,为了取代被ARM公司Keil工具绑定,ST在当年收购Atollic公司,帮助其在原有的TrueStudio扩展到集编译、调试和仿真等于一体的集成开发环境,并完全面向用户免费,再配合其STM32CubeMX,可以达到从代码配置到调试等各个环节。
keyled.h
#include "main.h"
typedef enum {
KEY_0 = 0,
KEY_1,
KEY_2,
KEY_UP,
KEY_NONE,
} KEYS;
KEYS ScanPressedKey(uint32_t timeout);
#define KEY_WAIT_ALWAYS0
#ifdef LED1_Pin
#define LED1_Toggle() HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin)
#define LED1_ON() HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET)
#endif
#ifdef LED2_Pin
#define LED2_Toggle() HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin)
#define LED2_ON() HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET)
#define LED2_OFF() HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET)
#endif
#ifdef Buzzer_Pin
#define Buzzer_Toggle() HAL_GPIO_TogglePin(Buzzer_GPIO_Port, Buzzer_Pin)
#define Buzzer_ON() HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET)
#define Buzzer_OFF() HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET)
#endif
keyled.c
#include "keyled.h"
/**
* Scans 4 keys in a polling fashion and returns the key value.
* timeout = 0 (ms) - If timeout = 0, it scans until a key is pressed.
*/
KEYS ScanPressedKey(uint32_t timeout)
{
KEYS key = KEY_NONE;
uint32_t tickstart = HAL_GetTick(); /* Get the Current time */
const uint32_t binDelay = 20; /* Delay time for Key shake off */
while (1)
{
#ifdef KEY0_Pin
if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(binDelay);
if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
return KEY_0;
}
#endif
#ifdef KEY1_Pin
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(binDelay);
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
return KEY_1;
}
#endif
#ifdef KEY2_Pin
if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(binDelay);
if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET)
return KEY_2;
}
#endif
#ifdef KEY_UP_Pin
if (HAL_GPIO_ReadPin(KEY_UP_GPIO_Port, KEY_UP_Pin) == GPIO_PIN_SET)
{
HAL_Delay(binDelay);
if (HAL_GPIO_ReadPin(KEY_UP_GPIO_Port, KEY_UP_Pin) == GPIO_PIN_SET)
return KEY_UP;
}
#endif
if (timeout != KEY_WAIT_ALWAYS)
{
if ((HAL_GetTick() - tickstart) > timeout)
break;
}
}
return key;
}
添加头文件路径
添加C源文件路径
main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
KEYS curKey = ScanPressedKey(KEY_WAIT_ALWAYS);
switch(curKey)
{
case KEY_0:
LED1_Toggle();
break;
case KEY_1:
LED2_Toggle();
break;
case KEY_2:
LED1_Toggle();
LED2_Toggle();
break;
case KEY_UP:
Buzzer_Toggle();
break;
default:
break;
}
HAL_Delay(200);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
基于以上可以实现用轮询Polling的方式实时检测,按下相应的按键点亮LED灯和关闭LED灯的功能。 |
|