【STM32項目實戰】一文了解單片機的SPI驅動外設功能

前言:在前面我有文章介紹了關于單片機的SPI外設CUBEMX配置,但是要想使用好SPI這個外設我們還必須對其原理性的時序有一個詳細的了解,所以這篇文章就補充一下SPI比較偏向底層的時序性的邏輯。


1,SPI簡介

SPI是MCU最常見的對外通信口之一,由摩托羅拉在上世紀80年代中開發,用于嵌入式系統中器件之間的短距離數據通信,標準模式使用四條信號線。目前常見的應用器件有:LCD模組、以太網模塊、SPI串行Flash和很多傳感器等,大部分SD卡都具有SPI操作模式

其采用主從模式(Master Slave)架構:支持多 slave 模式應用,般僅支持單 Master。時鐘由 Master 控制,在時鐘移位脈沖下,數據按位傳輸,高位在前,低位在后(MSB frst):SPI接口有2根單向數據線,為全雙工通信,目前應用中的數據速率可達幾 Mbps 的水平。

總結一下關鍵特點:

  • 同步通信:通信雙方共享一個時鐘信號

  • 全雙工傳輸:支持同時發送與接收

  • 速度快:常見支持幾MHz甚至幾十MHz

  • 多從機支持:主機通過CS片選控制多個從設備

2,SPI的物理接口

文章上面第一個章節我們有提到SPI的標準模式使用四條信號線,比如下面這個圖,其中的CSS片選線如果只有一個從機就可以忽略不計(單從機也就是說可以使用三根線),如果有多個從機那么CSS片選線的數量等于從機的數量

?

主從機內部結構簡化圖:?

?

?3,SPI通信原理詳解

按照時鐘極性和相位(CPOL & CPHA)可以將SPI協議分成4種模式:

如果 CPOL=0 ,串行同步時鐘的空閑狀態為低電平;如果 CPOL=1 ,串行同步時鐘的空閑狀態為高電平。時鐘相位 (CPHA) 能夠配置用于選擇兩種不同的傳輸協議之一進行數據傳輸。如果 CPHA=0 ,在串行同步時鐘的第一個跳變沿 ( 上升或下降 ) 數據被采樣;如果 CPHA=1 ,在串行同步時鐘的第二個跳變沿 ( 上升或下降 ) 數據被采樣

值得注意的是:發送和接收必須使用相同的時鐘配置,否則會出現數據偏移或失真。

?詳細的4種模式的時序示意圖:

4,MCU中的SPI外設結構

STM32 MCU 為例,SPI模塊一般包括以下部分:

  • 寄存器控制:用于配置波特率、主從模式、CPOL/CPHA等參數

  • TX/RX 緩沖器:發送與接收使用各自的 FIFO

  • 狀態寄存器:可判斷是否發送完成、是否接收到數據等

  • 中斷控制:可設置中斷方式發送/接收

  • DMA支持:支持高速數據傳輸而不占用CPU

常用寄存器:

  • SPI_CR1:控制寄存器(如主從、CPOL、CPHA)

  • SPI_SR:狀態寄存器(如TXE/RXNE位)

  • SPI_DR:數據寄存器(發送/接收)

當然,想了解MCU的SPI外設的特性,主要還是得看對應某一款芯片的參考手冊。下面就以STM32F4的參考手冊為例。

?SPI框圖:

5,基于STM32G474的SPI配置示例

都是CUBEMX生成的,大家看看參考一下就可以了。。。

spi.c

/* USER CODE BEGIN Header */
/********************************************************************************* @file    spi.c* @brief   This file provides code for the configuration*          of the SPI instances.******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "spi.h"/* USER CODE BEGIN 0 *//* USER CODE END 0 */SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_tx;
DMA_HandleTypeDef hdma_spi1_rx;// #define SPI_DMA_BUFFER_SIZE 16// uint8_t spi_tx_buffer[SPI_DMA_BUFFER_SIZE];
// uint8_t spi_rx_buffer[SPI_DMA_BUFFER_SIZE];
/* spi1 init function */
void MX_SPI1_Init(void)
{/* USER CODE BEGIN spi1_Init 0 *//* USER CODE END spi1_Init 0 *//* USER CODE BEGIN spi1_Init 1 *//* USER CODE END spi1_Init 1 */hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;hspi1.Init.Direction = SPI_DIRECTION_2LINES;hspi1.Init.DataSize = SPI_DATASIZE_16BIT;hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;hspi1.Init.NSS = SPI_NSS_SOFT;hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi1.Init.TIMode = SPI_TIMODE_DISABLE;hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi1.Init.CRCPolynomial = 7;hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;if (HAL_SPI_Init(&hspi1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN SPI1_Init 2 */}void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(spiHandle->Instance==SPI1){/* USER CODE BEGIN SPI1_MspInit 0 *//* USER CODE END SPI1_MspInit 0 *//* SPI1 clock enable */__HAL_RCC_SPI1_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_DMA1_CLK_ENABLE();/**SPI1 GPIO ConfigurationPB5     ------> SPI1_SCKPB6     ------> SPI1_MISOPB7     ------> SPI1_MOSI*/GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USER CODE BEGIN SPI1_MspInit 1 *//* SPI1 interrupt Init */HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);HAL_NVIC_EnableIRQ(SPI1_IRQn);/* USER CODE END SPI1_MspInit 1 */}
}void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{if(spiHandle->Instance==SPI1){/* USER CODE BEGIN SPI1_MspDeInit 0 *//* USER CODE END SPI1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_SPI1_CLK_DISABLE();/**SPI1 GPIO ConfigurationPB5     ------> SPI1_SCKPB6     ------> SPI1_MISOPB7     ------> SPI1_MOSI*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);/* SPI1 interrupt Deinit */HAL_NVIC_DisableIRQ(SPI1_IRQn);/* USER CODE BEGIN SPI1_MspDeInit 1 *//* USER CODE END SPI1_MspDeInit 1 */}
}/* USER CODE BEGIN 1 */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{if (hspi == &hspi1){// printf("SPI1 DMA Transfer Completed!\r\n");}
}/* USER CODE END 1 */

spi.h

/* USER CODE BEGIN Header */
/********************************************************************************* @file    spi.h* @brief   This file contains all the function prototypes for*          the spi.c file******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SPI_H__
#define __SPI_H__#ifdef __cplusplus
extern "C" {
#endif/* Includes ------------------------------------------------------------------*/
#include "main.h"/* USER CODE BEGIN Includes *//* USER CODE END Includes */extern SPI_HandleTypeDef hspi1;
extern DMA_HandleTypeDef hdma_spi1_tx;
extern DMA_HandleTypeDef hdma_spi1_rx;/* USER CODE BEGIN Private defines *//* USER CODE END Private defines */void MX_SPI1_Init(void);/* USER CODE BEGIN Prototypes *//* USER CODE END Prototypes */#ifdef __cplusplus
}
#endif#endif /* __SPI_H__ */

完結。。。?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81935.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81935.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81935.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【挖洞利器】GobyAwvs解放雙手

【滲透測試工具】解放雙手&Goby配合Awvs滲透測試利器\x0a通過Goby和Awvs 解放雙手https://mp.weixin.qq.com/s/SquRK8C5cRpWmfGbIOqxoQ

LangChain4j(15)——RAG高級之跳過檢索

之前的文章中,我們介紹了RAG的使用,但是,每次提問時,都會通過RAG進行檢索。有時,檢索是不必要執行的,比如,當用戶只是說“你好”時。于是,我們需要有條件的跳過檢索過程。 跳過決策…

【SDRS】面向多模態情感分析的情感感知解糾纏表征轉移

abstract 多模態情感分析(MSA)旨在利用多模態的互補信息對用戶生成的視頻進行情感理解。現有的方法主要集中在設計復雜的特征融合策略來整合單獨提取的多模態表示,忽略了與情感無關的信息的干擾。在本文中,我們提出將單模表征分解為情感特定特征和情感獨立特征,并將前者融…

Sui 上線兩周年,掀起增長「海嘯」

兩年前的 5 月 3 日,Sui 的主網正式發布,將在開發網和測試網上驗證過的下一代技術承諾變為現實。這一新興網絡旨在優化現有區塊鏈技術,結合高性能計算環境與安全性、可驗證性及韌性。 隨著 Sui 迎來兩周年,這股浪潮已成長為「海嘯…

深入理解 mapper-locations

mybatis-plus.mapper-locations: classpath*:/mapper/**/*.xml 是 MyBatis/MyBatis-Plus 在 Spring Boot 配置文件(如 application.yml 或 application.properties)中的一項關鍵配置,用于指定 MyBatis Mapper XML 文件的存放路徑。以下是詳細…

電容的作用

使用多個電容是從電容的實際等效模型去考慮的(也就是從SI,信號完整性方面)。只考慮一個實際電容時,它的阻抗曲線是一個類似于倒三角形的形狀,只在諧振頻率點(與等效串聯電感形成)處的阻抗最小。因此相當于只在這一個頻率點處及附近…

移植的本質是什么

有斷時間我就在想,為什么freertos,lvgl等等的移植都是把庫文件放進來,直接點擊編譯,然后把bug都處理完成就移植成功了,為什么呢? 明明我一個函數都沒調用,為什么會有一堆錯誤,莫名其…

廣告場景下的檢索平臺技術

檢索方向概述 數據檢索領域技術選型大體分為SQL事務數據庫、NoSQL數據庫、分析型數據庫三個類型。 SQL數據庫的設計思路是采用關系模型組織數據,注重讀寫操作的一致性,注重數據的絕對安全。為了實現這一思路,SQL數據庫往往會犧牲部分性能&…

高頻PCB設計如何選擇PCB層數?

以四層板為例,可以第一層和第二層畫信號,作為信號層。 第三層可以走電源,然后第四層走GND 但是更可以第一層和第三層畫信號。第二層可以走電源,然后第四層走GND 用中間的電源層以及地層可以起到屏蔽的作用,有效降低寄…

[Linux_69] 數據鏈路層 | Mac幀格式 | 局域網轉發 | MTU MSS

目錄 0.引入 1.以太網幀格式 2.重談局域網轉發的原理(基于協議) 小結 3.認識MTU 3.1MTU對IP協議的影響 3.2MTU對UDP協議的影響 3.3MTU對于TCP協議的影響 0.引入 在去年的這篇文章中,我們有對網絡進行過一個概述[Linux#47][網絡] 網絡協議 | TCP/IP模型 | 以…

vue2 provide 后 inject 數據不是響應式的,不實時更新

今天用 provide 后&#xff0c;inject 獲取數據時不是實時更新的&#xff0c;獲取的不是更新后的值 祖父組件 <div style"text-align: left !important;"><button click"change">更改</button> </div>data() {return {name: ini…

洛谷---P1629 郵遞員送信

題目描述 有一個郵遞員要送東西&#xff0c;郵局在節點 1。他總共要送 n?1 樣東西&#xff0c;其目的地分別是節點 2 到節點 n。由于這個城市的交通比較繁忙&#xff0c;因此所有的道路都是單行的&#xff0c;共有 m 條道路。這個郵遞員每次只能帶一樣東西&#xff0c;并且運…

2025年LangChain(V0.3)開發與綜合案例

LangChain是什么&#xff1f; 在實際企業開發中&#xff0c;大模型應用往往比簡單的問答要復雜得多。如果只是簡單地向大模型提問并獲取回答&#xff0c;那么大模型的許多強大功能都沒有被充分利用。 要開始使用LangChain&#xff0c;首先需要安裝相關的庫&#xff1a; pip …

十分鐘了解 @MapperScan

MapperScan 是 MyBatis 和 MyBatis-Plus 提供的一個 Spring Boot 注解&#xff0c;用于自動掃描并注冊 Mapper 接口&#xff0c;使其能夠被 Spring 容器管理&#xff0c;并與對應的 XML 或注解 SQL 綁定。它的核心作用是簡化 MyBatis Mapper 接口的配置&#xff0c;避免手動逐個…

深度解析 MindTorch:無縫遷移 PyTorch 到 MindSpore 的高效工具

在深度學習領域&#xff0c;框架的選擇往往取決于開發者的習慣、硬件支持以及項目需求。PyTorch 作為當前最受歡迎的深度學習框架之一&#xff0c;以其動態圖機制和簡潔的 API 設計深受開發者喜愛。然而&#xff0c;隨著昇騰硬件的崛起&#xff0c;如何高效地利用昇騰的強大計算…

[250506] Auto-cpufreq 2.6 版本發布:帶來增強的 TUI 監控及多項改進

目錄 Auto-cpufreq 2.6 版本發布&#xff1a;帶來增強的 TUI 監控及多項改進 Auto-cpufreq 2.6 版本發布&#xff1a;帶來增強的 TUI 監控及多項改進 Auto-cpufreq&#xff0c;一款適用于 Linux 的免費開源自動 CPU 速度與功耗優化器&#xff0c;已發布其最新版本 2.6。該工具…

Linux 更改內存交換 swap 為 zram 壓縮,減小磁盤寫入

1、查看當前 swap 的方式 swapon --show 我這里是默認的 swap 文件&#xff0c;大小為 2G。 2、安裝 zram Ubuntu 下&#xff1a; sudo apt install zram-tools安裝后默認會啟動&#xff1a; 3、關閉默認的 swap 文件 sudo swapoff /swapfile 其次是關閉 /etc/fstab 中的 …

ORCAD打印pdf

1 筆記本電腦綁定了打印機&#xff0c;要改成這個

C++中指針使用詳解(4)指針的高級應用匯總

C 中指針的高級應用非常豐富&#xff0c;掌握這些內容能讓你寫出更高性能、更底層控制力強的代碼。下面是應用模塊梳理和例子講解。 目錄預覽 函數指針與回調機制指針數組 vs 數組指針指針與類成員函數&#xff08;成員函數指針&#xff09;智能指針&#xff08;unique_ptr, s…

圖像處理軟件imgPro—調參救星!

推薦一款圖像處理軟件imgPro&#xff0c;該軟件是逛B站時偶然間發現&#xff0c;雖然up主是新號&#xff0c;但是視頻中看起來非常實用&#xff01; 核心是多種算法高效調參&#xff0c;亮點是自動生成源碼&#xff01;這您受得了嗎&#xff1f;調試之后&#xff0c;直接復制代…