为什么STM32中SPI的MISO引脚设置成复用推挽输出原子哥这个MISO,方向由SPI硬件控制,所以设置为复用推挽输出,也是可以的

本文探讨了STM32开发板上SPI实验中MISO端口的配置问题,虽然理论上MISO应设置为输入模式,但在实际操作中,即使设置为复用推挽输出也能正常工作。文章深入解析了这种现象的原因,并提供了详细的SPI初始化代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原子论坛:今天看了一下战舰开发板试验23的SPI实验,发现GPIO_PIN_14口,也就是SPI的MISO口,实验中设置的复用推挽输出,而查了中文参考手册,手册里面写的是在主模式下,MISO引脚应该设置成浮空或者带上拉输入才对,我把实验代码下载到了开发板,测试又是正常的,这个好奇怪???另外我还发现一个现象,MISO这个引脚就算你不对这个IO口进行设置(也就是说:不设置MISO引脚的GPIO_InitStructure.GPIO_Pin这个参数,也不设置初始的高低电平状态,发现传输也是正常。有人能解释一下这两种情况下为什么还能正常工作吗?
void SPI2_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  SPI_InitTypeDef  SPI_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能 
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2,  ENABLE );//SPI2时钟使能 
 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15复用推挽输出 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB

  GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);  //PB13/14/15上拉

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
 
SPI_Cmd(SPI2, ENABLE); //使能SPI外设

SPI2_ReadWriteByte(0xff);//启动传输  
 

 

在复用SPI总线时,必须先设置总线端口。读取其他ARM芯片(如NXP)一般很容易看出芯片的设置是否正确。不过对于STM32就容易让人迷惑了。例如,我们在使用SPI总线进行通信时,可以这样设置:

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;     // 复用的推挽输出

       恐怕大家对MISO端口的设置就会产生疑惑了,MISO不是应该设置成为输入端口(GPIO_Mode_IN_FLOATING)才行的吗?

      答题是肯定的,对于STM32的这一类管脚来说(如USART_RX)即可以设置成为输入模式,也可以设置成为复用的推挽输出。其工作都是正常的,不过建议大家还是设置成为输入端口的好,容易理解。

      具体产生这一问题的原因是:从功能上来说,MISO应该配置为输入模式才对,但为什么也可以配置为GPIO_Mode_AF_PP?请看下面的GPIO复用功能配置框图。当一个GPIO端口配置为GPIO_Mode_AF_PP是,这个端口的内部结构框图如下:图中可以看到,片上外设的复用功能输出信号会连接到输出控制电路,然后在端口上产生输出信号。但是在芯片内部,MISO是SPI模块的输入引脚,而不是输出引脚,也就是说图中的"复用功能输出信号"根本不存在,因此"输出控制电路"不能对外产生输出信号。而另一方面看,即使在GPIO_Mode_AF_PP模式下,复用功能输入信号却与外部引脚之间相互连接,既MISO得到了外部信号的电平,实现了输入的功能。

http://www.openedv.com/forum.php?mod=viewthread&tid=21805&highlight=MISO

<think>嗯,我现在要了解一下SPI的IO口配置,特别是推挽输出和开漏输出的区别以及使用场景。之前学过一点STM32GPIO配置,但对这两种模式的具体应用还不太清楚。首先,我需要回忆一下推挽输出和开漏输出的基本概念。 根据之前看的资料,推挽输出模式(Push-Pull)是通过两个晶体管(一个上拉,一个下拉)来直接驱动高电平或低电平。当输出高电平时,上边的晶体管导通,下边的关闭,这样IO口输出VDD;当输出低电平时,下边的导通,上边的关闭,输出接地。这样推挽输出的驱动能力比较强,可以直接驱动像LED这样的负载,不需要外接上拉电阻。 而开漏输出(Open-Drain)则是只有下拉晶体管,没有上拉的。当输出高电平时,实际上晶体管是关闭的,这时候IO口处于高阻态,需要外接上拉电阻才能拉到高电平。开漏输出的优点是允许线或连接,多个设备可以共享同一总线而不会冲突,比如I2C总线就常用开漏模式。 那在SPI通信中,这两种模式的应用有什么不同呢?SPI通常需要较高的速率,主从设备之间通过MOSI、MISO、SCK等信号线通信。主设备的SCK、MOSI应该配置为什么模式呢?推挽输出可能更适合,因为推挽的驱动能力强,信号上升沿和下降沿更快,适合高速传输。而如果使用开漏输出,可能需要外接上拉电阻,这样可能会增加上升时间,影响速度。但是某些情况下,比如多个主设备共享总线,或者需要电平兼容不同电压的设备,可能需要开漏加上拉的方式。 另外,MISO线的情况可能不同。从设备的MISO通常配置推挽输出吗?或者是否有可能需要开漏?如果多个从设备共用MISO线,可能需要开漏模式,避免多个输出同时推挽导致冲突。不过通常SPI每个从设备都有单独的片选信号,所以MISO可能不需要线或,直接推挽输出就可以了。 另外,配置方法方面,在STM32的标准库或HAL库中,如何设置SPI的IO口模式?比如,使用GPIO_Mode_Out_PP(推挽输出)或者GPIO_Mode_Out_OD(开漏输出)。需要查一下相关库函数的配置参数。 还有,SPI总线的电平问题。如果主设备和从设备的电压不同,比如主设备是3.3V,从设备是5V,这时候可能需要开漏输出加上拉电阻到5V,这样可以实现电平转换。而推挽输出在这种情况下可能会有电平不兼容的问题,导致损坏设备或者信号错误。 总结一下,推挽输出适用于需要高速、强驱动能力的场景,如SPI的主设备输出信号线;而开漏输出适用于需要总线共享、电平转换或防止冲突的情况。不过在大多数SPI应用中,主设备的SCK、MOSI和从设备的MISO通常使用推挽输出,以确保信号质量。但在特殊情况下,比如多主设备或混合电压系统,可能需要开漏输出。</think>### SPI接口推挽输出与开漏输出详解 #### 1. 核心区别 - **推挽输出(Push-Pull)** 通过上下两个晶体管交替导通,直接输出高/低电平,驱动能力强,适合高速场景。例如: $$V_{out} = \begin{cases} V_{DD} & \text{高电平} \\ 0 & \text{低电平} \end{cases}$$ - **开漏输出(Open-Drain)** 仅下拉晶体管工作,高电平依赖外部上拉电阻,支持总线共享和电平转换。例如: $$V_{out} = \begin{cases} V_{pull-up} & \text{高电平} \\ 0 & \text{低电平} \end{cases}$$ #### 2. 使用场景对比 | **场景** | 推挽输出 | 开漏输出 | |-----------------------|----------------------------|----------------------------| | 驱动能力 | 强(直接驱动LED、电机等)[^2] | 弱(需外接上拉) | | 总线共享 | 不支持(可能冲突) | 支持(如I²C) | | 电平兼容性 | 仅匹配自身电压 | 支持多电压(如3.3V↔5V) | | 信号速度 | 快(陡峭边沿) | 较慢(上拉电阻影响) | #### 3. SPI接口配置建议 - **主设备引脚(SCK/MOSI)** 优先选择推挽输出,确保高速信号完整性(如SPI时钟频率>10MHz时)。 - **从设备引脚MISO)** 若为单从设备,用推挽输出;若多从设备共享MISO,需开漏输出+上拉电阻。 - **电平转换需求** 若主从设备电压不同(如3.3V主控与5V外设),开漏输出+外部上拉至目标电压。 #### 4. STM32配置方法 **标准库示例**(以SCK引脚配置为例): ```c // 推挽输出配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 开漏输出配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏输出 ``` **HAL库示例**: ```c GPIO_InitStruct.Alternate = GPIO_AF5_SPI1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 推挽模式 // 或 GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // 开漏模式 ``` #### 5. 典型问题分析 **案例1**:SPI通信中出现波形畸变 原因可能是开漏输出未接上拉电阻,导致高电平上升缓慢。解决方法:改用推挽输出或添加1-10kΩ上拉电阻。 **案例2**:3.3V MCU连接5V传感器 使用开漏输出+外部上拉至5V,既可保护MCU引脚,又实现电平匹配[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值