在硬件确实连接的情况下,gpio没有输出,可能的原因:
时钟没开
没正确初始化
一些特殊引脚如PC13不适合作为gpio,灌电流能力弱啥的
一标准库中默认的是复用功能,需显式的修改为gpio功能
一个案例:使用spi功能
虽然PB15没有复用
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_0);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_0);但是:
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_RxOnly; 设置了双线,PB15就被强制复用了。
所以PB15虽然初始化了GPIO,但还是用不了,改为单线接收既可。
GPIO 概念
GPIO(General-purpose input/output)为通用输入输出端口,是所有的 MCU 必不可少的外设之一。
GPIO、端口、引脚的概念:
引脚(Pin):物理硬件接口,如 PA1
端口(Port):将引脚按逻辑分组,由寄存器统一控制,如 GPIOA
GPIO:引脚最基本的输出输出功能。
引脚复用,是指将引脚配置为其它外设的功能,如ADC、定时器等,最大化引脚利用率。
GPIO 工作模式:
高低电平定义:
以通过软件配置来进行控制,,,GPIO引脚需要与外设连接在一起,以实现和外设的通信、控制以及采集和捕获等功能。
高低电平的定义:一般电平采用都是TTL电平信号,TTL电平信号规定:+5V等价于逻辑“1”,0V等价于逻辑“0”,但实际上电平有一定的范围:>2.4V就表示高电平,<0.4V就表示低电平。
查看引脚功能
引脚类型:
S:电源供应引脚
I:仅输入
I/O:输入/输出
引脚特性:
TTa:可以容忍3.3V,且支持ADC/DAC模拟功能。
FT:可以容忍5V,FT的也支持ADC/DAC模拟功能啊,所以就很奇怪,为什么上面的不直接写成TT。
B:BOOT0引脚
RST:复位引脚,内部有弱上拉电阻。
复用功能和附加功能是互斥的,使用复用功能或附加功能后,引脚就无法再手动控制了。
复用功能:外设功能复用,通过 GPIOx_AFR 寄存器选择。
附加功能:引脚特殊的功能,这个功能不受GPIO相关的寄存器控制,而是由对应的外设寄存器直接控制的。比如ADC1将PA7(附加功能为ADC12_IN7)引脚作为输入引脚。就是你想要使用这个功能,不是通过GPIO的寄存器设置的,是使用外设的寄存器直接设置的。
(1)对于F405、F407系列
在数据手册(Datasheet)中找到【pin and ball definitions】

(2)对于F103x、F051x系列
在数据手册(Datasheet)中找到【pin definitions】

区别在于:
对于F4:引脚初始化的时候就设置复用了。
对于F1:开启了外设后,它有默认的引脚。引脚初始化后需手动重映射。
对于引脚的复用,有专门的表,看起来更方便:

重映射就是改变外设默认的引脚,前提是修改的那些引脚具有外设的功能。
GD32:
Datasheet:

(1)查找外设可用的引脚
比如搜索 TIMER1_CH

假设根据项目,选择了 PB11 引脚。
(2)根据 PB11 引脚,在表中找到对应外设(TIMER1)的复用号 AF?

GPIO 模式
输入:
浮空输入(默认)
模拟输入
上拉输入
下拉输入
输出:
推挽输出
开漏输出
复用推挽输出
复用开漏输出
GPIO 操作
引脚初始化
工作模式
工作速度:边沿转换速度。
上拉电阻
完整代码:
// 多个引脚使用|分隔F0 标准库:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_InitTypeDef gpio_init_struct;
gpio_init_struct.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
gpio_init_struct.GPIO_Mode = GPIO_Mode_OUT;
gpio_init_struct.GPIO_Speed = GPIO_Speed_50MHz;
gpio_init_struct.GPIO_OType = GPIO_OType_PP;
gpio_init_struct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB, &gpio_init_struct);引脚重置
读引脚
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)写引脚
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)例如:
// 置 1
HAL_GPIO_WritePin(GPIOn, GPIO_PIN_x |GPIO_PIN_x, GPIO_PIN_SET);
// 清 0
HAL_GPIO_WritePin(GPIOn, GPIO_PIN_x |GPIO_PIN_x, GPIO_PIN_RESET);翻转电平
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)例如:
HAL_GPIO_TogglePin(GPIOn, GPIO_PIN_x);使用寄存器方式操作GPIO
寄存器方式设置引脚输入输出:
#define SDA_IN() \
{ \
GPIOB->MODER &=~ (3 << (7 * 2)); \
GPIOB->MODER |= 0 << 7 * 2; \
} // 输入模式一个引脚使用两位控制,这里是PB7,所以是第14、15位。
3 为二进制的11,先清除,再设置。
寄存器方式设置引脚输出电平:
表示寄存器地址:
#define GPIO1_DR *((volatile unsigned int *)0X0209C000)(unsigned int *)0X0209C000:0X0209C000 只是一个数字而已,将其强制转换为一个指针类型的表达式,就像指针变量,指针变量的值为 0X0209C000(volatile unsigned int *)0X0209C000:volatile 告诉编译器指向的 unsigned int 随时可能被硬件修改,禁止优化。*((volatile unsigned int *)0X0209C000):指针解引用,取 0X0209C000 地址处的值。
((volatile unsigned int )0x0209C000) 是一个左值表达式,所以能GPIO1_DR = 1;这种写法