一、芯片以及開發板
1.芯片:STM32L476
1.開發板:Nuleo-L476RG
官網查看詳細信息以及下載各種用戶手冊、說明書等等......
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相連
四、點亮LD2
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的參數。
五、關於GPIO結構體中的工作模式 GPIO_InitTypeDef ->Mode
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