LED实验
099.2.2LED实验
/* ==================== 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 */
一、LED实验
1.1 实验一灯闪烁
目标是让板载 LED1 周期性亮灭。硬件连接是 PB5,软件需要完成三件事:打开 GPIOB 时钟、把 PB5 配为普通推挽输出、在主循环中周期性改变输出电平。
flowchart LR
RCC[RCC 打开 GPIOB 时钟] --> INIT[PB5 推挽输出\n初始高电平]
INIT --> WRITE[写低或翻转 PB5]
WRITE --> DELAY[延时]
DELAY --> WRITE
1.1.1 按键PE3控制蜂鸣器开关
完整工程后续还使用 PE3 控制 PB8 蜂鸣器;本节先完成其中最简单的 PB5 LED 闪烁。模式判断方法相同:LED 和蜂鸣器控制脚都需要输出数字高/低电平,因此选择普通推挽输出;PE3 是读取按键状态,才配置为上拉输入。
PB5 不能因为“开漏也能拉低 LED”就直接选开漏。本实验还需要可靠输出高电平让 LED 熄灭;使用推挽输出能主动拉高、主动拉低,不依赖外部上拉形成高电平。
1.1.2 新建工程
工程配置要点:
- 选择 STM32F103ZET6/LQFP144;
SYS → Debug选择Serial Wire,保留 SWD 下载调试;- RCC 的 HSE 选择
Crystal/Ceramic Resonator; - 时钟树配置为 HSE 8 MHz、PLL ×9、SYSCLK 72 MHz,APB1 分频为 2;
- 在
Project Manager → Code Generator中按课程方式为各外设生成独立.c/.h; - PB5 设置为
GPIO_Output。
只填写“72”并不保证所有时钟都正确。生成前还应确认没有红色超限提示,尤其是 PCLK1 不超过 36 MHz、Flash 延迟为 2 个等待周期。
1.1.3 配置推广输出模式
这里的“推广输出”指推挽输出(Push-Pull)。PB5 参数建议:
| 参数 | 配置 | 原因 |
|---|---|---|
| Output Level | High | 板载 LED 为低电平点亮,上电先灭 |
| GPIO mode | Output Push Pull | 主动输出高、低电平 |
| Pull-up/Pull-down | No pull 或保持生成配置 | 推挽输出由输出级强驱动,内部弱上下拉不是决定因素 |
| Maximum output speed | Low | LED 慢速开关不需要快边沿,可减少 EMI 和瞬态电流 |
| User Label | LED1 | 生成可读的 LED1_Pin、LED1_GPIO_Port |
STM32F1 的输出速度编码为 2/10/50 MHz 最大速率。HAL 中 GPIO_SPEED_FREQ_LOW 对应 2 MHz。这是输出边沿/驱动配置,不代表调用写引脚函数后自动产生 2 MHz 方波。
1.1.4 电路图
开发板的 LED1 连接如下:
3.3 V ── LED1 ── R2 1 kΩ ── PB5
阳极 GPIO 灌电流
PB5 = 0 V:3.3 V → LED1 → 1 kΩ → PB5 → GND,灯亮
PB5 = 3.3 V:回路两端压差接近 0,灯灭
这称为“低电平有效”或“灌电流点亮”。它与常见的 GPIO → 电阻 → LED → GND 高电平点亮电路方向相反,所以写代码前一定要看原理图。
LED 电流可粗略估算为:
$I_{LED}\approx\frac{3.3\text{ V}-V_F-V_{OL}}{1\text{ k}\Omega}$
假设绿色 LED 正向压降约 2.0 V、PB5 低电平压降较小,电流约为 1.3 mA。实际值随 LED、GPIO 输出能力和温度变化;精确设计要查器件参数。
推挽输出低电平时,STM32 内部 NMOS 导通,电流从板上 3.3 V 流入 PB5 再到地;高电平时内部 PMOS 导通,把 PB5 拉向 VDD。限流电阻 R2 保护 LED 和 GPIO,不能省略。
1.1.5 生成代码
生成后的关系是:
main.h:LED1_Pin = GPIO_PIN_5,LED1_GPIO_Port = GPIOB
gpio.c:打开 GPIOB 时钟,先写高电平,再配置 PB5 推挽低速输出
main.c:调用 MX_GPIO_Init(),在 while(1) 中实现闪烁
先设置输出锁存值、再切换为输出模式,可以减少初始化瞬间的错误脉冲。__HAL_RCC_GPIOB_CLK_ENABLE() 必须在配置 GPIOB 寄存器之前执行。
源码中输出模式虽然填写了 GPIO_PULLUP,但在 STM32F1 的普通推挽输出配置中,高低电平由输出驱动级和 ODR 决定;内部上拉/下拉主要用于输入模式。为了表达意图更清楚,实际工程可在图形界面选择 No pull。
1.1.6 应用案例
1.1.6.1 例题: GPIO库函数应用
HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState) 有三个参数:端口、引脚掩码和目标状态。推荐使用枚举名而不是裸写 0/1:
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET); /* PB5=0,LED1 亮 */
HAL_Delay(1000);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); /* PB5=1,LED1 灭 */
HAL_Delay(1000);
HAL_Delay(1000) 的单位是毫秒,依赖 HAL 时基中断正常运行。如果全局中断被长时间关闭,或在高优先级中断中不当调用,它可能无法按预期返回。
用户逻辑必须放在对应的 USER CODE BEGIN / END 保护区内,尤其是主循环代码。生成器注释本身也是保留位置的标记,不要删除。
1.1.6.2 例题: GPIO写入不同电平
HAL_GPIO_WritePin() 在 STM32F1 HAL 中使用 BSRR/BRR 完成置位或复位,避免对整个 ODR 做一次易受并发影响的读—改—写。
GPIO_PIN_SET → 写 BSRR 对应位 → ODR 位置 1 → PB5 高 → LED 灭
GPIO_PIN_RESET → 写 BRR 对应位 → ODR 位清 0 → PB5 低 → LED 亮
第二个参数是位掩码,因此可以把多个同端口引脚用按位或组合,一次设为相同状态;不同 GPIO 端口不能放进同一次调用。
1.1.6.3 例题: GPIO灯电极反转
正确函数名是 HAL_GPIO_TogglePin(),不是 token。它读取当前 ODR 状态并把指定引脚翻转:
while (1)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
HAL_Delay(1000);
}
初始值为高时,第一次翻转变低,LED 亮;下一次变高,LED 灭。若其他执行路径也会改同一引脚,翻转后的绝对状态可能不易判断,此时直接写 SET/RESET 更清晰。