STM32--点灯

一、实验前准备

1.1利用STM32Cube创建工程并且打开工程

                                                        注释:配置好所用引脚

1.2ST-Link驱动

1.3下载CH340驱动以及程序下载软件(烧录)

1.4硬件连接

二、LED点亮原理

寿命与亮度有关系,亮度越大导致发热过大会减少LED寿命

为什么:核心原理:LED不是理想的光源

理想的光源会将所有电能100%转换成光能。但LED(以及几乎所有电光源)在实际工作中,其电光转换效率达不到100%。

根据情况对PA8,推挽输出,开漏输出都可以;PA3仅推挽输出

  设置指定GPIO高低电平  由于下图文件使用STM32Cube建立无需使能时钟,引脚初始化因此可使用下述代码,如使用上图方法请参考3.4完整代码展示

  由于上述文件使用STM32Cube建立无需使能时钟,引脚初始化因此可使用上述代码,如使用


 三、设置指定GPIO高低电平的几种方法        

3.1 使用HAL库函数(推荐)

// 设置指定GPIO引脚为低电平
HAL_GPIO_WritePin(GPIOx, GPIO_PIN_x, GPIO_PIN_RESET);

// 示例:设置GPIOA的PIN5为低电平
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

3.2 使用LL库(低层库)

// 设置引脚为低电平
LL_GPIO_ResetOutputPin(GPIOx, GPIO_PIN_x);

// 示例:设置GPIOB的PIN3为低电平
LL_GPIO_ResetOutputPin(GPIOB, GPIO_PIN_3);

3. 3直接操作寄存器

// 使用BSRR寄存器(推荐方式)
GPIOx->BSRR = (GPIO_PIN_x << 16);  // 低16位用于置位,高16位用于复位

// 或使用ODR寄存器
GPIOx->ODR &= ~GPIO_PIN_x;

// 示例:设置GPIOC的PIN8为低电平
GPIOC->BSRR = (GPIO_PIN_8 << 16);
// 或
GPIOC->ODR &= ~GPIO_PIN_8;

3.4 完整示例代码

#include "main.h"
#include "stm32f1xx_hal.h"  // 根据你的芯片系列选择

int main(void)
{
    HAL_Init();

    // 配置GPIO
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();  // 使能GPIOA时钟

    // 配置PA5为推挽输出
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 设置PA5为低电平
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);

    while (1)
    {
        // 主循环
    }
}

注释:STM32 GPIO输出低电平四种方案优缺点对比

方案优点缺点适用场景性能等级
HAL库函数• 代码可读性高
• 跨STM32系列兼容性好
• 易于维护和调试
• 提供完善的错误处理
• 适合初学者
• 执行效率相对较低
• 代码体积较大
• 有函数调用开销
• 实时性稍差
• 快速原型开发
• 跨平台项目
• 团队协作开发
• 对实时性要求不高的应用
★★★☆☆
LL库(低层库)• 执行效率高
• 代码体积小
• 接近寄存器操作的性能
• 保持一定的可移植性
• 较好的实时性
• 可读性不如HAL
• 需要更多硬件知识
• 兼容性稍差于HAL
• 对性能有要求的应用
• 资源受限环境
• 有经验的开发者
• 特定芯片优化
★★★★☆
直接操作寄存器• 最高执行效率
• 最小代码体积
• 最佳实时性
• 完全控制硬件
• 无函数调用开销
• 可读性差
• 可移植性差
• 容易出错
• 调试困难
• 需要深入了解硬件
• 极端性能要求
• 实时性关键应用
• 资深嵌入式工程师
• 特定优化场景
★★★★★
完整示例代码• 包含完整初始化流程
• 适合学习和参考
• 减少配置错误
• 提供完整上下文
• 代码冗长
• 包含不必要部分
• 需要根据实际情况修改
• 学习阶段
• 项目模板
• 调试参考
• 新手入门
★★☆☆☆

性能对比数据表

操作方式执行时间代码大小可维护性学习曲线
HAL库100% (基准)100% (基准)优秀简单
LL库60-70%70-80%良好中等
寄存器30-50%50-60%一般困难

选择指南表

项目阶段推荐方案替代方案关键考量
学习入门HAL库 + 完整示例-易于理解,减少错误
快速原型HAL库LL库开发速度快,调试方便
产品开发LL库HAL库平衡性能和开发效率
性能优化寄存器操作LL库极致性能,资源利用最大化
团队项目HAL库/LL库-代码可维护性强,易于协作

3.5 重要注意事项

  1. 时钟使能:在使用GPIO前必须使能对应GPIO端口的时钟

  2. GPIO配置:需要先将GPIO配置为输出模式

  3. 引脚定义:根据实际使用的引脚修改GPIOxGPIO_PIN_x

3.6 常用GPIO输出模式

  • GPIO_MODE_OUTPUT_PP:推挽输出

  • GPIO_MODE_OUTPUT_OD:开漏输出

对于大多数应用场景,推荐使用HAL库函数,因为代码可读性好且移植性强。

四、拓展

问题:PA8和PA5两个一起的时候亮,而注释掉PA8代码,只留PA5是不亮或者微亮

		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);	
        HAL_Delay(500);
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
		HAL_Delay(500);
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
		HAL_Delay(500);
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
		HAL_Delay(500);
	

1. 最可能的原因:PA5被复用为其他功能

STM32的PA5通常默认用作:

  • ADC输入通道5

  • SPI1 SCK引脚

  • 调试接口

当PA8也在使用时,可能系统配置正确,但单独使用PA5时配置被覆盖。

改用其他引脚

2. 解决方案

方案1:检查并重新配置PA5

c

// 在初始化部分确保PA5正确配置
GPIO_InitTypeDef GPIO_InitStruct = {0};

// 明确配置PA5为输出模式
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  // 重要:推挽输出
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

// 初始状态
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);

方案2:禁用PA5的复用功能

// 如果使用CubeMX,检查这些配置:
// - PA5不应用作ADC
// - PA5不应用于SPI1
// - 调试接口不影响PA5

// 或者在代码中强制禁用ADC
__HAL_RCC_ADC1_CLK_DISABLE();  // 禁用ADC时钟

方案3:完整的初始化修复

c

void GPIO_Init_Fixed(void)
{
    // 使能GPIOA时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 先配置PA8
    GPIO_InitStruct.Pin = GPIO_PIN_8;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 重新配置PA5,确保模式正确
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  // 确保是输出模式
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    // 设置初始状态
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
}

3. 调试步骤

步骤1:检查GPIO配置寄存器

c

// 在调试时查看PA5的配置
uint32_t mode = GPIOA->MODER;    // 模式寄存器
uint32_t otype = GPIOA->OTYPER;  // 输出类型寄存器

// PA5应该配置为输出模式 (01)
// 第10-11位应该是01: 通用输出模式
printf("GPIOA MODER: 0x%08lX\n", mode);
printf("PA5 mode bits: %lu\n", (mode >> 10) & 0x3);

步骤2:使用不同的GPIO引脚测试

c

// 暂时改用其他引脚测试,如PA6、PA7
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);

步骤3:电压测量

  • 用万用表测量PA5单独工作时的电压

  • 正常情况:GPIO_PIN_RESET时应该是0V,GPIO_PIN_SET时应该是3.3V

  • 如果电压异常(如1.5V左右),说明配置错误

4. 如果使用CubeMX配置

在CubeMX中检查:

  1. PA5的Pinout配置:应该是GPIO_Output

  2. System Core → GPIO:PA5配置为Output Push Pull

  3. Analog → ADC:确保PA5没有被用作ADC输入

  4. Connectivity → SPI1:确保PA5没有被用作SPI SCK

5. 最终解决方案

c

#include "main.h"

// 修复PA5配置的函数
void Fix_PA5_Configuration(void)
{
    // 禁用可能影响PA5的外设
    __HAL_RCC_ADC1_CLK_DISABLE();
    __HAL_RCC_SPI1_CLK_DISABLE();

    // 重新配置PA5为输出
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    // 修复PA5配置
    Fix_PA5_Configuration();

    while (1)
    {
        // 现在PA5应该能正常工作了
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
        HAL_Delay(500);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
        HAL_Delay(500);
    }
}

这个问题90%的可能性是PA5被配置为模拟输入模式(ADC默认模式),导致无法输出数字信号。按照上述方法重新配置即可解决!

五、成品展示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值