欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > STM32单片机芯片与内部03 GPIO-LED控制-硬件、库函数配置、HAL库配置

STM32单片机芯片与内部03 GPIO-LED控制-硬件、库函数配置、HAL库配置

2025/2/23 22:10:15 来源:https://blog.csdn.net/qq_39376872/article/details/144232228  浏览:    关键词:STM32单片机芯片与内部03 GPIO-LED控制-硬件、库函数配置、HAL库配置

目录

 一、硬件连接与基本原理

二、库函数工程模板

1、GPIO Init structure definition

2、时钟使能

3、配置输出模式、速度

4、初始化

5、设定高低电平

三、库函数API

1、API简介

2、初始化封装

3、输出高低电平封装

五、HAL库工程模板

 1、GPIO Init structure definition

2、时钟使能

3、配置输出模式、速度

4、初始化

5、设定高低电平

六、HAL库API

1、初始化封装

2、输出高低电平封装

七、用户侧

1、库函数

2、HAL库

 3、用户


 一、硬件连接与基本原理

        PB5和PE5,输出高点平则LED关闭,输出低电平LED点亮。

二、库函数工程模板

        stm32f10x_gpio.c、stm32f10x_gpio.h为核心。

1、GPIO Init structure definition

typedef struct
{uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.This parameter can be any value of @ref GPIO_pins_define */GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.This parameter can be a value of @ref GPIOSpeed_TypeDef */GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

        首先是配置,刚才前文讲了其实GPIO可以配置的就是模式和速度,除此之外还有引脚,因此可以封装为结构体。

2、时钟使能

        前文未进行阐述这个部分,其实很简单的输出有速度,输出有各类时序电路其都需要时钟进行支撑,而对于前面提到的PB5和PE5,其本质也有对应的端口时钟,其挂载在APB2,这个具体在后文进行介绍。

#define RCC_APB2Periph_AFIO              ((uint32_t)0x00000001)
#define RCC_APB2Periph_GPIOA             ((uint32_t)0x00000004)
#define RCC_APB2Periph_GPIOB             ((uint32_t)0x00000008)
#define RCC_APB2Periph_GPIOC             ((uint32_t)0x00000010)
#define RCC_APB2Periph_GPIOD             ((uint32_t)0x00000020)
#define RCC_APB2Periph_GPIOE             ((uint32_t)0x00000040)
#define RCC_APB2Periph_GPIOF             ((uint32_t)0x00000080)
#define RCC_APB2Periph_GPIOG             ((uint32_t)0x00000100)
#define RCC_APB2Periph_ADC1              ((uint32_t)0x00000200)
#define RCC_APB2Periph_ADC2              ((uint32_t)0x00000400)
#define RCC_APB2Periph_TIM1              ((uint32_t)0x00000800)
#define RCC_APB2Periph_SPI1              ((uint32_t)0x00001000)
#define RCC_APB2Periph_TIM8              ((uint32_t)0x00002000)
#define RCC_APB2Periph_USART1            ((uint32_t)0x00004000)
#define RCC_APB2Periph_ADC3              ((uint32_t)0x00008000)
#define RCC_APB2Periph_TIM15             ((uint32_t)0x00010000)
#define RCC_APB2Periph_TIM16             ((uint32_t)0x00020000)
#define RCC_APB2Periph_TIM17             ((uint32_t)0x00040000)
#define RCC_APB2Periph_TIM9              ((uint32_t)0x00080000)
#define RCC_APB2Periph_TIM10             ((uint32_t)0x00100000)
#define RCC_APB2Periph_TIM11             ((uint32_t)0x00200000)#define RCC_APB1Periph_TIM2              ((uint32_t)0x00000001)
#define RCC_APB1Periph_TIM3              ((uint32_t)0x00000002)
#define RCC_APB1Periph_TIM4              ((uint32_t)0x00000004)
#define RCC_APB1Periph_TIM5              ((uint32_t)0x00000008)
#define RCC_APB1Periph_TIM6              ((uint32_t)0x00000010)
#define RCC_APB1Periph_TIM7              ((uint32_t)0x00000020)
#define RCC_APB1Periph_TIM12             ((uint32_t)0x00000040)
#define RCC_APB1Periph_TIM13             ((uint32_t)0x00000080)
#define RCC_APB1Periph_TIM14             ((uint32_t)0x00000100)
#define RCC_APB1Periph_WWDG              ((uint32_t)0x00000800)
#define RCC_APB1Periph_SPI2              ((uint32_t)0x00004000)
#define RCC_APB1Periph_SPI3              ((uint32_t)0x00008000)
#define RCC_APB1Periph_USART2            ((uint32_t)0x00020000)
#define RCC_APB1Periph_USART3            ((uint32_t)0x00040000)
#define RCC_APB1Periph_UART4             ((uint32_t)0x00080000)
#define RCC_APB1Periph_UART5             ((uint32_t)0x00100000)
#define RCC_APB1Periph_I2C1              ((uint32_t)0x00200000)
#define RCC_APB1Periph_I2C2              ((uint32_t)0x00400000)
#define RCC_APB1Periph_USB               ((uint32_t)0x00800000)
#define RCC_APB1Periph_CAN1              ((uint32_t)0x02000000)
#define RCC_APB1Periph_CAN2              ((uint32_t)0x04000000)
#define RCC_APB1Periph_BKP               ((uint32_t)0x08000000)
#define RCC_APB1Periph_PWR               ((uint32_t)0x10000000)
#define RCC_APB1Periph_DAC               ((uint32_t)0x20000000)
#define RCC_APB1Periph_CEC               ((uint32_t)0x40000000)

        通过如下配置即可实现开启APB2上的GPIOB和GPIOE的时钟。

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟

3、配置输出模式、速度

typedef enum
{ GPIO_Mode_AIN = 0x0,GPIO_Mode_IN_FLOATING = 0x04,GPIO_Mode_IPD = 0x28,GPIO_Mode_IPU = 0x48,GPIO_Mode_Out_OD = 0x14,GPIO_Mode_Out_PP = 0x10,GPIO_Mode_AF_OD = 0x1C,GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;
typedef enum
{ GPIO_Speed_10MHz = 1,GPIO_Speed_2MHz, GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

        可以看到在库函数已进行了响应的封装,具有了各类的配置。

4、初始化

        可以看到在GPIO_Init(GPIOB, &GPIO_InitStructure)前面是对PB进行了配置,后面配置PE5的时候,结构体本质上只有IO、速度、模式的区别,在均相同的时候,直接初始化即可,修改好GPIOB、GPIOE即可。

 GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //LED0-->PB.5 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	    		 //LED1-->PE.5GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHzGPIO_Init(GPIOE, &GPIO_InitStructure);	  				 //根据设定参数初始化GPIOE.5

        例如可以修改为:

 GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //LED0-->PB.5 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5GPIO_Init(GPIOE, &GPIO_InitStructure);	  				 //根据设定参数初始化GPIOE.5

5、设定高低电平

        前文提到,本质上要设定BSRR寄存器和BRR寄存器,这个部分库函数也进行了相关的封装。

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{/* Check the parameters */assert_param(IS_GPIO_ALL_PERIPH(GPIOx));assert_param(IS_GPIO_PIN(GPIO_Pin));GPIOx->BSRR = GPIO_Pin;
}
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{/* Check the parameters */assert_param(IS_GPIO_ALL_PERIPH(GPIOx));assert_param(IS_GPIO_PIN(GPIO_Pin));GPIOx->BRR = GPIO_Pin;
}

三、库函数API

1、API简介

        API(应用程序编程接口)是软件系统中不同部分之间通信的一套规则。它定义了请求的格式、传输方式、数据结构和操作规则,使得不同的软件应用能够相互交互和数据交换。

        因此如何设计前文的初始化使得用户层可以不用管底层配置,从而直接调用很重要。

2、初始化封装

void LED_Init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //LED0-->PB.5 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHzGPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5GPIO_SetBits(GPIOB,GPIO_Pin_5);						 //PB.5 输出高GPIO_Init(GPIOE, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHzGPIO_SetBits(GPIOE,GPIO_Pin_5); 						 //PE.5 输出高 
}

        可以看到封装为LED_Init,用户侧基本上直接调用即可。

LED_Init();		  	//初始化与LED连接的硬件接口

3、输出高低电平封装

        除了初始化一次性配置外,对于GPIO输出高低电平肯定是要进行重复的操作的。直接看GPIO_SetBits、GPIO_ResetBits本质上还是官方提供的函数名,不适合用户侧去直观使用,可以进行额外封装。封装后几乎隔离了PB5的概念。

void LED0_HIGH()
{GPIO_SetBits(GPIOB,GPIO_Pin_5);
}
void LED1_HIGH()
{GPIO_SetBits(GPIOE,GPIO_Pin_5);
}
void LED0_LOW()
{GPIO_ResetBits(GPIOB,GPIO_Pin_5);
}
void LED1_LOW()
{GPIO_ResetBits(GPIOE,GPIO_Pin_5);
}

        后续如果要添加额外内容,即可在LED_HIGH、LED_LOW内进行编写即可。

五、HAL库工程模板

        stm32f1xx_hal_gpio.c、 stm32f1xx_hal_gpio.h为核心。其实HAL就是更深层次的封装,进一步隔离了BSP和用户层。

 1、GPIO Init structure definition

typedef struct
{uint32_t Pin;       /*!< Specifies the GPIO pins to be configured.This parameter can be any value of @ref GPIO_pins_define */uint32_t Mode;      /*!< Specifies the operating mode for the selected pins.This parameter can be a value of @ref GPIO_mode_define */uint32_t Pull;      /*!< Specifies the Pull-up or Pull-Down activation for the selected pins.This parameter can be a value of @ref GPIO_pull_define */uint32_t Speed;     /*!< Specifies the speed for the selected pins.This parameter can be a value of @ref GPIO_speed_define */
} GPIO_InitTypeDef;

        首先是配置,刚才前文讲了其实GPIO可以配置的就是模式和速度,除此之外还有引脚,因此可以封装为结构体。相比较于库函数,其增加了Pull作为上下拉的配置。

2、时钟使能

        前面提到本质是挂载在APB2总线,HAL库则不再让用户考虑这个。

    __HAL_RCC_GPIOB_CLK_ENABLE();           	//开启GPIOB时钟__HAL_RCC_GPIOE_CLK_ENABLE();           	//开启GPIOE时钟

3、配置输出模式、速度

        可以看到不再封装在结构体了,而是直接配置为define。

#define  GPIO_MODE_INPUT                        0x00000000u   /*!< Input Floating Mode                   */
#define  GPIO_MODE_OUTPUT_PP                    0x00000001u   /*!< Output Push Pull Mode                 */
#define  GPIO_MODE_OUTPUT_OD                    0x00000011u   /*!< Output Open Drain Mode                */
#define  GPIO_MODE_AF_PP                        0x00000002u   /*!< Alternate Function Push Pull Mode     */
#define  GPIO_MODE_AF_OD                        0x00000012u   /*!< Alternate Function Open Drain Mode    */
#define  GPIO_MODE_AF_INPUT                     GPIO_MODE_INPUT          /*!< Alternate Function Input Mode         */
#define  GPIO_NOPULL        0x00000000u   /*!< No Pull-up or Pull-down activation  */
#define  GPIO_PULLUP        0x00000001u   /*!< Pull-up activation                  */
#define  GPIO_PULLDOWN      0x00000002u   /*!< Pull-down activation                */
#define  GPIO_SPEED_FREQ_LOW              (GPIO_CRL_MODE0_1) /*!< Low speed */
#define  GPIO_SPEED_FREQ_MEDIUM           (GPIO_CRL_MODE0_0) /*!< Medium speed */
#define  GPIO_SPEED_FREQ_HIGH             (GPIO_CRL_MODE0)   /*!< High speed */

        可以看到在库函数已进行了相应的封装,具有了各类的配置。

4、初始化

        可以看到在GPIO_Init(GPIOB, &GPIO_InitStructure)前面是对PB进行了配置,后面配置PE5的时候,结构体本质上只有IO、速度、模式的区别,在均相同的时候,直接初始化即可,修改好GPIOB、GPIOE即可。

    GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_GPIOB_CLK_ENABLE();           	//开启GPIOB时钟__HAL_RCC_GPIOE_CLK_ENABLE();           	//开启GPIOE时钟GPIO_Initure.Pin=GPIO_PIN_5; 				//PB5GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  	//推挽输出GPIO_Initure.Pull=GPIO_PULLUP;          	//上拉GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;    //高速HAL_GPIO_Init(GPIOB,&GPIO_Initure);GPIO_Initure.Pin=GPIO_PIN_5; 				//PE5HAL_GPIO_Init(GPIOE,&GPIO_Initure);

5、设定高低电平

        前文提到,本质上要设定BSRR寄存器和BRR寄存器,这个部分HAL库函数也进行了相关的封装。

void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{/* Check the parameters */assert_param(IS_GPIO_PIN(GPIO_Pin));assert_param(IS_GPIO_PIN_ACTION(PinState));if (PinState != GPIO_PIN_RESET){GPIOx->BSRR = GPIO_Pin;}else{GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;}
}

        不同于HAL库,这次直接使用一个函数进行了封装,且只使用BSRR寄存器,前文提到BSRR可以直接设定0和1。

        除此之外还封装了一个Toggle,即如果目前GPIO为高电平,则切换为低电平;如果目前GPIO为低电平,则切换为高电平,这个也是很好用的。

void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{/* Check the parameters */assert_param(IS_GPIO_PIN(GPIO_Pin));if ((GPIOx->ODR & GPIO_Pin) != 0x00u){GPIOx->BRR = (uint32_t)GPIO_Pin;}else{GPIOx->BSRR = (uint32_t)GPIO_Pin;}
}

        可以看到,之前提到过ODR寄存器不仅可以输出而且可以输入,相当于切换之前读取一下当前的状态。

六、HAL库API

1、初始化封装

void LED_Init(void)
{GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_GPIOB_CLK_ENABLE();           	//开启GPIOB时钟__HAL_RCC_GPIOE_CLK_ENABLE();           	//开启GPIOE时钟GPIO_Initure.Pin=GPIO_PIN_5; 				//PB5GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;  	//推挽输出GPIO_Initure.Pull=GPIO_PULLUP;          	//上拉GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;    //高速HAL_GPIO_Init(GPIOB,&GPIO_Initure);GPIO_Initure.Pin=GPIO_PIN_5; 				//PE5HAL_GPIO_Init(GPIOE,&GPIO_Initure);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);	//PB5置1,默认初始化后灯灭HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);	//PE5置1,默认初始化后灯灭
}

        可以看到封装为LED_Init,用户侧基本上直接调用即可。

LED_Init();		  	//初始化与LED连接的硬件接口

2、输出高低电平封装

        除了初始化一次性配置外,对于GPIO输出高低电平肯定是要进行重复的操作的。直接看GPIO_SetBits、GPIO_ResetBits本质上还是官方提供的函数名,不适合用户侧去直观使用,可以进行额外封装。封装后几乎隔离了PB5的概念。

void LED0_HIGH()
{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
}
void LED1_HIGH()
{HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_SET);
}
void LED0_LOW()
{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
}
void LED1_LOW()
{HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,GPIO_PIN_RESET);
}

        后续如果要添加额外内容,即可在LED_HIGH、LED_LOW内进行编写即可。

七、用户侧

1、库函数

int main(void)
{	delay_init();	    //延时函数初始化	  LED_Init();		  	//初始化与LED连接的硬件接口while(1){LED0_HIGH();LED1_LOW();delay_ms(300);	 //延时300msLED0_LOW();LED1_HIGH();delay_ms(300);	//延时300ms}
}

        delay_init()和delay_ms()先不进行介绍,可以看到经过封装后,用户侧非常好进行操作修改。

2、HAL库

int main(void)
{HAL_Init();                    	 	//初始化HAL库    Stm32_Clock_Init(RCC_PLL_MUL9);   	//设置时钟,72Mdelay_init(72);               		//初始化延时函数LED_Init();							//初始化LED	while(1){LED0_HIGH(); 	//LED0对应引脚PB5拉低,亮,等同于LED0(0)LED1_HIGH();   	//LED1对应引脚PE5拉高,灭,等同于LED1(1)delay_ms(500);											//延时500msLED0_LOW();   	//LED0对应引脚PB5拉高,灭,等同于LED0(1)LED1_LOW(); 	//LED1对应引脚PE5拉低,亮,等同于LED1(0)delay_ms(500);                                      	//延时500ms }
}

        HAL_Init、Stm32_Clock_Init、delay_init以后进行介绍。

 3、用户

        对于用户而言,不管使用标准库还是HAL库,都是LED_Init()初始化LED,LED_HIGH、LED_LOW设定LED的高低电平状态,非常非常方便。这就是API封装的魅力所在。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词