国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

STM32—SPI詳解入門(mén)(使用SPI通訊讀寫(xiě)W25Q128模塊)

這篇具有很好參考價(jià)值的文章主要介紹了STM32—SPI詳解入門(mén)(使用SPI通訊讀寫(xiě)W25Q128模塊)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

目錄

一、SPI是什么

二、SPI物理架構(gòu)

三、SPI工作原理

四、SPI工作模式

五、SPI相關(guān)寄存器介紹

六、SPI用到的結(jié)構(gòu)體與函數(shù)

1.結(jié)構(gòu)體

2.函數(shù)

七、W25Q128芯片

1.W25Q128介紹

2.W25Q128存儲(chǔ)架構(gòu)

3.W25Q128常用指令

4.W25Q128狀態(tài)寄存器

5.W25Q128常見(jiàn)操作流程

八、實(shí)驗(yàn)(使用SPI通訊讀寫(xiě)W25Q128模塊)

1.接線

2.配置

3.代碼

1.main.c文件

2.w25q128.c文件(向工程添加w25q128.c文件)

3.w25q128.h文件(向工程添加w25q128.h文件)

4.spi.c文件編寫(xiě)

5.spi.h文件編寫(xiě)

九、STM32工程添加.c和.h文件


一、SPI是什么

????????SPI是串行外設(shè)接口(Serial Peripheral Interface)的縮寫(xiě),是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節(jié)約了芯片的管腳,同時(shí)為PCB的布局上節(jié)省空間,提供方便,正是出于這種簡(jiǎn)單易用的特性,越來(lái)越多的芯片集成了這種通信協(xié)議,比如 AT91RM9200 。

二、SPI物理架構(gòu)

????????SPI總線包含四條總線:分別為MOSI、MISO、SCK、NSS(CS)。

(1)MISO:主設(shè)備輸入/從設(shè)備輸出引腳。該引腳在從模式下發(fā)送數(shù)據(jù),在主模式下接收數(shù)據(jù)。

(2)MOSI:主設(shè)備輸出/從設(shè)備輸入引腳。該引腳在主模式下發(fā)送數(shù)據(jù),在從模式下接收數(shù)據(jù)。

(3)SCK:時(shí)鐘信號(hào),可以使主從設(shè)備同步輸入輸出。

(4)NSS(CS):?由主設(shè)備控制,用來(lái)選擇指定的從設(shè)備進(jìn)行通信。(當(dāng)主設(shè)備想要讀/寫(xiě)從設(shè)備時(shí),首先拉低從設(shè)備對(duì)應(yīng)的NSS線)。

三、SPI工作原理

????????1.SPI主從模式

?????????SPI分為主、從兩種模式,一個(gè)SPI通訊系統(tǒng)需要包含一個(gè)(且只能是一個(gè))主設(shè)備,一個(gè)或多個(gè)從設(shè)備。提供時(shí)鐘的為主設(shè)備(Master),接收時(shí)鐘的設(shè)備為從設(shè)備(Slave),SPI接口的讀寫(xiě)操作,都是由主設(shè)備發(fā)起。當(dāng)存在多個(gè)從設(shè)備時(shí),主設(shè)備通過(guò)從設(shè)備各自的片選信號(hào)(NSS)來(lái)選擇從設(shè)備。

????????2.SPI主、從設(shè)備通訊接線

????????????????一個(gè)主設(shè)備和一個(gè)從設(shè)備

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ??? ???????????一個(gè)主設(shè)備和多個(gè)從設(shè)備????????

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? 3.SPI數(shù)據(jù)傳輸

????????SPI主設(shè)備和從設(shè)備都有一個(gè)移位寄存器,主機(jī)可以通過(guò)向它的移位寄存器寫(xiě)入數(shù)據(jù)來(lái)發(fā)起一次SPI通訊,主設(shè)備的7移到從設(shè)備的0上,而從設(shè)備的7移到主設(shè)備的0上。

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

1.主設(shè)備拉低對(duì)應(yīng)從設(shè)備的NSS信號(hào)線。(選擇從設(shè)備進(jìn)行通信)

2.主設(shè)備發(fā)送時(shí)鐘信號(hào),從設(shè)備接收時(shí)鐘信號(hào)。(告訴從設(shè)備開(kāi)始進(jìn)行SPI通訊)

3.數(shù)據(jù)交換

????????主設(shè)備(Master)將要發(fā)送的數(shù)據(jù)傳輸?shù)桨l(fā)送緩存區(qū)(Menory),當(dāng)從設(shè)備收到主設(shè)備發(fā)送的時(shí)鐘信號(hào),并且在MOSI引腳上出現(xiàn)第一個(gè)數(shù)據(jù)位時(shí),發(fā)送過(guò)程開(kāi)始。余下的位被裝進(jìn)移位寄存器,通過(guò)MOSI信號(hào)線將字節(jié)一位一位的發(fā)送給從設(shè)備。同時(shí)主設(shè)備通過(guò)MISO引腳將數(shù)據(jù)一位一位的接收到移位寄存器,當(dāng)數(shù)據(jù)接收完成時(shí),將數(shù)據(jù)傳輸?shù)浇邮站彌_區(qū)。

????????從設(shè)備同理,將自己發(fā)送緩沖區(qū)的數(shù)據(jù)通過(guò)移位寄存器和MISO一位一位發(fā)送給主設(shè)備,同時(shí)通過(guò)MOSI引腳將數(shù)據(jù)一位一位的接收到移位寄存器,當(dāng)數(shù)據(jù)接收完成時(shí),將數(shù)據(jù)傳輸?shù)浇邮站彌_區(qū)?

????????SPI只有主模式和從模式之分,沒(méi)有讀和寫(xiě)的說(shuō)法,數(shù)據(jù)的寫(xiě)操作和讀操作是同步完成的。

? ? ? ? ? ? ? ? ? ? ? i.如果只進(jìn)行寫(xiě)操作,主機(jī)只需忽略接收到的字節(jié)。? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ii.如果只進(jìn)行讀操作,只需發(fā)送一個(gè)空字節(jié)來(lái)獲取SPI通訊的一個(gè)字節(jié)。

四、SPI工作模式

1.時(shí)鐘極性(CPOL)

????????控制在沒(méi)有數(shù)據(jù)傳輸時(shí)時(shí)鐘線的空閑狀態(tài)電平。? ? ? ?

  • 0:SCK在空閑狀態(tài)保持低電平。

  • 1:SCK在空閑狀態(tài)保持高電平。

2.時(shí)鐘相位(CPHA)

????????時(shí)鐘線在第幾個(gè)時(shí)鐘邊沿采樣數(shù)據(jù)。

  • 0:SCK的第一個(gè)(奇數(shù))邊沿進(jìn)行數(shù)據(jù)位采樣,數(shù)據(jù)在第一個(gè)時(shí)鐘邊沿被鎖存。

  • 1:SCK的第二個(gè)(偶數(shù))邊沿進(jìn)行數(shù)據(jù)位采樣,數(shù)據(jù)在第二個(gè)時(shí)鐘邊沿被鎖存。

3.SPI模式時(shí)序圖

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? 模式0(常用)(CPOL = 0,CPHA = 0)

? ? ? ? ? ? ?空閑時(shí)SCK時(shí)鐘為低電平,采樣時(shí)刻為第一個(gè)邊沿即上升沿。如圖所示,黃線進(jìn)行采樣

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? ?模式1(CPOL = 0,CPHA = 1)

? ? ? ? ? ? ?空閑時(shí)SCK時(shí)鐘為低電平,采樣時(shí)刻為第二個(gè)邊沿即下降沿。如圖所示,黃線進(jìn)行采樣。

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? ?模式2(CPOL = 1,CPHA = 0)

? ? ? ? ? ? ?空閑時(shí)SCK時(shí)鐘為高電平,采樣時(shí)刻為第一個(gè)邊沿即下降沿。如圖所示,黃線進(jìn)行采樣。

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

????????模式3(常用)(CPOL = 1,CPHA = 1)

? ? ? ? ? ??空閑時(shí)SCK時(shí)鐘為高電平,采樣時(shí)刻為第二個(gè)邊沿即上升沿。如圖所示,黃線進(jìn)行采樣。

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

五、SPI相關(guān)寄存器介紹

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

六、SPI用到的結(jié)構(gòu)體與函數(shù)

1.結(jié)構(gòu)體

(句柄結(jié)構(gòu)體)SPI_HandleTypeDef

typedef struct __SPI_HandleTypeDef
{
  SPI_TypeDef  *Instance;  /* SPIx */
 
  SPI_InitTypeDef  Init;  /* SPI初始化結(jié)構(gòu)體:通信參數(shù) */
 
} SPI_HandleTypeDef;

(初始化結(jié)構(gòu)體)SPI_InitTypeDefSPI

typedef struct
{
  uint32_t Mode;  /* SPI模式(主機(jī)模式。從機(jī)模式) */
 
  uint32_t Direction;  /* 工作方式(全雙工方式、半雙工、只讀、只寫(xiě)) */
 
  uint32_t DataSize;  /* 數(shù)據(jù)格式(8bit、16bit) */
 
  uint32_t CLKPolarity;  /* 時(shí)鐘極性(CPOL) */
 
  uint32_t CLKPhase;  /* 時(shí)鐘相位(CPHA) */
 
  uint32_t NSS;  /* SS控制方式(軟件) */
 
  uint32_t BaudRatePrescaler;  /* SPI波特率預(yù)分頻值 */
 
  uint32_t FirstBit;  /* 數(shù)據(jù)傳輸順序(MSB、LSB) */
 
  uint32_t TIMode;  /* 數(shù)據(jù)幀格式(Motorola、TI)*/
 
  uint32_t CRCCalculation;  /* 設(shè)置硬件CRC檢驗(yàn) */
 
  uint32_t CRCPolynomial;  /* 設(shè)置CRC檢驗(yàn)多項(xiàng)式 */
 
} SPI_InitTypeDef;

2.函數(shù)

__HAL_RCC_SPI1_CLK_ENABLE()

使能SPI時(shí)鐘。(使用STM32CubeMX會(huì)自動(dòng)配置)

HAL_SPI_Init()

初始化SPI。(使用STM32CubeMX會(huì)自動(dòng)配置)

HAL_SPI_MspInit()

初始化SPI相關(guān)引腳。(使用STM32CubeMX會(huì)自動(dòng)配置)

HAL_SPI_Transmit()? (SPI發(fā)送數(shù)據(jù))

原型:
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

參數(shù):
SPI_HandleTypeDef *hspi:SPI句柄
uint8_t *pData:發(fā)送數(shù)據(jù)的存儲(chǔ)地址
uint16_t Size:發(fā)送的數(shù)據(jù)量大小
uint32_t Timeout:超時(shí)時(shí)間

實(shí)例:
uint8_t uint8_t data = 56;

HAL_SPI_TransmitReceive(&hspi1, &data, 1, 1000);

HAL_SPI_Receive()? (SPI接收數(shù)據(jù))

原型:
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

參數(shù):
SPI_HandleTypeDef *hspi:SPI句柄
uint8_t *pData:接收數(shù)據(jù)的存儲(chǔ)地址
uint16_t Size:接收的數(shù)據(jù)量大小
uint32_t Timeout:超時(shí)時(shí)間

實(shí)例:
uint8_t uint8_t data;

HAL_SPI_TransmitReceive(&hspi1, &data, 1, 1000);

HAL_SPI_TransmitReceive()? (SPI發(fā)送接收數(shù)據(jù))

原型:
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,uint32_t Timeout)

參數(shù):
SPI_HandleTypeDef *hspi:SPI句柄
uint8_t *pTxData:發(fā)送數(shù)據(jù)的存儲(chǔ)地址
uint8_t *pRxData:接收數(shù)據(jù)的存儲(chǔ)地址
uint16_t Size:發(fā)送和接收的數(shù)據(jù)量大小
uint32_t Timeout:超時(shí)時(shí)間

實(shí)例:
uint8_t spi1_read_write_byte(uint8_t data)
{
uint8_t rec_data = 0;

HAL_SPI_TransmitReceive(&hspi1, &data, &rec_data, 1, 1000);

return rec_data;
}

__HAL_SPI_ENABLE()? ?(使能SPI外設(shè))

__HAL_SPI_DISABLE()? ? (失能SPI外設(shè))

七、W25Q128芯片

1.W25Q128介紹

  • W25Q128是華邦公司推出的一款SPI接口的NOR FIash芯片,其存儲(chǔ)空間為128 Mbit,相當(dāng)于16M字節(jié)。

  • Flash 是常用的用于儲(chǔ)存數(shù)據(jù)的半導(dǎo)體器件,它具有容量大,可重復(fù)擦寫(xiě)、按”扇區(qū)/塊”擦除、掉電后數(shù)據(jù)可繼續(xù)保存的特性。

  • Flash 是有一個(gè)物理特性:只能寫(xiě)0,不能寫(xiě)1,靠擦除來(lái)寫(xiě)1。

  • 支持SPI模式1。

  • 數(shù)據(jù)格式:8bit,MSB。

2.W25Q128存儲(chǔ)架構(gòu)

  • 一個(gè)W25Q128 = 256個(gè)塊 = 256 * 16個(gè)扇區(qū) = 256 * 16 *16個(gè)頁(yè) = 256 * 16 * 16 * 256個(gè)字節(jié),即16777216字節(jié),約16M字節(jié),即尋址范圍為0x00 ~ 0xFFFFFF。

  • 16777216 -1 = 0xFFFFFF。

  • 對(duì)Flash擦除時(shí)一般按扇區(qū)(4K = 4096字節(jié))來(lái)進(jìn)行擦除。

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

3.W25Q128常用指令

????????W25Q128 全部指令非常多,但常用的如下幾個(gè)指令:

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

1.寫(xiě)使能(0x06)

  • 寫(xiě)使能指令將狀態(tài)寄存器中的WEL位設(shè)置為1。

  • 必須在每個(gè)頁(yè)寫(xiě)、扇區(qū)擦除、塊擦除、芯片擦除和寫(xiě)狀態(tài)寄存器指令之前進(jìn)行寫(xiě)使能。

  • 操作:拉低CS片選->發(fā)送指令0x06 ->拉高CS片選。

2.讀SR1(0x05)

  • 讀取狀態(tài)寄存器指令允許讀取8位狀態(tài)寄存器的值。

  • 操作:拉低CS片選 ->發(fā)送指令0x05 ->定義一個(gè)uint8_t數(shù)據(jù)接收SR1的返回值 ->拉高CS片選?

3.讀數(shù)據(jù)(0x03)

  • 讀取數(shù)據(jù)指令允許從存儲(chǔ)器順序讀取一個(gè)或多個(gè)數(shù)據(jù)字節(jié)。

  • 操作:拉低CS片選 -> 發(fā)送指令0x03 -> 發(fā)送24位地址 -> 讀取數(shù)據(jù) -> 拉高CS片選

4.頁(yè)寫(xiě)(0x02)

  • 頁(yè)寫(xiě)指令允許在指定地址寫(xiě)入小于256字節(jié)的指定長(zhǎng)度的數(shù)據(jù),在非0xFF處寫(xiě)入的數(shù)據(jù)會(huì)失敗。

  • 操作:寫(xiě)使能 -> 拉低CS片選 -> 發(fā)送指令0x02 -> 發(fā)送24位地址 -> 寫(xiě)入數(shù)據(jù) -> 拉高CS片選 -> 等待寫(xiě)入結(jié)束(即判斷狀態(tài)寄存器的BUSY位是否置0

5.扇區(qū)擦除時(shí)序(0x20)

????????寫(xiě)入數(shù)據(jù)前,檢查內(nèi)存空間是否全部都是 0XFF ,不滿(mǎn)足需擦除。

????????拉低CS片選 → 發(fā)送20H→ 發(fā)送24位地址 → 拉高CS片選

6.芯片擦除(0xC7)

  • 芯片擦除指令將W25Q128的所有數(shù)據(jù)都擦除為0xFF。

  • 操作:寫(xiě)使能 -> 等待空閑(即判斷狀態(tài)寄存器的BUSY位是否置0) -> 拉低CS片選 -> 發(fā)送指令0xC7 -> 拉高CS片選 -> 等待芯片擦除完成(即判斷狀態(tài)寄存器的BUSY位是否置0)

7.讀取W25Q128的芯片ID(0x90)

  • 讀取制造商/設(shè)備ID指令。

  • 操作:拉低片選信號(hào) -> 發(fā)送24位地址,地址為0xFFFFFF -> 定義一個(gè)uint16_t數(shù)據(jù)接收芯片ID -> 拉高片選信號(hào)

4.W25Q128狀態(tài)寄存器

????????W25Q128一共有3個(gè)狀態(tài)寄存器,它們的作用時(shí)跟蹤芯片的狀態(tài)。其中,狀態(tài)寄存器1比較常用。

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? ?1.BUSY位(指示當(dāng)前的狀態(tài))????????

????????BUSY是狀態(tài)寄存器中的只讀位,當(dāng)設(shè)備執(zhí)行頁(yè)程序、四頁(yè)程序、扇區(qū)擦除、塊擦除、芯片擦除、寫(xiě)狀態(tài)寄存器或擦除/程序安全寄存器指令時(shí),將其設(shè)置為1狀態(tài)。 在此期間,器件將忽略除讀取狀態(tài)寄存器和擦除/程序掛起指令之外的其他指令。 當(dāng)編程、擦除或?qū)懭霠顟B(tài)/安全寄存器指令完成時(shí),忙位將被清除為0狀態(tài),表示設(shè)備已準(zhǔn)備好接受進(jìn)一步的指令。

0:空閑

1:忙
? ? ? ? 2.WEL位(寫(xiě)使能鎖定)

????????WEL是狀態(tài)寄存器(S1)中的只讀位,在執(zhí)行寫(xiě)使能指令后被設(shè)置為1。 當(dāng)設(shè)備被禁止寫(xiě)入時(shí),WEL狀態(tài)位被清除為0。 在上電時(shí)或在下列任何指令之后發(fā)生寫(xiě)禁用狀態(tài):寫(xiě)禁用、頁(yè)程序、四頁(yè)程序、扇區(qū)擦除、塊擦除、芯片擦除、寫(xiě)狀態(tài)寄存器、擦除安全寄存器和程序安全寄存器。

1:可以操作頁(yè)、扇區(qū)、塊

0:禁止寫(xiě)入
?

5.W25Q128常見(jiàn)操作流程

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

寫(xiě)操作:

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

八、實(shí)驗(yàn)(使用SPI通訊讀寫(xiě)W25Q128模塊)

1.接線

????????W25Q128與STM32F103C8T6板子接線,在STM32F103C8T6的產(chǎn)品手冊(cè)中找到板子上的SPI1的接口。

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

????????PA4作為SPI1的NSS,PA5作為SPI1的CLK,PA6作為SPI1的DO(MISO),PA7作為SPI1的DI(MOSI)。

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

2.配置

? ? ? ? 1.SYS

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? 2.?RCC

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

?stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

?????????3.SPI1

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

?????????4.SUART1

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? ? 5.使用MicroLIB庫(kù)

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

3.代碼

1.main.c文件

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 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 "main.h"
#include "spi.h"
#include "usart.h"
#include "gpio.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
 
#include "stdio.h"
#include "string.h"
#include "w25q128.h"
 
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
 
#define TEXT_SIZE 16
#define  FLASH_WriteAddress     0x000000  //數(shù)據(jù)寫(xiě)入w25q128的地址,地址范圍為0x000000 ~ 0xFFFFFF
#define  FLASH_ReadAddress      FLASH_WriteAddress
 
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
 
/* USER CODE BEGIN PV */
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
 
//重寫(xiě)stdio.h文件中的prinft()里的fputc()函數(shù)
int fputc(int my_data,FILE *p)
{
    unsigned char temp = my_data;
    //改寫(xiě)后,使用printf()函數(shù)會(huì)將數(shù)據(jù)通過(guò)串口一發(fā)送出去
    HAL_UART_Transmit(&huart1,&temp,1,0xffff);  //0xfffff為最大超時(shí)時(shí)間
    return my_data;
}
 
 
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
    uint8_t datatemp[TEXT_SIZE];
    
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */
 
    /* w25q128初始化 */
    w25q128_init();
    
    /* 寫(xiě)入測(cè)試數(shù)據(jù) */
    sprintf((char *)datatemp, "hello jiangxiao");
    w25q128_write(datatemp, FLASH_WriteAddress, TEXT_SIZE);
    printf("數(shù)據(jù)寫(xiě)入完成!\r\n");
    
    /* 讀出測(cè)試數(shù)據(jù) */
    memset(datatemp, 0, TEXT_SIZE);
    w25q128_read(datatemp, FLASH_ReadAddress, TEXT_SIZE);
    printf("讀出數(shù)據(jù):%s\r\n", datatemp);
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/* USER CODE BEGIN 4 */
 
/* USER CODE END 4 */
 
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
 
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

2.w25q128.c文件(向工程添加w25q128.c文件)

#include "w25q128.h"
#include "spi.h"
#include "stdio.h"
 
 
 
//w25q128初始化
void w25q128_init(void)
{
		uint16_t flash_type;
    spi1_read_write_byte(0xFF); /* 清除DR(數(shù)據(jù)寄存器),寫(xiě)入一個(gè)0xFF */
    W25Q128_CS(1);  //拉高片選信號(hào)不進(jìn)行SPI通信
		flash_type = w25q128_read_id();   /* 讀取FLASH ID. */
		if (flash_type == W25Q128){
			printf("檢測(cè)到W25Q128芯片\r\n");
		}
}
 
 
 
//等待W25Q128空閑
static void w25q128_wait_busy(void)
{
    while ((w25q128_rd_sr1() & 0x01) == 1);   /* 等待狀態(tài)寄存器的BUSY位清空 */
}
 
 
 
//讀取狀態(tài)寄存器的值
uint8_t w25q128_rd_sr1(void)
{
    uint8_t rec_data = 0;
    
    W25Q128_CS(0);
		spi1_read_write_byte(FLASH_ReadStatusReg1);     // 寫(xiě)入指令0x05:讀狀態(tài)寄存器1
    rec_data = spi1_read_write_byte(0xFF);  //獲取狀態(tài)寄存器1的值
    W25Q128_CS(1);
    
    return rec_data;
}
 
 
 
//W25Q128寫(xiě)使能,即置位WEL為1
void w25q128_write_enable(void)
{
    W25Q128_CS(0);
    spi1_read_write_byte(FLASH_WriteEnable);   /* 發(fā)送指令0x06:寫(xiě)使能 */
    W25Q128_CS(1);
}
 
 
 
//發(fā)送24位地址
static void w25q128_send_address(uint32_t address)  /*address:地址范圍0~16777215字節(jié),即尋址范圍為0x00 ~ 0xFFFFFF */
{
    spi1_read_write_byte((uint8_t)((address)>>16));     /* 發(fā)送 bit23 ~ bit16 地址 */
    spi1_read_write_byte((uint8_t)((address)>>8));      /* 發(fā)送 bit15 ~ bit8  地址 */
    spi1_read_write_byte((uint8_t)address);             /* 發(fā)送 bit7  ~ bit0  地址 */
}
 
 
 
//擦除整個(gè)芯片
void w25q128_erase_chip(void)
{
    w25q128_write_enable();    /* 寫(xiě)使能 */
    w25q128_wait_busy();       /* 等待空閑 */
    W25Q128_CS(0);
    spi1_read_write_byte(FLASH_ChipErase);  /* 發(fā)送指令0xC7:擦除整個(gè)芯片 */ 
    W25Q128_CS(1);
    w25q128_wait_busy();       /* 等待芯片擦除結(jié)束 */
}
 
 
 
//擦除一個(gè)扇區(qū)
void w25q128_erase_sector(uint32_t saddr)  /* saddr:該參數(shù)是第幾個(gè)扇區(qū) */
{
    saddr *= 4096;  /* 一個(gè)扇區(qū)大小為4096字節(jié) */
    w25q128_write_enable();        /* 寫(xiě)使能 */
    w25q128_wait_busy();           /* 等待空閑 */
    W25Q128_CS(0);
    spi1_read_write_byte(FLASH_SectorErase);    /* 發(fā)送指令0x20:擦除指定扇區(qū) */
    w25q128_send_address(saddr);   /* 發(fā)送擦除的扇區(qū)地址 */
    W25Q128_CS(1);
    w25q128_wait_busy();           /* 等待扇區(qū)擦除完成 */
}
 
 
 
//讀取w25q128芯片ID
uint16_t w25q128_read_id(void)
{
    uint16_t deviceid;
 
    W25Q128_CS(0);  //拉低片選信號(hào)進(jìn)行SPI通信
    spi1_read_write_byte(FLASH_ManufactDeviceID);   /* 發(fā)送讀取 ID 命令 */
		/* 發(fā)送3個(gè)0 */
		/*
    spi1_read_write_byte(0);    
    spi1_read_write_byte(0);
    spi1_read_write_byte(0);
		*/
	
		w25q128_send_address(0x000000);
	
    deviceid = spi1_read_write_byte(0xFF) << 8;     /* 讀取高8位字節(jié) */
    deviceid |= spi1_read_write_byte(0xFF);         /* 讀取低8位字節(jié) */
    W25Q128_CS(1);
 
    return deviceid;
}
 
/*
讀取W25Q128的FLASH,在指定地址開(kāi)始讀取指定長(zhǎng)度的數(shù)據(jù)
pubf:需要讀取的數(shù)據(jù)
addr:指定的地址
datalen:指定的數(shù)據(jù)大小
*/
void w25q128_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
    uint16_t i;
 
    W25Q128_CS(0);
    spi1_read_write_byte(FLASH_ReadData);       /* 發(fā)送指令0x03:讀取數(shù)據(jù) */
    w25q128_send_address(addr);                /* 發(fā)送需要讀取的數(shù)據(jù)地址 */
    
    for(i=0;i<datalen;i++)
    {
        pbuf[i] = spi1_read_write_byte(0XFF);   /* 循環(huán)讀取 */
    }
    
    W25Q128_CS(1);
}
 
 
 
/*
單頁(yè)寫(xiě),在指定地址寫(xiě)入小于256字節(jié)的指定長(zhǎng)度的數(shù)據(jù),在非0xFF處寫(xiě)入的數(shù)據(jù)會(huì)失敗
pubf:需要寫(xiě)入的數(shù)據(jù)
addr:指定的地址
datalen:指定的數(shù)據(jù)大小
*/
static void w25q128_write_page(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
    uint16_t i;
 
    w25q128_write_enable();    /* 寫(xiě)使能 */
 
    W25Q128_CS(0);
    spi1_read_write_byte(FLASH_PageProgram);    /* 發(fā)送命令0x02:頁(yè)寫(xiě) */
    w25q128_send_address(addr);                /* 發(fā)送寫(xiě)入的頁(yè)地址 */
 
    for(i=0;i<datalen;i++)
    {
        spi1_read_write_byte(pbuf[i]);          /* 循環(huán)寫(xiě)入 */
    }
    
    W25Q128_CS(1);
    w25q128_wait_busy();       /* 等待寫(xiě)入結(jié)束 */
}
 
 
 
/*
多頁(yè)寫(xiě),在指定地址寫(xiě)入指定長(zhǎng)度的數(shù)據(jù),在非0xFF處寫(xiě)入的數(shù)據(jù)會(huì)失敗
pubf:需要寫(xiě)入的數(shù)據(jù)
addr:指定的地址
datalen:指定的數(shù)據(jù)大小
*/
static void w25q128_write_nocheck(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
    uint16_t pageremain;
    pageremain = 256 - addr % 256;  /* 獲取指定地址那頁(yè)的剩余字節(jié)數(shù) */
 
    if (datalen <= pageremain)      /* 指定地址那頁(yè)的剩余字節(jié)數(shù)能裝下指定數(shù)據(jù)大小 */
    {
        pageremain = datalen;  
    }
 
    while (1)
    { 
			/* 當(dāng)指定地址那頁(yè)的剩余字節(jié)數(shù)能裝下指定數(shù)據(jù)大小時(shí),一次性寫(xiě)完 */
            
			/* 當(dāng)指定數(shù)據(jù)大小比指定地址那頁(yè)的剩余字節(jié)數(shù)要大時(shí), 先寫(xiě)完指定地址那頁(yè)的剩余字節(jié), 然后根據(jù)剩余數(shù)據(jù)大小進(jìn)行不同處理 */
        w25q128_write_page(pbuf, addr, pageremain);  //頁(yè)寫(xiě)
 
        if (datalen == pageremain)   /* 寫(xiě)入結(jié)束了 */
        {
            break;  
        }
        else     /* datalen > pageremain */
        {
            pbuf += pageremain;         /* pbuf指針地址偏移,前面已經(jīng)寫(xiě)了pageremain字節(jié) */
            addr += pageremain;         /* 寫(xiě)地址偏移,前面已經(jīng)寫(xiě)了pageremain字節(jié) */
            datalen -= pageremain;      /* 寫(xiě)入總長(zhǎng)度減去已經(jīng)寫(xiě)入了的字節(jié)數(shù) */
 
            if (datalen > 256)          /* 剩余數(shù)據(jù)大小還大于一頁(yè) */
            {
                pageremain= 256;       /* 一次寫(xiě)入256個(gè)字節(jié),即一次寫(xiě)一頁(yè) */
            }
            else     /* 剩余數(shù)據(jù)大小小于一頁(yè)  */
            {
                pageremain= datalen;   /* 一次性寫(xiě)完 */
            }
        }
    }
}
 
 
/*
//寫(xiě)入W25Q128的FLASH,在指定地址開(kāi)寫(xiě)入取指定長(zhǎng)度的數(shù)據(jù)
pubf:需要寫(xiě)入的數(shù)據(jù)
addr:指定的地址
datalen:指定的數(shù)據(jù)大小
*/
uint8_t g_w25q128_buf[4096];   /* 扇區(qū)緩存 */
 
void w25q128_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen)
{
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;
    uint8_t *w25q128_buf;
 
    w25q128_buf = g_w25q128_buf;
    secpos = addr / 4096;       /* 獲取指定地址在哪片扇區(qū) */
    secoff = addr % 4096;       /* 指定數(shù)據(jù)在在扇區(qū)內(nèi)的偏移數(shù)據(jù)大小 */
    secremain = 4096 - secoff;  /* 扇區(qū)剩余字節(jié)數(shù) */
 
    if (datalen <= secremain)  /* 指定地址那片扇區(qū)的剩余字節(jié)數(shù)能裝下指定數(shù)據(jù)大小 */
    {
        secremain = datalen;    
    }
 
    while (1)
    {
        w25q128_read(w25q128_buf, secpos * 4096, 4096);   /* 讀出指定地址那片扇區(qū)的全部?jī)?nèi)容 */
 
        for (i = 0; i < secremain; i++)   /* 校驗(yàn)數(shù)據(jù),防止數(shù)據(jù)出現(xiàn)非0xFF */
        {
            if (w25q128_buf[secoff + i] != 0xFF)  //扇區(qū)數(shù)據(jù)有一個(gè)數(shù)據(jù)不是0xFF
            {
                break;      /* 需要擦除, 直接退出for循環(huán) */
            }
        }
 
        if (i < secremain)   /* 需要擦除 */
        {
            w25q128_erase_sector(secpos);  /* 擦除這個(gè)扇區(qū) */
 
            for (i = 0; i < secremain; i++)   /* 復(fù)制 */
            {
                w25q128_buf[i + secoff] = pbuf[i];
            }
 
            w25q128_write_nocheck(w25q128_buf, secpos * 4096, 4096);  /* 寫(xiě)入整個(gè)扇區(qū) */
        }
        else        /* 寫(xiě)已經(jīng)擦除了的,直接寫(xiě)入扇區(qū)剩余區(qū)間. */
        {
            w25q128_write_nocheck(pbuf, addr, secremain);  /* 直接寫(xiě)扇區(qū) */
        }
 
        if (datalen == secremain)
        {
            break;  /* 寫(xiě)入結(jié)束了 */
        }
        else        /* 寫(xiě)入未結(jié)束 */
        {
            secpos++;               /* 扇區(qū)地址增1,新的一個(gè)扇區(qū) */
            secoff = 0;             /* 偏移位置為0 */
 
            pbuf += secremain;      /* 指針偏移 */
            addr += secremain;      /* 寫(xiě)地址偏移 */
            datalen -= secremain;   /* 字節(jié)數(shù)遞減 */
 
            if (datalen > 4096)
            {
                secremain = 4096;   /* 一次寫(xiě)入一個(gè)扇區(qū) */
            }
            else
            {
                secremain = datalen;/* 一次性寫(xiě)完 */
            }
        }
    }
}
 

3.w25q128.h文件(向工程添加w25q128.h文件)

#include "stdint.h"
 
/* W25Q128片選引腳定義 */
#define W25Q128_CS_GPIO_PORT           GPIOA
#define W25Q128_CS_GPIO_PIN            GPIO_PIN_4
 
/* W25Q128片選信號(hào) */
#define W25Q128_CS(x)      do{ x ? \
                                  HAL_GPIO_WritePin(W25Q128_CS_GPIO_PORT, W25Q128_CS_GPIO_PIN, GPIO_PIN_SET) : \
                                  HAL_GPIO_WritePin(W25Q128_CS_GPIO_PORT, W25Q128_CS_GPIO_PIN, GPIO_PIN_RESET); \
                            }while(0)
 
/* FLASH芯片列表 */
#define W25Q128     0XEF17          /* W25Q128  芯片ID */
 
/* 指令表 */
#define FLASH_WriteEnable                        0x06 
#define FLASH_ReadStatusReg1                0x05 
#define FLASH_ReadData                            0x03 
#define FLASH_PageProgram                        0x02 
#define FLASH_SectorErase                        0x20 
#define FLASH_ChipErase                            0xC7 
#define FLASH_ManufactDeviceID            0x90 
 
/* 靜態(tài)函數(shù) */
static void w25q128_wait_busy(void);                                                                                                //等待W25Q128空閑       
static void w25q128_send_address(uint32_t address);                                                                      //發(fā)送24位地址
static void w25q128_write_page(uint8_t *pbuf, uint32_t addr, uint16_t datalen);         //單頁(yè)寫(xiě),在指定地址寫(xiě)入小于256字節(jié)的指定長(zhǎng)度的數(shù)據(jù),在非0xFF處寫(xiě)入的數(shù)據(jù)會(huì)失敗
static void w25q128_write_nocheck(uint8_t *pbuf, uint32_t addr, uint16_t datalen);        //多頁(yè)寫(xiě),在指定地址寫(xiě)入指定長(zhǎng)度的數(shù)據(jù),在非0xFF處寫(xiě)入的數(shù)據(jù)會(huì)失敗
 
/* 普通函數(shù) */
void w25q128_init(void);                            //w25q128初始化  
uint16_t w25q128_read_id(void);       //讀取w25q128芯片ID   
void w25q128_write_enable(void);      //W25Q128寫(xiě)使能,即置位WEL為1    
uint8_t w25q128_rd_sr1(void);                 //讀取狀態(tài)寄存器的值        
 
void w25q128_erase_chip(void);               //擦除整個(gè)芯片      
void w25q128_erase_sector(uint32_t saddr);   //擦除一個(gè)扇區(qū)
void w25q128_read(uint8_t *pbuf, uint32_t addr, uint16_t datalen);     //讀取W25Q128的FLASH,在指定地址開(kāi)始讀取指定長(zhǎng)度的數(shù)據(jù)
void w25q128_write(uint8_t *pbuf, uint32_t addr, uint16_t datalen);    //寫(xiě)入W25Q128的FLASH,在指定地址開(kāi)寫(xiě)入取指定長(zhǎng)度的數(shù)據(jù)
 
 
 
 

4.spi.c文件編寫(xiě)

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi.c
  * @brief   This file provides code for the configuration
  *          of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 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;  /* SPI句柄 */
 
/* 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;  /* 設(shè)置SPI模式主機(jī)模式 */
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;  /* 設(shè)置SPI工作方式:全雙工 */
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;  /* 設(shè)置數(shù)據(jù)格式:8bit */
    
    /* SPI模式1 */
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;  /* 設(shè)置時(shí)鐘極性:CPOL = 0 */
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;  /* 設(shè)置時(shí)鐘相位:CPHA = 1 */
  
    hspi1.Init.NSS = SPI_NSS_SOFT;  /* 設(shè)置片選方式:軟件NSS */
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;  /* 設(shè)置SPI時(shí)鐘波特率分頻:256分頻 */
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;  /* 設(shè)置數(shù)據(jù)大小端:MSB */
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;  /* 設(shè)置數(shù)據(jù)幀格式:Motolora */
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;  /* 設(shè)置CRC校驗(yàn):關(guān)閉CRC檢驗(yàn) */
  hspi1.Init.CRCPolynomial = 10;  /* 設(shè)置CRC校驗(yàn)多項(xiàng)式:1~65535 */
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */
 
  /* USER CODE END 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_GPIOA_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /* USER CODE BEGIN SPI1_MspInit 1 */
 
  /* 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 Configuration
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);
 
  /* USER CODE BEGIN SPI1_MspDeInit 1 */
 
  /* USER CODE END SPI1_MspDeInit 1 */
  }
}
 
/* USER CODE BEGIN 1 */
 
/*通過(guò)SPI1同時(shí)讀寫(xiě)一個(gè)字節(jié)數(shù)據(jù)
主機(jī)只向從機(jī)進(jìn)行寫(xiě)操作,調(diào)用此函數(shù)時(shí)忽略返回值
主機(jī)只向從機(jī)進(jìn)行讀操作,調(diào)用此函數(shù)時(shí)隨便傳入一個(gè)字符,盡量是0xFF
*/
uint8_t spi1_read_write_byte(uint8_t data)  
{
    uint8_t rec_data = 0;
    
    HAL_SPI_TransmitReceive(&hspi1, &data, &rec_data, 1, 1000);  //spi讀寫(xiě)數(shù)據(jù)函數(shù),參數(shù)2存放用來(lái)發(fā)送的數(shù)據(jù),參數(shù)3存放用來(lái)接收的數(shù)據(jù)
   
    return rec_data;  
}
 
/* USER CODE END 1 */

5.spi.h文件編寫(xiě)

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi.h
  * @brief   This file contains all the function prototypes for
  *          the spi.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 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;
 
/* USER CODE BEGIN Private defines */
 
/* USER CODE END Private defines */
 
void MX_SPI1_Init(void);
 
/* USER CODE BEGIN Prototypes */
 
uint8_t spi1_read_write_byte(uint8_t data);
 
/* USER CODE END Prototypes */
 
#ifdef __cplusplus
}
#endif
 
#endif /* __SPI_H__ */
 

九、STM32工程添加.c和.h文件

????????1.在創(chuàng)建好的STM32工程中找到Core的文件夾

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? ?2.向文件夾里添加新的xxx.c文件或xxx.h文件

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? 3.在keil5中導(dǎo)入工程后,將這兩個(gè)文件添加到工程列表中

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

?stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件

? ? ? ? 4.添加頭文件

????????只需在需要添加頭文件的c文件中寫(xiě)上需添加的頭文件再編譯就能自動(dòng)添加

? ? ? ? 例如下圖

stm32 w25q128,STM32,stm32,單片機(jī),嵌入式硬件?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-628647.html

到了這里,關(guān)于STM32—SPI詳解入門(mén)(使用SPI通訊讀寫(xiě)W25Q128模塊)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • STM32CubeMX教程26 FatFs 文件系統(tǒng) - W25Q128讀寫(xiě)

    正點(diǎn)原子stm32f407探索者開(kāi)發(fā)板V2.4 STM32CubeMX軟件(Version 6.10.0) keil μVision5 IDE(MDK-Arm) ST-LINK/V2驅(qū)動(dòng) 野火DAP仿真器 XCOM V2.6串口助手 使用STM32CubeMX軟件配置STM32F407開(kāi)發(fā)板 使用FatFs中間件通過(guò)SPI通信協(xié)議對(duì)W25Q128芯片進(jìn)行讀寫(xiě)等操作 關(guān)于STM32F407使用SPI通信協(xié)議對(duì)W25Q128 FLASH芯片讀寫(xiě)

    2024年02月19日
    瀏覽(29)
  • 【STM32】SPI初步使用 讀寫(xiě)FLASH W25Q64

    【STM32】SPI初步使用 讀寫(xiě)FLASH W25Q64

    (1) SS( Slave Select):從設(shè)備選擇信號(hào)線,常稱(chēng)為片選信號(hào)線,每個(gè)從設(shè)備都有獨(dú)立的這一條 NSS 信號(hào)線,當(dāng)主機(jī)要選擇從設(shè)備時(shí),把該從設(shè)備的 NSS 信號(hào)線設(shè)置為低電平,該從設(shè)備即被選中,即片選有效,接著主機(jī)開(kāi)始與被選中的從設(shè)備進(jìn)行 SPI通訊。所以 SPI通訊以 NSS 線置低電

    2024年02月10日
    瀏覽(22)
  • STM32-SPI通信(W25Q64芯片簡(jiǎn)介,使用SPI讀寫(xiě)W25Q64存儲(chǔ)器芯片)

    STM32-SPI通信(W25Q64芯片簡(jiǎn)介,使用SPI讀寫(xiě)W25Q64存儲(chǔ)器芯片)

    ???SPI(Serial Peripheral Interface)是由Motorola公司開(kāi)發(fā)的一種通用數(shù)據(jù)總線四根通信線:SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)。 ?SPI通信具有以下特點(diǎn): 同步,全雙工; 支持總線掛載多設(shè)備(SPI僅支持一主多從); 在不

    2024年02月08日
    瀏覽(21)
  • stm32(SPI讀寫(xiě)W25Q18)

    stm32(SPI讀寫(xiě)W25Q18)

    SPI是串行外設(shè)接口(Serial Peripheral Interface)的縮寫(xiě),是一種 高速的,全雙工,同步 的通信總 線,并且在芯片的管腳上只占用四根線,節(jié)約了芯片的管腳,同時(shí)為PCB的布局上節(jié)省空間,提 供方便,正是出于這種簡(jiǎn)單易用的特性,越來(lái)越多的芯片集成了這種通信協(xié)議,比如 A

    2024年02月16日
    瀏覽(23)
  • 【STM32】STM32學(xué)習(xí)筆記-硬件SPI讀寫(xiě)W25Q64(40)

    【STM32】STM32學(xué)習(xí)筆記-硬件SPI讀寫(xiě)W25Q64(40)

    在大容量產(chǎn)品和互聯(lián)型產(chǎn)品上,SPI接口可以配置為支持SPI協(xié)議或者支持I2S音頻協(xié)議。SPI接口默認(rèn)工作在SPI方式,可以通過(guò)軟件把功能從SPI模式切換到I2S模式。 在小容量和中容量產(chǎn)品上,不支持I2S音頻協(xié)議。 串行外設(shè)接口(SPI)允許芯片與外部設(shè)備以半/全雙工、同步、串行方式

    2024年02月19日
    瀏覽(21)
  • 【STM32】STM32學(xué)習(xí)筆記-軟件SPI讀寫(xiě)W25Q64(38)

    【STM32】STM32學(xué)習(xí)筆記-軟件SPI讀寫(xiě)W25Q64(38)

    在大容量產(chǎn)品和互聯(lián)型產(chǎn)品上,SPI接口可以配置為支持SPI協(xié)議或者支持I 2 S音頻協(xié)議。SPI接口默認(rèn)工作在SPI方式,可以通過(guò)軟件把功能從SPI模式切換到I2S模式。 在小容量和中容量產(chǎn)品上,不支持I 2 S音頻協(xié)議。 串行外設(shè)接口(SPI)允許芯片與外部設(shè)備以半/全雙工、同步、串行方

    2024年01月24日
    瀏覽(22)
  • 2023版 STM32實(shí)戰(zhàn)11 SPI總線讀寫(xiě)W25Q

    2023版 STM32實(shí)戰(zhàn)11 SPI總線讀寫(xiě)W25Q

    英文全稱(chēng):Serial peripheral Interface 串行外設(shè)接口 -1- 串行(逐bit傳輸) -2- 同步(共用時(shí)鐘線) -3- 全雙工(收發(fā)可同時(shí)進(jìn)行) -4- 通信只能由主機(jī)發(fā)起(一主,多從機(jī)) -1- CS片選一般配置為軟件控制 -2- 片選低電平有效,從器件CS引腳可直接連接GND -3- 從機(jī)不能主動(dòng)給主機(jī)發(fā)數(shù)據(jù) -4- 主機(jī)想要

    2024年02月08日
    瀏覽(21)
  • 【STM32】軟件SPI讀寫(xiě)W25Q64芯片

    【STM32】軟件SPI讀寫(xiě)W25Q64芯片

    目錄 W25Q64模塊 W25Q64芯片簡(jiǎn)介 硬件電路 W25Q64框圖 Flash操作注意事項(xiàng) 狀態(tài)寄存器 ?編輯 指令集?INSTRUCTIONS?編輯 ?編輯 SPI讀寫(xiě)W25Q64代碼 硬件接線圖 MySPI.c MySPI.h W25Q64 W25Q64.c W25Q64.h W25Q64_Ins.h main.c 測(cè)試 SPI通信(W25Q64芯片簡(jiǎn)介,使用SPI讀寫(xiě)W25Q64存儲(chǔ)器芯片)? SPI通信文章:【

    2024年02月19日
    瀏覽(19)
  • 【STM32CubeMX學(xué)習(xí)】SPI讀寫(xiě)W25Q16

    【STM32CubeMX學(xué)習(xí)】SPI讀寫(xiě)W25Q16

    ????????SPI分為主從工作模式,通常有一個(gè)主設(shè)備和一個(gè)或多個(gè)從設(shè)備,本文中MCU為主機(jī),W25Q16為從機(jī)。 SPI通信有以下四根線: MISO:主設(shè)備數(shù)據(jù)輸入,從設(shè)備數(shù)據(jù)輸出。 MOSI:主設(shè)備數(shù)據(jù)輸出,從設(shè)備數(shù)據(jù)輸入。 SCLK:時(shí)鐘信號(hào),由主設(shè)備產(chǎn)生。 CS:從設(shè)備片選信號(hào),由

    2024年02月03日
    瀏覽(17)
  • 基于STM32實(shí)現(xiàn)W25Q16讀寫(xiě)操作(spi)

    基于STM32實(shí)現(xiàn)W25Q16讀寫(xiě)操作(spi)

    在之前我們學(xué)習(xí)了flash閃存,這個(gè)更多的是內(nèi)部數(shù)據(jù)存儲(chǔ),容量也是會(huì)比較小。這次我們來(lái)學(xué)習(xí)一下更多的存儲(chǔ)單元w25q16,順便了解spi———串行外圍設(shè)備接口。 在我們的核心板子上基本都會(huì)有這么一塊芯片,只是有的容量會(huì)計(jì)較大,大家可以查看板子的原理圖,如圖所示:

    2024年01月19日
    瀏覽(23)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包