GPIO实验代码
100.2.3GPIO实验代码
/* ==================== Core\Inc\main.h ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.h
* @brief : Header for main.c file.
* This file contains the common defines of the application.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
void Error_Handler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define KEY1_Pin GPIO_PIN_3
#define KEY1_GPIO_Port GPIOE
#define KEY2_Pin GPIO_PIN_4
#define KEY2_GPIO_Port GPIOE
#define LED2_Pin GPIO_PIN_5
#define LED2_GPIO_Port GPIOE
#define SUN_Pin GPIO_PIN_11
#define SUN_GPIO_Port GPIOB
#define LED1_Pin GPIO_PIN_5
#define LED1_GPIO_Port GPIOB
#define BEEP_Pin GPIO_PIN_8
#define BEEP_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
/* ==================== Core\Inc\gpio.h ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file gpio.h
* @brief This file contains all the function prototypes for
* the gpio.c file
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __GPIO_H__
#define __GPIO_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_GPIO_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__ GPIO_H__ */
/* ==================== Core\Src\gpio.c ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file gpio.c
* @brief This file provides code for the configuration
* of all used GPIO pins.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "gpio.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/*----------------------------------------------------------------------------*/
/* Configure GPIO */
/*----------------------------------------------------------------------------*/
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : PEPin PEPin */
GPIO_InitStruct.Pin = KEY1_Pin|KEY2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = LED2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = SUN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(SUN_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pins : PBPin PBPin */
GPIO_InitStruct.Pin = LED1_Pin|BEEP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* ==================== Core\Src\main.c ==================== */
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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)
{
// HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
// HAL_Delay(1000);
if(0 == HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin))
{
HAL_Delay(120);
if(0 == HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin))
{
HAL_GPIO_TogglePin(BEEP_GPIO_Port, BEEP_Pin);
}
}
if(0 == HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin))
{
HAL_Delay(120);
if(0 == HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin))
{
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
}
}
if(0 == HAL_GPIO_ReadPin(SUN_GPIO_Port, SUN_Pin))
{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 1);
}else{
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, 0);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
一、实验二
本实验实现三条业务逻辑:KEY1 切换蜂鸣器、KEY2 切换 LED2、光敏模块控制 LED1。引脚和板载电路的有效电平不同,写判断前先列真值表:
| 对象 | 引脚 | 空闲/初始 | 动作状态 |
|---|---|---|---|
| KEY1 | PE3 | 上拉为 1 | 按下接 GND,读 0 |
| KEY2 | PE4 | 上拉为 1 | 按下接 GND,读 0 |
| LED1 | PB5 | 写 1,灭 | 写 0,亮 |
| LED2 | PE5 | 写 1,灭 | 写 0,亮 |
| BEEP | PB8 | 写 0,不响 | 写 1,三极管导通并响 |
| SUN | PB11 | 模块驱动 | 本板实测亮为 0、暗为 1 |
1.1 引脚初始化
GPIO 初始化顺序为:使能 GPIOE/GPIOB/GPIOA 时钟,先设置输出锁存电平,再成组配置输入和输出。GPIOA 本实验没有普通业务引脚,但 SWD 等系统配置或生成器模板可能保留其时钟;实际可根据 .ioc 和生成代码核对。
1.1.1 按键配置为上拉输入模式
PE3、PE4 的按键另一端接 GND:
MCU 内部
3.3 V ──[弱上拉]──┬── PE3/PE4 ── 按键 ── GND
│
└──> 输入缓冲 ──> IDR
松开:弱上拉使输入为 1
按下:按键把输入强拉为 0
弱上拉限制按下时的电流,近似为 3.3 V / Rpull。内部上拉阻值范围较宽,不适合当作精密电阻;线路很长或干扰严重时可使用合适的外部上拉并加强滤波。
代码把两个同端口、同配置的引脚合并初始化:
GPIO_InitStruct.Pin = KEY1_Pin | KEY2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
1.1.2 灯配置为推广输出
这里的“推广输出”仍指推挽输出。PB5 与 PE5 分属 GPIOB、GPIOE,不能在一次 HAL_GPIO_Init() 中共同配置;即使参数相同,也要分别传入各自端口。
两只 LED 均先写 GPIO_PIN_SET,上电默认熄灭,再配置为低速推挽输出。输出端采用内部强驱动,建议 No pull;配套工程生成的 GPIO_PULLUP 不决定 LED 的点亮逻辑。
1.1.3 光敏传感器配置为浮空输入
光敏模块数字输出 DO 接 PB11。模块内部通常由光敏电阻分压、比较器和电位器阈值组成:
flowchart LR
LIGHT[环境光] --> LDR[光敏电阻分压]
POT[电位器阈值] --> CMP[比较器]
LDR --> CMP
CMP --> DO[DO 高/低电平]
DO --> PB11[PB11 浮空数字输入]
“浮空输入”在这里表示 STM32 不再附加内部上拉或下拉,由模块的 DO 主动驱动。若模块输出是开漏而板上没有上拉,浮空就不合适;应查模块原理图或测量空闲电平。本实验现象证明模块能够给出稳定数字电平。
PB8 蜂鸣器脚应配置为推挽输出并默认写低。板上 10 kΩ 基极下拉使 MCU 复位和高阻阶段的三极管保持截止;软件初始化低电平再提供第二层保障。
1.1.4 写代码儿
完整执行关系:
flowchart TD
LOOP[while 1] --> K1{PE3 == 0?}
K1 -- 是 --> D1[延时并复查] --> B[翻转 PB8 蜂鸣器]
K1 -- 否 --> K2
B --> K2{PE4 == 0?}
K2 -- 是 --> D2[延时并复查] --> L2[翻转 PE5 LED2]
K2 -- 否 --> SUN
L2 --> SUN{读取 PB11}
SUN -- 亮处 0 --> OFF[PB5=1,LED1 灭]
SUN -- 暗处 1 --> ON[PB5=0,LED1 亮]
OFF --> LOOP
ON --> LOOP
GPIO_PinState 的定义是 GPIO_PIN_RESET=0、GPIO_PIN_SET=1。直接写枚举名比把函数结果和裸数字 0 比较更清晰。
1.1.4.1 按键控制蜂鸣器开关
-
1.1.4.1.1 读取按键信号
HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)返回引脚的数字状态。读取的是IDR路径,不是输出锁存器。由于 KEY1 低电平有效,判断可以写为:if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) { /* 检测到按下 */ } -
1.1.4.1.2 灯进行反转
本功能实际翻转的是蜂鸣器 PB8:低变高时三极管导通并响,高变低时停止。
HAL_GPIO_TogglePin(BEEP_GPIO_Port, BEEP_Pin)的端口和引脚必须配套,不能把某个端口宏与另一个引脚随意组合。 -
1.1.4.1.3 消抖操作
机械触点在按下和松开瞬间会反复接通/断开。配套代码先检测低电平、延时 120 ms、再检测一次,能滤掉按下沿的一部分抖动:
初次读到低 → 延时 → 再读仍低 → 确认为按下120 ms 是课程开发板的实验取值,不是通用固定值;常见消抖窗口约 5~20 ms,实际应结合按键和交互要求测量。更重要的是,配套代码没有等待按键释放:长按超过 120 ms 时,主循环可能反复翻转。若要求“按一次只切换一次”,应在确认按下后等待释放,或用定时扫描状态机检测按下沿:
RELEASED ──连续稳定低──> PRESSED(只在这里触发一次) PRESSED ──连续稳定高──> RELEASED不要在中断服务函数里使用长时间阻塞延时;可用周期定时器、系统节拍或主循环状态机消抖。
1.1.4.2 按键控制LED2亮灭
控制 LED2 的按键是 PE4/KEY2,不是 PB4;被控 LED2 是 PE5。逻辑与 KEY1 相同:按下读 0,经消抖后调用:
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
由于 LED2 低电平点亮,翻转只是改变亮灭,不必在每次按键中单独计算有效电平。若程序还会从其他位置修改 PE5,则使用明确的状态变量和 WritePin() 更容易保持软件状态与硬件一致。
1.1.4.3 光敏传感器控制LED1亮灭
课程先写一版程序观察极性,再根据现象调整,这是调试数字传感器的有效方法。最终实测关系为:
| PB11/SUN | 光照状态 | 写 PB5 | LED1 |
|---|---|---|---|
| 0 | 较亮 | 1 | 灭 |
| 1 | 较暗 | 0 | 亮 |
配套源码正是这套逻辑。PB5 低电平点亮,所以“给 LED 写 1”代表熄灭,不能把 GPIO 数值直接当成灯的布尔状态。
光敏 DO 持续输出电平,不需要机械按键式消抖,但比较器在阈值附近仍可能因光照波动而快速翻转。若出现闪烁,可调整模块电位器、增加光学/电气迟滞,或在软件中要求状态连续保持若干次后再切换。