1.芯片:STM32L476
1.开发板:Nuleo-L476RG
官网查看详细信息以及下载各种用户手册、说明书等等......
https://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-nucleo-boards/nucleo-l476rg.html#resource
3、GPIO示例参考资料
https://www.yiboard.com/thread-430-1-1.html
https://www.yiboard.com/thread-433-1-1.html
0.到官网找相应板子的驱动程序,下载安装ST-Link V2-1
1.下载STM32CubeMX(STM32芯片图形化配置工具,允许用户使用图形化向导生成C初始化代码,可以大大减轻开发工作、时间和费用),创建工程,选择芯片型号等
2.Keil5 点击工具栏的Pack Installer图标,安装STM32L4xx_DFP设备支持包,导入工程 ,通电,灯亮。
1.STM32CubeMX下载的示例工程,已将除用户代码的功能全部写好,我们只需要在main.c中添加我们想让板子跑的程序就OK。这里我们要点亮一个LED2灯。
关于HAL库的介绍:https://blog.csdn.net/m0_37621078/article/details/100084448
查看开发板用户手册:有3个LED灯,LD1常亮,LD2是user LED,LD3亮红色说明开发板有电源5V。
2.查看开发板的原理图:
(1)user按键,B1,与PC13相连
(2)LD2 ,也就是LED2灯,与PA5相连
1.使用GPIO的第一步是使能时钟:
该功能通过RCC(Reset and clock control)寄存器控制。所有的GPIO连接到AHB2总线。HAL库提供了专门的函数来启用GPIOA的时钟。
__HAL_RCC_GPIOA_CLK_ENABLE
该函数定义可在文件stm32l4xx_hal_rcc.h找到,其实现函数如下:
通过实现函数可知,主要方式是通过RCC_AHB2ENR寄存器的第0位(GPIOA EN)置位来实现。
2.定义一个GPIO_InitTypeDef结构体来设置GPIO的参数
GPIO_InitTypeDef GPIO_InitStruct;
结构体声明在:stm3214xx_hal_gpio.h
该结构体有5个参数:
1. Pin 选择引脚编号
2. Mode 设置GPIO的工作模式
3. Pull 设置引脚的上拉/下拉
4. Speed 设置GPIO输出的最大频率
5. Alternate 设置选择引脚的复用功能
其中每项都有自己的选项
■ Pin:指定需要配置的GPIO管脚,该选项可以是以下的任何值:
■ GPIO_PIN_0: 选择引脚0;
■ GPIO_PIN_1: 选择引脚1;
■ GPIO_PIN_2: 选择引脚2;
■ GPIO_PIN_3: 选择引脚3;
■ GPIO_PIN_4: 选择引脚4;
■ GPIO_PIN_5: 选择引脚5;
■ GPIO_PIN_6: 选择引脚6;
■ GPIO_PIN_7: 选择引脚7;
■ GPIO_PIN_8: 选择引脚8;
■ GPIO_PIN_9: 选择引脚9;
■ GPIO_PIN_10: 选择引脚10;
■ GPIO_PIN_11: 选择引脚11;
■ GPIO_PIN_12: 选择引脚12;
■ GPIO_PIN_13: 选择引脚13;
■ GPIO_PIN_14: 选择引脚14;
■ GPIO_PIN_15: 选择引脚15;
■ GPIO_PIN_All: 选择所有的引脚;
■ GPIO_PIN_MASK:引脚掩码;
■ Mode:指定选择引脚的工作模式
■ GPIO_MODE_INPUT:悬浮输入模式
■ GPIO_MODE_OUTPUT_PP:推挽输出模式
■ GPIO_MODE_OUTPUT_OD:漏极开路输出模式
■ GPIO_MODE_AF_PP:复用功能推挽模式
■ GPIO_MODE_AF_OD:复用功能漏极开路模式
■ GPIO_MODE_ANALOG:模拟模式
■ GPIO_MODE_ANALOG_ADC_CONTROL:模拟模式,用于ADC转换
■ GPIO_MODE_IT_RISING:上升沿触发检测的外部中断模式
■ GPIO_MODE_IT_FALLING:下降沿触发检测的外部中断模式
■ GPIO_MODE_IT_RISING_FALLING:上升/下降沿触发检测的外部中断模式
■ GPIO_MODE_EVT_RISING:上升沿触发检测的外部事件模式
■ GPIO_MODE_EVT_FALLING:下降沿触发检测的外部事件模式
■ GPIO_MODE_EVT_RISING_FALLING:上升/下降沿触发检测的外部事件模式
■ Pull:指定引脚的上拉/下拉
■ GPIO_NOPULL:无上拉/下拉电阻
■ GPIO_PULLUP:带有上拉电阻
■ GPIO_PULLDOWN:带有下拉电阻
■ Speed:指定引脚的输出频率:
■ GPIO_SPEED_FREQ_LOW:输出频率最大为5MHz
■ GPIO_SPEED_FREQ_MEDIUM:输出频率范围5MHz-25MHz
■ GPIO_SPEED_FREQ_HIGH:输出频率范围25MHz-50MHz
■ GPIO_SPEED_FREQ_VERY_HIGH::输出频率范围50MHz-80MHz
3.HAL库提供了GPIO的初始化函数HAL_GPIO_Init() ,函数在stm32l4xx_hal_gpio.h
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
该头文件的对应的.c文件中,有函数实现....en 看不懂
/**
* @brief Initialize the GPIOx peripheral according to the specified parameters in the GPIO_Init.
* @param GPIOx: where x can be (A..H) to select the GPIO peripheral for STM32L4 family
* @param GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains
* the configuration information for the specified GPIO peripheral.
* @retval None
*/
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
uint32_t position = 0x00u;
uint32_t iocurrent;
uint32_t temp;
/* Check the parameters */
assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
/* Configure the port pins */
while (((GPIO_Init->Pin) >> position) != 0x00u)
{
/* Get current io position */
iocurrent = (GPIO_Init->Pin) & (1uL << position);
if (iocurrent != 0x00u)
{
/*--------------------- GPIO Mode Configuration ------------------------*/
/* In case of Alternate function mode selection */
if((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
{
/* Check the Alternate function parameters */
assert_param(IS_GPIO_AF_INSTANCE(GPIOx));
assert_param(IS_GPIO_AF(GPIO_Init->Alternate));
/* Configure Alternate function mapped with the current IO */
temp = GPIOx->AFR[position >> 3u];
temp &= ~(0xFu << ((position & 0x07u) * 4u));
temp |= ((GPIO_Init->Alternate) << ((position & 0x07u) * 4u));
GPIOx->AFR[position >> 3u] = temp;
}
/* Configure IO Direction mode (Input, Output, Alternate or Analog) */
temp = GPIOx->MODER;
temp &= ~(GPIO_MODER_MODE0 << (position * 2u));
temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2u));
GPIOx->MODER = temp;
/* In case of Output or Alternate function mode selection */
if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) ||
(GPIO_Init->Mode == GPIO_MODE_OUTPUT_OD) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
{
/* Check the Speed parameter */
assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
/* Configure the IO Speed */
temp = GPIOx->OSPEEDR;
temp &= ~(GPIO_OSPEEDR_OSPEED0 << (position * 2u));
temp |= (GPIO_Init->Speed << (position * 2u));
GPIOx->OSPEEDR = temp;
/* Configure the IO Output Type */
temp = GPIOx->OTYPER;
temp &= ~(GPIO_OTYPER_OT0 << position) ;
temp |= (((GPIO_Init->Mode & GPIO_OUTPUT_TYPE) >> 4u) << position);
GPIOx->OTYPER = temp;
}
#if defined(STM32L471xx) || defined(STM32L475xx) || defined(STM32L476xx) || defined(STM32L485xx) || defined(STM32L486xx)
/* In case of Analog mode, check if ADC control mode is selected */
if((GPIO_Init->Mode & GPIO_MODE_ANALOG) == GPIO_MODE_ANALOG)
{
/* Configure the IO Output Type */
temp = GPIOx->ASCR;
temp &= ~(GPIO_ASCR_ASC0 << position) ;
temp |= (((GPIO_Init->Mode & ANALOG_MODE) >> 3) << position);
GPIOx->ASCR = temp;
}
#endif /* STM32L471xx || STM32L475xx || STM32L476xx || STM32L485xx || STM32L486xx */
/* Activate the Pull-up or Pull down resistor for the current IO */
temp = GPIOx->PUPDR;
temp &= ~(GPIO_PUPDR_PUPD0 << (position * 2u));
temp |= ((GPIO_Init->Pull) << (position * 2u));
GPIOx->PUPDR = temp;
/*--------------------- EXTI Mode Configuration ------------------------*/
/* Configure the External Interrupt or event for the current IO */
if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
{
/* Enable SYSCFG Clock */
__HAL_RCC_SYSCFG_CLK_ENABLE();
temp = SYSCFG->EXTICR[position >> 2u];
temp &= ~(0x0FuL << (4u * (position & 0x03u)));
temp |= (GPIO_GET_INDEX(GPIOx) << (4u * (position & 0x03u)));
SYSCFG->EXTICR[position >> 2u] = temp;
/* Clear EXTI line configuration */
temp = EXTI->IMR1;
temp &= ~(iocurrent);
if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
{
temp |= iocurrent;
}
EXTI->IMR1 = temp;
temp = EXTI->EMR1;
temp &= ~(iocurrent);
if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
{
temp |= iocurrent;
}
EXTI->EMR1 = temp;
/* Clear Rising Falling edge configuration */
temp = EXTI->RTSR1;
temp &= ~(iocurrent);
if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
{
temp |= iocurrent;
}
EXTI->RTSR1 = temp;
temp = EXTI->FTSR1;
temp &= ~(iocurrent);
if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
{
temp |= iocurrent;
}
EXTI->FTSR1 = temp;
}
}
position++;
}
}
4.使用库函数,点亮LD2
int main(void)
{
/* USER CODE BEGIN 1 */
//定义一个GPIO结构体
GPIO_InitTypeDef GPIO_InitDef;
//启用GPIOA时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
//定义LD2的每一个参数 init配置
GPIO_InitDef.Pin = GPIO_PIN_5;
GPIO_InitDef.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitDef.Pull = GPIO_NOPULL;
GPIO_InitDef.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitDef);
//user按键的设置
/*
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitDef.Pin = GPIO_PIN_13;
GPIO_InitDef.Mode = GPIO_MODE_INPUT;
GPIO_InitDef.Pull = GPIO_PULLDOWN;
GPIO_InitDef.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
//Initialize pins
HAL_GPIO_Init(GPIOC, &GPIO_InitDef);
*/
while (1)
{
//点亮LD2
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
}
}
编译、无报错、load到开发板中,这样,开发板的LED2就点亮了。
回顾电路板的原理图:
我们要点亮LD2,所以要给PA5引脚接高电平。
如何给?HAL库中给出了很多生成的代码,代码的做法是:将GPIO端分组,分为ABCDEFG...等几个组,然后再用引脚1234567...确定。所以写的代码为:
GPIO_InitDef.Pin = GPIO_PIN_5;
HAL_GPIO_Init(GPIOA, &GPIO_InitDef);
先给结构体确定好引脚5,再规定这是A组的,就设置完一个结构体,也就是设置完一个LD2的参数。
1.这次点亮LED的工作模式为推挽输出:
推挽输出:意思就是输出具有驱动能力(比如:引脚上接一个LED,可以直接点亮,若是开漏输出,就不能点亮LED)。
推挽输出这个功能是比较常用的功能,我们一般输出控制某个信号,基本上都是配置为GPIO_Mode_Out_PP 推挽输出。
推挽输出电流大小也是比较关键的一个参数,根据芯片不同,其大小也不同,具体可以查看数据手册:
参考链接:https://blog.csdn.net/ybhuangfugui/article/details/52953533
1、上拉输入:上拉就是把电位拉高,比如拉到Vcc。上拉就是将不确定的信号通过一个电阻嵌位在高电平!电阻同时起限流作用!强弱只是上拉电阻的阻值不同,没有什么严格区分。
2、下拉输入:就是把电压拉低,拉到GND。与上拉原理相似。
3、浮空输入:浮空(floating)就是逻辑器件的输入引脚即不接高电平,也不接低电平。由于逻辑器件的内部结构,当它输入引脚悬空时,相当于该引脚接了高电平。一般实际运用时,引脚不建议悬空,易受干扰。 通俗讲就是让管脚什么都不接,浮空着。
4、模拟输入:模拟输入是指传统方式的输入。数字输入是输入PCM数字信号,即0,1的二进制数字信号,通过数模转换,转换成模拟信号,经前级放大进入功率放大器,功率放大器还是模拟的。
5、推挽输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源低定。
6、开漏输出:输出端相当于三极管的集电极。要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。
7、复用输出:可以理解为GPIO口被用作第二功能时的配置情况(即并非作为通用IO口使用)。端口必须配置成复用功能输出模式(推挽或开漏)。
好好理解一下,其实就能得出,这些GPIO模式能在下面几种情况应用,参考网上的资料后,总结出下面几点:
在STM32中选用IO模式,下面是参考网上的资料后总结出的结果。
(1)GPIO_Mode_AIN 模拟输入—应用ADC模拟输入,或者低功耗下省电
(2)GPIO_Mode_IN_FLOATING 浮空输入—可以做KEY识别
(3)GPIO_Mode_IPD 下拉输入— IO内部下拉电阻输入
(4)GPIO_Mode_IPU 上拉输入—IO内部上拉电阻输入
(5)GPIO_Mode_Out_OD 开漏输出—IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能。
(6)GPIO_Mode_Out_PP 推挽输出—IO输出0-接GND,IO输出1 -接VCC,读输入值是未知的。
(7)GPIO_Mode_AF_OD 复用开漏输出—片内外设功能(TX1,MOSI,MISO.SCK.SS)。
(8)GPIO_Mode_AF_PP 复用推挽输出—片内外设功能(I2C的SCL,SDA)。
————————————————
参考链接:https://blog.csdn.net/santa9527/article/details/78842832