简介
介绍STM32标准库的基本概念及其在嵌入式开发中的重要性,强调GPIO作为外设基础模块的关键作用。
GPIO基本概念
GPIO(General-Purpose Input/Output,通用输入 / 输出)是 MCU(微控制器)上最基础、最常用的外设之一,本质是一组可通过软件配置的通用引脚,用于连接外部硬件(如 LED、按键、传感器等),实现数据的输入和输出控制。
IO口
我们知道每一个板子都有很多个引脚,以STM32F103RCT6为例,
STM32F103RCT6 共有 64 个引脚。其中 51 个用于数据的输入输出。为了管理这些引脚,引入 GPIO 端口来管理。
每个 GPIO 端口最多管理 16 个 IO 口(专用于数据输入输出的引脚)。51 个 IO 口必须使用多个 GPIO 端口才能管理。因此对 GPIO 端口进行编号:GPIOA,GPIOB,GPIOC...
那我们怎么表示每个端口的IO口呢?
很简单,我们都知道每个端口都有16个引脚,分别是pin0,pin1,pin2...pin15,而这些引脚分配在不同的端口下,因此就有了PA0,PA1,PA2,PA3,...,PA15这样的说法,在不同的端口下,每个引脚的端口号都不一样,我能将STM32F103RCT6的51个引脚分成了GPIOA(Pin0-Pin15),GPIOB(Pin0-Pin15),GPIOC(Pin0-Pin15),以及GPIOD(PIN0-PIN2).
那各个端口又是如何处理各个IO口的呢?
通过各自的寄存器。每个外设都有它的特定的寄存器。GPIO 端口有 7 个寄存器:
CRL 配置低寄存器
CRH 配置高寄存器
IDR 输入数据寄存器,读取它可获取 IO 口电平状态,1 高电平,0 低电平
ODR 输出数据寄存器,写它可以对 IO 输出高低电平,1 高电平,0 低电平。开漏时写 1 输出高阻抗
BSRR 复位/置位寄存器
BRR 复位寄存器
LCKR 配置锁定寄存器
IO的基本结构:
了解完什么是GPIO,我们再来了解一下GPIO的几种工作模式
4 种输入模式:
输入浮空 ,输入上拉, 输入下拉,模拟输入
4 种输出模式:
通用推挽输出,通用开漏输出,复用功能推挽输出,复用功能开漏输出
输入浮空/上拉/下拉配置
输入模拟配置
推挽输出(上面是高电平下面是低电平)
开漏输出(上面是高电平下面是低电平)
那怎么选择我们的输出模式呢?
对外输出数字信号时,一般配置为推挽输出。
一般外部电路外接上拉电阻,并且所有设备都配置为开漏时,才使用开漏模式。I2C 总线配置为开漏模式。
在开漏模式时,对输入数据寄存器的读访问可得到I/O状态
在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值。
在知道了GPIO的输入输出模式之后,我们来看一下GPIO.h库下一些比较常用的函数
#include "stm32f10x_gpio.h"
// GPIO 端口默认初始化
void GPIO_DeInit(GPIO_TypeDef* GPIOx);
// AFIO 默认初始化
void GPIO_AFIODeInit(void);
// GPIO 端口初始化(重点使用)
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
// GPIO 结构体初始化
void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);// 读 IDR 的某个位
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 读 IDR 所有低 16 个位
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);// 读 ODR 的某个位
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 读 ODR 的所有低 16 个位
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
// 对 ODR 某些位置 1
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 对 ODR 某些位清 0
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 对 ODR 的某个位写 0 或 1
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
// 写 ODR 的所有低 16 个位
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);// 锁定配置
void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);// 事件输出配置
void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
// 使能/禁用事件输出
void GPIO_EventOutputCmd(FunctionalState NewState);// 复用功能重映射配置
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);// 外部中断线配置
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
在了解完一些常用的函数之后我们就可以开始我们简单的GPIO的配置了
GPIO初始化步骤
- 硬件连接分析:明确目标引脚及电路设计需求(如驱动LED、读取按键)。
- 时钟使能:调用
RCC_APB2PeriphClockCmd()
开启对应GPIO端口的时钟。 - 参数配置:填充
GPIO_InitTypeDef
结构体(引脚号、模式、速度等)。 - 初始化函数调用:通过
GPIO_Init()
完成配置。
关键函数与参数详解
GPIO_Init()
:参数配置逻辑与实例(如GPIO_Mode_Out_PP
推挽输出)。GPIO_SetBits()
/GPIO_ResetBits()
:控制引脚高低电平的方法。
代码实例
提供完整的初始化代码片段,以点亮LED为例:
gpio.c
#include"gpio.h"
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);//使能时钟
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6| GPIO_Pin_7|GPIO_Pin_8;//选择Pin
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, & GPIO_InitStruct);
GPIO_WriteBit(GPIOC, GPIO_Pin_6| GPIO_Pin_7|GPIO_Pin_8,Bit_SET);//默认输出高电平
}
void delay(uint32_t ms)
{
for(uint32_t i=0;i<=ms*7200;i++)
{
__NOP();
}
}
gpio.h
#ifndef __GPIO_H_
#define __GPIO_H_
#include "stm32f10x.h"
#include <stdio.h>
void MX_GPIO_Init(void);
void delay(uint32_t ms);
#endif
main.c
/**
******************************************************************************
* @file Project/STM32F10x_StdPeriph_Template/main.c
* @author MCD Application Team
* @version V3.5.0
* @date 08-April-2011
* @brief Main program body
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include"gpio.h"
int main(void)
{
MX_GPIO_Init();
while(1)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_6,Bit_RESET);//默认输出低电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_6,Bit_SET);//默认输出高电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_7,Bit_RESET);//默认输出低电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_7,Bit_SET);//默认输出高电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_8,Bit_RESET);//默认输出低电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_8,Bit_SET);//默认输出高电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_7|GPIO_Pin_8,Bit_RESET);//默认输出低电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_7|GPIO_Pin_8,Bit_SET);//默认输出高电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_6|GPIO_Pin_8,Bit_RESET);//默认输出低电平
delay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_6|GPIO_Pin_8,Bit_SET);//默认输出高电平
delay(500);
}
}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
常见问题与调试技巧
- 时钟未使能导致初始化失败。
- 模式选择错误(如输入误配为输出)。
- 使用逻辑分析仪或万用表验证信号。
总结
强调标准库在快速开发中的优势,建议结合数据手册(如《STM32参考手册》)深入理解寄存器与库函数的关联。通过观察原理图找到等所在引脚,通过所在的引脚去配置,并分析灯的有效电平是高电平还是低电平.