STM32 SPI从机向主机发送数据失败问题咨询
问题解答
1. 从机向主机发送数据是否必须使用全双工模式?
是的,必须使用全双工模式。SPI的核心机制是只有主机能生成时钟信号,从机只能在主机提供的时钟同步下发送数据。当从机要向主机传输数据时,主机需要发送哑元字节来触发时钟,同时在同一时钟周期内接收从机输出的数据——这种“同时收发”的操作只有全双工模式(SPI_DIRECTION_2LINES)才能支持。
你当前的配置中,主机和从机都使用了SPI_DIRECTION_1LINE(半双工),同一时间只能单向传输,无法实现主机发哑元的同时接收从机数据,这是你接收全'\0'的核心原因之一。
2. 从机端应使用哪些HAL函数,调用顺序是怎样的?
从机无法主动发起通信,只能被动响应主机的时钟触发,正确操作流程如下:
- 初始化阶段:确保从机SPI配置为全双工模式,NSS设置为硬件输入(你当前的这部分配置是正确的)。
- 准备发送数据:在主机发起通信前,从机要提前将待发送数据加载到TX缓冲区,并启动中断/DMA模式的发送操作,等待主机时钟触发。常用函数:
HAL_SPI_Transmit_IT():中断模式发送,主机时钟启动后自动移出缓冲区数据。HAL_SPI_Transmit_DMA():DMA模式发送,适合大数据量传输。
- 回调处理:在
HAL_SPI_TxCpltCallback()中处理发送完成后的逻辑(比如重新加载数据准备下一次传输)。
注意:从机不能调用阻塞式的HAL_SPI_Transmit(),因为它会等待自身生成时钟(而从机无时钟控制权),导致死锁。
代码与配置问题修正
1. SPI配置修改
将主机和从机的传输方向改为全双工:
// 主机SPI1配置修改 hspi1.Init.Direction = SPI_DIRECTION_2LINES; // 从机SPI2配置修改 hspi2.Init.Direction = SPI_DIRECTION_2LINES;
2. 代码逻辑调整
主机端:
使用HAL_SPI_TransmitReceive_IT()同时发送哑元字节并接收从机数据,替代分开调用的收发操作:
void ex1(){ uint8_t dummy_buff[BUFF_SIZE] = {0}; // 哑元字节缓冲区 uint8_t spi1_rx_buff[BUFF_SIZE] = {0}; uint8_t spi2_tx_buff[BUFF_SIZE] = "Hello from Slave!"; // 从机要发送的数据 // 从机提前启动中断发送,等待主机时钟触发 HAL_SPI_Transmit_IT(SPI_2_SLAVE, spi2_tx_buff, BUFF_SIZE); while(1){ // 主机发起通信:发送哑元,同步接收从机数据 HAL_SPI_TransmitReceive_IT(SPI_1_MASTER, dummy_buff, spi1_rx_buff, BUFF_SIZE); // 等待接收完成回调 while(!flag_1); flag_1 = 0; // 通过UART打印接收结果 HAL_UART_Transmit(UART_DEBUG, spi1_rx_buff, strlen((char*)spi1_rx_buff), HAL_MAX_DELAY); // 重新启动从机发送,准备下一次传输 HAL_SPI_Transmit_IT(SPI_2_SLAVE, spi2_tx_buff, BUFF_SIZE); HAL_Delay(1000); // 延时循环测试 } }
中断回调补充:
添加发送完成回调处理从机发送逻辑:
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi){ if (hspi == SPI_1_MASTER){ flag_1 = 1; // 主机接收完成标志 } } void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi){ if (hspi == SPI_2_SLAVE){ // 从机发送完成,可在此准备下一次发送数据 } }
3. 其他注意事项
- 硬件连线必须正确:主机SCK→从机SCK,主机MOSI→从机MOSI,主机MISO→从机MISO,主机NSS→从机NSS。
- 主机与从机的SPI参数(时钟极性、相位、数据位宽、传输首位)必须完全一致,你当前的这部分配置是匹配的,无需修改。
内容的提问来源于stack exchange,提问作者Yarden Modan
相关产品推荐
相关产品推荐

