该项目基于型号STM32F103C8T6,项目的具体内容参考GitHub仓库,根据各个模块来学习对应的功能的实现。
开发GPIO驱动
在开发GPIO模块前,需要对GPIO_TypeDef
中的参数有一定的认识。
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
1. CRL (Configuration Register Low)
作用:配置 GPIO 端口的低 8 个引脚(Pin 0 ~ Pin 7)的模式和速度。
位域:
- 每 4 位控制一个引脚:
MODEy[1:0]
:配置引脚的模式(输入、输出、复用功能、模拟模式)。CNFy[1:0]
:配置引脚的输出类型(推挽、开漏、复用功能、模拟模式)。
- 每 4 位控制一个引脚:
示例:
设置 Pin 0 为推挽输出模式:
c
Copy
GPIOx->CRL &= ~(0xF << 0); // 清除 Pin 0 的配置 GPIOx->CRL |= (0x3 << 0); // 设置 Pin 0 为推挽输出模式
2. CRH (Configuration Register High)
作用:配置 GPIO 端口的高 8 个引脚(Pin 8 ~ Pin 15)的模式和速度。
位域:
- 每 4 位控制一个引脚:
MODEy[1:0]
:配置引脚的模式(输入、输出、复用功能、模拟模式)。CNFy[1:0]
:配置引脚的输出类型(推挽、开漏、复用功能、模拟模式)。
- 每 4 位控制一个引脚:
示例:
设置 Pin 8 为开漏输出模式:
c
Copy
GPIOx->CRH &= ~(0xF << 0); // 清除 Pin 8 的配置 GPIOx->CRH |= (0x6 << 0); // 设置 Pin 8 为开漏输出模式
3. IDR (Input Data Register)
作用:读取 GPIO 端口的输入数据。
位域:
- 低 16 位(Bit 0 ~ Bit 15)对应 GPIO 的 16 个引脚。
- 每个位的值为
0
或1
,表示对应引脚的输入状态。
示例:
读取 Pin 5 的输入状态:
c
Copy
uint8_t pinState = (GPIOx->IDR & GPIO_PIN_5) ? 1 : 0;
4. ODR (Output Data Register)
作用:设置 GPIO 端口的输出数据。
位域:
- 低 16 位(Bit 0 ~ Bit 15)对应 GPIO 的 16 个引脚。
- 每个位的值为
0
或1
,表示对应引脚的输出状态。
示例:
设置 Pin 6 输出高电平:
c
Copy
GPIOx->ODR |= GPIO_PIN_6;
设置 Pin 6 输出低电平:
c
Copy
GPIOx->ODR &= ~GPIO_PIN_6;
5. BSRR (Bit Set/Reset Register)
作用:原子地设置或复位 GPIO 引脚。
位域:
- 低 16 位(Bit 0 ~ Bit 15):设置对应引脚为高电平。
- 高 16 位(Bit 16 ~ Bit 31):复位对应引脚为低电平。
示例:
设置 Pin 7 为高电平:
c
Copy
GPIOx->BSRR = GPIO_PIN_7;
设置 Pin 7 为低电平:
c
Copy
GPIOx->BSRR = GPIO_PIN_7 << 16;
6. BRR (Bit Reset Register)
作用:复位 GPIO 引脚(设置为低电平)。
位域:
- 低 16 位(Bit 0 ~ Bit 15):复位对应引脚为低电平。
示例:
复位 Pin 9 为低电平:
c
Copy
GPIOx->BRR = GPIO_PIN_9;
7. LCKR (Configuration Lock Register)
作用:锁定 GPIO 端口的配置寄存器(CRL 和 CRH),防止意外修改。
位域:
- 低 16 位(Bit 0 ~ Bit 15):锁定对应引脚的配置。
- Bit 16:锁定键(Lock Key),用于确认锁定操作。
示例:
锁定 Pin 10 的配置:
c
Copy
GPIOx->LCKR = GPIO_PIN_10 | (1 << 16); // 锁定 Pin 10 GPIOx->LCKR = GPIO_PIN_10; // 确认锁定 GPIOx->LCKR = GPIO_PIN_10 | (1 << 16); // 再次锁定 uint32_t lockStatus = GPIOx->LCKR; // 读取锁定状态
引脚初始化
void GPIO_Init_Pin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIOMode_TypeDef GPIO_Mode, GPIOSpeed_TypeDef GPIO_Speed)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 使能GPIO时钟 */
if(GPIOx == GPIOA)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
else if(GPIOx == GPIOB)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
else if(GPIOx == GPIOC)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
else if(GPIOx == GPIOD)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
else if(GPIOx == GPIOE)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
/* 配置GPIO */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed;
GPIO_Init(GPIOx, &GPIO_InitStruct);
}