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的配置。
AFRL和AFRH:复用功能寄存器,用于配置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 代码解释
-
使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。
-
配置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为无上拉/下拉。 -
设置和复位PA0的输出状态:
-
GPIOA->ODR |= GPIO_ODR_0;
:设置PA0为高电平。 -
GPIOA->ODR &= ~GPIO_ODR_0;
:设置PA0为低电平。 -
延时:使用简单的延时循环来实现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 代码解释
-
使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。
-
配置PA0为上拉输入模式:
-
GPIOA->MODER &= ~GPIO_MODER_MODE0;
:设置PA0为输入模式。 -
GPIOA->PUPDR |= GPIO_PUPDR_PUPD0_0;
:设置PA0为上拉。 -
使能SYSCFG时钟:通过设置RCC的APB2ENR寄存器位,使能SYSCFG的时钟。
-
配置PA0为EXTI0的中断源:
SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA;
:设置PA0为EXTI0的中断源。-
使能EXTI0中断:
-
EXTI->IMR |= EXTI_IMR_MR0;
:使能EXTI0中断。 -
EXTI->RTSR |= EXTI_RTSR_TR0;
:配置EXTI0为上升沿触发。 -
使能EXTI0中断向量:通过设置NVIC寄存器位,使能EXTI0的中断向量。
-
中断处理函数:
-
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 代码解释
-
使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。
-
配置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)。 -
使能USART1时钟:通过设置RCC的APB2ENR寄存器位,使能USART1的时钟。
-
配置USART1:
-
USART1->BRR = 0x04B0;
:设置波特率为9600。 -
USART1->CR1 |= USART_CR1_UE;
:使能USART1。 -
USART1->CR1 |= USART_CR1_TE;
:使能发送器。 -
USART1->CR1 |= USART_CR1_RE;
:使能接收器。 -
发送字符:
-
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 代码解释
-
使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。
-
配置PA0为模拟模式:
-
GPIOA->MODER |= GPIO_MODER_MODE0_1;
:设置PA0为模拟模式。 -
GPIOA->MODER &= ~GPIO_MODER_MODE0_0;
:设置PA0为模拟模式。 -
使能ADC时钟:通过设置RCC的APB2ENR寄存器位,使能ADC1的时钟。
-
配置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;
:启动软件触发的转换。 -
读取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 代码解释
-
使能GPIOA时钟:通过设置RCC的AHBENR寄存器位,使能GPIOA的时钟。
-
配置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为推挽输出。 -
使能TIM2时钟:通过设置RCC的APB1ENR寄存器位,使能TIM2的时钟。
-
配置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功能。
作者:kkchenkx