您现在的位置是:首页 >学无止境 >STMicroelectronics 系列:STM32L1 系列_(7).STM32L1系列GPIO应用网站首页学无止境

STMicroelectronics 系列:STM32L1 系列_(7).STM32L1系列GPIO应用

kkchenkx 2025-07-28 00:01:04
简介STMicroelectronics 系列:STM32L1 系列_(7).STM32L1系列GPIO应用

STM32L1系列GPIO应用

1. GPIO概述

1.1 GPIO的基本概念

通用输入输出(General Purpose Input Output,简称GPIO)是微控制器中的一种基本功能,用于实现与外部设备的交互。STM32L1系列微控制器的GPIO功能非常强大,支持多种工作模式,包括输入、输出、复用功能等。GPIO的工作模式和配置可以通过寄存器进行灵活设置,以满足不同应用场景的需求。
在这里插入图片描述

1.2 GPIO的特点

  • 低功耗:STM32L1系列微控制器的设计重点之一是低功耗,GPIO也不例外,支持多种低功耗模式。

  • 多种工作模式:输入模式、输出模式、复用功能模式、模拟模式等。

  • 灵活的配置:可以通过寄存器配置GPIO的模式、速度、上拉/下拉状态等。

  • 中断功能:GPIO可以配置为外部中断源,响应外部事件。

  • 多路复用:GPIO可以复用为多种外设功能,如I2C、UART、SPI等。

2. GPIO寄存器配置

2.1 GPIO寄存器结构

STM32L1系列微控制器的GPIO寄存器结构如下:

  • MODER:模式寄存器,用于配置GPIO的模式。

  • OTYPER:输出类型寄存器,用于配置GPIO的输出类型(推挽或开漏)。

  • OSPEEDR:输出速度寄存器,用于配置GPIO的输出速度。

  • PUPDR:上拉/下拉寄存器,用于配置GPIO的上拉/下拉状态。

  • IDR:输入数据寄存器,用于读取GPIO的输入状态。

  • ODR:输出数据寄存器,用于设置GPIO的输出状态。

  • BSRR:复位寄存器,用于设置或复位GPIO的输出状态。

  • LCKR:锁定寄存器,用于锁定GPIO的配置。

  • AFRLAFRH:复用功能寄存器,用于配置GPIO的复用功能。

2.2 寄存器配置示例

以下是一个配置GPIO为输出模式的示例代码:


#include "stm32l1xx.h"



void GPIO_Config(void) {

    // 使能GPIOA时钟

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;



    // 配置PA0为推挽输出模式

    GPIOA->MODER |= GPIO_MODER_MODE0_0; // 01: 通用推挽输出

    GPIOA->OTYPER &= ~GPIO_OTYPER_OT0; // 0: 推挽输出

    GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED0; // 00: 低速输出

    GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD0; // 00: 无上拉/下拉

}



int main(void) {

    // 初始化GPIO

    GPIO_Config();



    while (1) {

        // 设置PA0输出高电平

        GPIOA->ODR |= GPIO_ODR_0;



        // 延时

        for (volatile uint32_t i = 0; i < 1000000; i++);



        // 设置PA0输出低电平

        GPIOA->ODR &= ~GPIO_ODR_0;



        // 延时

        for (volatile uint32_t i = 0; i < 1000000; i++);

    }

}

2.3 代码解释

  1. 使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。

  2. 配置PA0为推挽输出模式

    • GPIOA->MODER |= GPIO_MODER_MODE0_0;:设置PA0为通用推挽输出模式。

    • GPIOA->OTYPER &= ~GPIO_OTYPER_OT0;:设置PA0为推挽输出类型。

    • GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED0;:设置PA0为低速输出。

    • GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD0;:设置PA0为无上拉/下拉。

  3. 设置和复位PA0的输出状态

    • GPIOA->ODR |= GPIO_ODR_0;:设置PA0为高电平。

    • GPIOA->ODR &= ~GPIO_ODR_0;:设置PA0为低电平。

  4. 延时:使用简单的延时循环来实现LED的闪烁效果。

3. GPIO输入模式配置

3.1 输入模式概述

GPIO可以配置为输入模式,用于读取外部信号。STM32L1系列支持多种输入模式,包括浮空输入、上拉输入和下拉输入。

3.2 配置浮空输入模式

以下是一个配置GPIO为浮空输入模式的示例代码:


#include "stm32l1xx.h"



void GPIO_Config(void) {

    // 使能GPIOA时钟

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;



    // 配置PA0为浮空输入模式

    GPIOA->MODER &= ~GPIO_MODER_MODE0; // 00: 输入模式

    GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD0; // 00: 无上拉/下拉

}



int main(void) {

    // 初始化GPIO

    GPIO_Config();



    while (1) {

        // 读取PA0的输入状态

        uint32_t state = GPIOA->IDR & GPIO_IDR_ID0;



        if (state) {

            // PA0为高电平

            GPIOA->ODR |= GPIO_ODR_0; // 设置PA1为高电平

        } else {

            // PA0为低电平

            GPIOA->ODR &= ~GPIO_ODR_0; // 设置PA1为低电平

        }



        // 延时

        for (volatile uint32_t i = 0; i < 1000000; i++);

    }

}

3.3 配置上拉输入模式

以下是一个配置GPIO为上拉输入模式的示例代码:


#include "stm32l1xx.h"



void GPIO_Config(void) {

    // 使能GPIOA时钟

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;



    // 配置PA0为上拉输入模式

    GPIOA->MODER &= ~GPIO_MODER_MODE0; // 00: 输入模式

    GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_0; // 01: 上拉

}



int main(void) {

    // 初始化GPIO

    GPIO_Config();



    while (1) {

        // 读取PA0的输入状态

        uint32_t state = GPIOA->IDR & GPIO_IDR_ID0;



        if (state) {

            // PA0为高电平

            GPIOA->ODR |= GPIO_ODR_1; // 设置PA1为高电平

        } else {

            // PA0为低电平

            GPIOA->ODR &= ~GPIO_ODR_1; // 设置PA1为低电平

        }



        // 延时

        for (volatile uint32_t i = 0; i < 1000000; i++);

    }

}

4. GPIO外部中断配置

4.1 外部中断概述

GPIO可以配置为外部中断源,用于检测外部事件并触发中断。STM32L1系列支持多种中断触发方式,包括上升沿、下降沿和双沿触发。

4.2 配置PA0为外部中断源

以下是一个配置PA0为外部中断源并实现中断处理的示例代码:


#include "stm32l1xx.h"

#include "stm32l1xx_exti.h"



void GPIO_Config(void) {

    // 使能GPIOA时钟

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;



    // 配置PA0为上拉输入模式

    GPIOA->MODER &= ~GPIO_MODER_MODE0; // 00: 输入模式

    GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_0; // 01: 上拉

}



void EXTI_Config(void) {

    // 使能SYSCFG时钟

    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;



    // 配置PA0为EXTI0的中断源

    SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA;



    // 使能EXTI0中断

    EXTI->IMR |= EXTI_IMR_MR0;



    // 配置EXTI0为上升沿触发

    EXTI->RTSR |= EXTI_RTSR_TR0;



    // 使能EXTI0中断向量

    NVIC_EnableIRQ(EXTI0_IRQn);

}



void EXTI0_IRQHandler(void) {

    // 清除EXTI0中断标志

    EXTI->PR |= EXTI_PR_PR0;



    // 切换PA1的状态

    GPIOA->ODR ^= GPIO_ODR_1;

}



int main(void) {

    // 初始化GPIO

    GPIO_Config();



    // 初始化EXTI

    EXTI_Config();



    while (1) {

        // 主循环

    }

}

4.3 代码解释

  1. 使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。

  2. 配置PA0为上拉输入模式

    • GPIOA->MODER &= ~GPIO_MODER_MODE0;:设置PA0为输入模式。

    • GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_0;:设置PA0为上拉。

  3. 使能SYSCFG时钟:通过设置RCC的APB2ENR寄存器位,使能SYSCFG的时钟。

  4. 配置PA0为EXTI0的中断源

    • SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA;:设置PA0为EXTI0的中断源。
  5. 使能EXTI0中断

    • EXTI->IMR |= EXTI_IMR_MR0;:使能EXTI0中断。

    • EXTI->RTSR |= EXTI_RTSR_TR0;:配置EXTI0为上升沿触发。

  6. 使能EXTI0中断向量:通过设置NVIC寄存器位,使能EXTI0的中断向量。

  7. 中断处理函数

    • EXTI0_IRQHandler:处理PA0的外部中断。

    • EXTI->PR |= EXTI_PR_PR0;:清除EXTI0的中断标志。

    • GPIOA->ODR ^= GPIO_ODR_1;:切换PA1的状态。

5. GPIO复用功能配置

5.1 复用功能概述

GPIO的复用功能允许将GPIO配置为外设功能,如I2C、UART、SPI等。STM32L1系列提供了多个复用功能寄存器(AFRL和AFRH)来配置GPIO的复用功能。

5.2 配置PA9为USART1_TX

以下是一个配置PA9为USART1_TX的示例代码:


#include "stm32l1xx.h"

#include "stm32l1xx_usart.h"



void GPIO_Config(void) {

    // 使能GPIOA时钟

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;



    // 配置PA9为USART1_TX

    GPIOA->MODER |= GPIO_MODER_MODE9_1; // 10: 复用功能

    GPIOA->MODER &= ~GPIO_MODER_MODE9_0; // 10: 复用功能

    GPIOA->OTYPER &= ~GPIO_OTYPER_OT9; // 0: 推挽输出

    GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED9_1; // 10: 中速

    GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED9_0; // 10: 中速

    GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD9; // 00: 无上拉/下拉

    GPIOA->AFR[1] |= GPIO_AFRH_AFSEL9_2; // 0100: 复用功能4 (USART1_TX)

    GPIOA->AFR[1] &= ~(GPIO_AFRH_AFSEL9_3 | GPIO_AFRH_AFSEL9_1 | GPIO_AFRH_AFSEL9_0); // 0100: 复用功能4 (USART1_TX)

}



void USART_Config(void) {

    // 使能USART1时钟

    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;



    // 配置USART1

    USART1->BRR = 0x04B0; // 波特率设置为9600

    USART1->CR1 |= USART_CR1_UE; // 使能USART1

    USART1->CR1 |= USART_CR1_TE; // 使能发送器

    USART1->CR1 |= USART_CR1_RE; // 使能接收器

}



void USART_SendChar(uint8_t data) {

    // 等待发送缓冲区为空

    while (!(USART1->SR & USART_SR_TXE));



    // 发送数据

    USART1->DR = data;

}



int main(void) {

    // 初始化GPIO

    GPIO_Config();



    // 初始化USART

    USART_Config();



    while (1) {

        // 发送字符

        USART_SendChar('A');



        // 延时

        for (volatile uint32_t i = 0; i < 1000000; i++);

    }

}

5.3 代码解释

  1. 使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。

  2. 配置PA9为USART1_TX

    • GPIOA->MODER |= GPIO_MODER_MODE9_1;:设置PA9为复用功能。

    • GPIOA->MODER &= ~GPIO_MODER_MODE9_0;:设置PA9为复用功能。

    • GPIOA->OTYPER &= ~GPIO_OTYPER_OT9;:设置PA9为推挽输出。

    • GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED9_1;:设置PA9为中速。

    • GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED9_0;:设置PA9为中速。

    • GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD9;:设置PA9为无上拉/下拉。

    • GPIOA->AFR[1] |= GPIO_AFRH_AFSEL9_2;:设置PA9为复用功能4 (USART1_TX)。

    • GPIOA->AFR[1] &= ~(GPIO_AFRH_AFSEL9_3 | GPIO_AFRH_AFSEL9_1 | GPIO_AFRH_AFSEL9_0);:设置PA9为复用功能4 (USART1_TX)。

  3. 使能USART1时钟:通过设置RCC的APB2ENR寄存器位,使能USART1的时钟。

  4. 配置USART1

    • USART1->BRR = 0x04B0;:设置波特率为9600。

    • USART1->CR1 |= USART_CR1_UE;:使能USART1。

    • USART1->CR1 |= USART_CR1_TE;:使能发送器。

    • USART1->CR1 |= USART_CR1_RE;:使能接收器。

  5. 发送字符

    • USART_SendChar:发送一个字符。

    • while (!(USART1->SR & USART_SR_TXE));:等待发送缓冲区为空。

    • USART1->DR = data;:发送数据。

6. GPIO模拟模式配置

6.1 模拟模式概述

GPIO可以配置为模拟模式,用于连接模拟信号输入设备,如ADC。在模拟模式下,GPIO的数字功能被禁用,允许模拟信号通过。这对于需要进行模拟信号采集的应用非常有用,例如温度传感器、光敏传感器等。

6.2 配置PA0为模拟模式

以下是一个配置PA0为模拟模式并读取ADC值的示例代码:


#include "stm32l1xx.h"

#include "stm32l1xx_adc.h"



void GPIO_Config(void) {

    // 使能GPIOA时钟

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;



    // 配置PA0为模拟模式

    GPIOA->MODER |= GPIO_MODER_MODE0_1; // 11: 模拟模式

    GPIOA->MODER &= ~GPIO_MODER_MODE0_0; // 11: 模拟模式

}



void ADC_Config(void) {

    // 使能ADC时钟

    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;



    // 配置ADC

    ADC1->CR2 |= ADC_CR2_ADON; // 使能ADC

    ADC1->CR2 |= ADC_CR2_CONT; // 连续转换模式

    ADC1->CR2 |= ADC_CR2_CAL; // 校准ADC



    // 等待校准完成

    while (ADC1->CR2 & ADC_CR2_CAL);



    ADC1->CR2 |= ADC_CR2_RSTCAL; // 重置校准标志

    while (ADC1->CR2 & ADC_CR2_RSTCAL);



    // 配置ADC通道

    ADC1->SQR3 |= ADC_SQR3_SQ1_0; // 选择通道0 (PA0)

    ADC1->SQR3 &= ~ADC_SQR3_SQ1_1; // 选择通道0 (PA0)

    ADC1->SQR3 &= ~ADC_SQR3_SQ1_2; // 选择通道0 (PA0)

    ADC1->SQR3 &= ~ADC_SQR3_SQ1_3; // 选择通道0 (PA0)

    ADC1->CR2 |= ADC_CR2_SWSTART; // 启动软件触发的转换

}



uint16_t ADC_Read(uint8_t channel) {

    // 选择要读取的通道

    ADC1->SQR3 = (channel << 0);



    // 启动转换

    ADC1->CR2 |= ADC_CR2_SWSTART;



    // 等待转换完成

    while (!(ADC1->SR & ADC_SR_EOC));



    // 读取转换结果

    return ADC1->DR;

}



int main(void) {

    // 初始化GPIO

    GPIO_Config();



    // 初始化ADC

    ADC_Config();



    while (1) {

        // 读取PA0的ADC值

        uint16_t adc_value = ADC_Read(0);



        // 处理ADC值

        // 例如,可以在调试串口上打印ADC值

        // 或者根据ADC值控制其他外设



        // 延时

        for (volatile uint32_t i = 0; i < 1000000; i++);

    }

}

6.3 代码解释

  1. 使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。

  2. 配置PA0为模拟模式

    • GPIOA->MODER |= GPIO_MODER_MODE0_1;:设置PA0为模拟模式。

    • GPIOA->MODER &= ~GPIO_MODER_MODE0_0;:设置PA0为模拟模式。

  3. 使能ADC时钟:通过设置RCC的APB2ENR寄存器位,使能ADC1的时钟。

  4. 配置ADC

    • ADC1->CR2 |= ADC_CR2_ADON;:使能ADC。

    • ADC1->CR2 |= ADC_CR2_CONT;:设置为连续转换模式。

    • ADC1->CR2 |= ADC_CR2_CAL;:校准ADC。

    • while (ADC1->CR2 & ADC_CR2_CAL);:等待校准完成。

    • ADC1->CR2 |= ADC_CR2_RSTCAL;:重置校准标志。

    • while (ADC1->CR2 & ADC_CR2_RSTCAL);:等待重置校准标志完成。

    • ADC1->SQR3 |= ADC_SQR3_SQ1_0;:选择通道0 (PA0)。

    • ADC1->CR2 |= ADC_CR2_SWSTART;:启动软件触发的转换。

  5. 读取ADC值

    • ADC_Read函数用于读取指定通道的ADC值。

    • ADC1->SQR3 = (channel << 0);:选择要读取的通道。

    • ADC1->CR2 |= ADC_CR2_SWSTART;:启动转换。

    • while (!(ADC1->SR & ADC_SR_EOC));:等待转换完成。

    • return ADC1->DR;:读取转换结果并返回。

7. GPIO高级应用

7.1 GPIO与定时器结合

GPIO与定时器结合可以实现更复杂的功能,例如PWM输出、捕获外部信号等。以下是一个配置GPIO为PWM输出的示例代码:


#include "stm32l1xx.h"

#include "stm32l1xx_tim.h"



void GPIO_Config(void) {

    // 使能GPIOA时钟

    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;



    // 配置PA0为复用功能2 (TIM2_CH1)

    GPIOA->MODER |= GPIO_MODER_MODE0_1; // 10: 复用功能

    GPIOA->MODER &= ~GPIO_MODER_MODE0_0; // 10: 复用功能

    GPIOA->AFR[0] |= GPIO_AFRH_AFSEL0_0; // 0010: 复用功能2

    GPIOA->AFR[0] &= ~(GPIO_AFRH_AFSEL0_1 | GPIO_AFRH_AFSEL0_2 | GPIO_AFRH_AFSEL0_3); // 0010: 复用功能2

    GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED0_1; // 10: 中速

    GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED0_0; // 10: 中速

    GPIOA->OTYPER &= ~GPIO_OTYPER_OT0; // 0: 推挽输出

}



void TIM_Config(void) {

    // 使能TIM2时钟

    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;



    // 配置TIM2为PWM模式

    TIM2->PSC = 48 - 1; // 预分频器,假设系统时钟为48MHz

    TIM2->ARR = 1000 - 1; // 自动重载值

    TIM2->CCR1 = 500; // 比较值

    TIM2->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; // 110: PWM模式1

    TIM2->CCER |= TIM_CCER_CC1E; // 使能通道1输出

    TIM2->CR1 |= TIM_CR1_ARPE; // 自动重载预装载使能

    TIM2->CR1 |= TIM_CR1_CEN; // 使能定时器

}



int main(void) {

    // 初始化GPIO

    GPIO_Config();



    // 初始化TIM2

    TIM_Config();



    while (1) {

        // 主循环

    }

}

7.2 代码解释

  1. 使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。

  2. 配置PA0为TIM2_CH1

    • GPIOA->MODER |= GPIO_MODER_MODE0_1;:设置PA0为复用功能。

    • GPIOA->MODER &= ~GPIO_MODER_MODE0_0;:设置PA0为复用功能。

    • GPIOA->AFR[0] |= GPIO_AFRH_AFSEL0_0;:设置PA0为复用功能2 (TIM2_CH1)。

    • GPIOA->AFR[0] &= ~(GPIO_AFRH_AFSEL0_1 | GPIO_AFRH_AFSEL0_2 | GPIO_AFRH_AFSEL0_3);:设置PA0为复用功能2 (TIM2_CH1)。

    • GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED0_1;:设置PA0为中速。

    • GPIOA->OSPEEDR &= ~GPIO_OSPEEDR_OSPEED0_0;:设置PA0为中速。

    • GPIOA->OTYPER &= ~GPIO_OTYPER_OT0;:设置PA0为推挽输出。

  3. 使能TIM2时钟:通过设置RCC的APB1ENR寄存器位,使能TIM2的时钟。

  4. 配置TIM2为PWM模式

    • TIM2->PSC = 48 - 1;:设置预分频器,假设系统时钟为48MHz。

    • TIM2->ARR = 1000 - 1;:设置自动重载值。

    • TIM2->CCR1 = 500;:设置比较值。

    • TIM2->CCMR1 |= TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;:设置PWM模式1。

    • TIM2->CCER |= TIM_CCER_CC1E;:使能通道1输出。

    • TIM2->CR1 |= TIM_CR1_ARPE;:自动重载预装载使能。

    • TIM2->CR1 |= TIM_CR1_CEN;:使能定时器。

8. 总结

STM32L1系列微控制器的GPIO功能非常强大,可以灵活配置多种工作模式,包括输入、输出、复用功能和模拟模式。通过寄存器配置,可以实现各种应用场景,如外部中断检测、PWM输出和ADC采集等。理解并掌握这些配置方法对于开发高效、低功耗的嵌入式系统非常关键。希望本文的内容能够帮助读者更好地理解和应用STM32L1系列的GPIO功能。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。