日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《STM32从零开始学习历程》——SPI读取FLASH ID

發布時間:2023/12/10 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《STM32从零开始学习历程》——SPI读取FLASH ID 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

《STM32從零開始學習歷程》@EnzoReventon

SPI讀取FLSAH ID

相關鏈接:
SPI物理層及FLASH芯片介紹
SPI協議層
SPI特性及架構

參考資料:
[野火EmbedFire]《STM32庫開發實戰指南——基于野火霸天虎開發板》
[正點原子]STM32F4開發指南-庫函數版本_V1.2
[ST]《STM32F4xx中文參考手冊》
SPI協議及總線協議介紹
W25Q128產品數據手冊

1 實現功能

本實驗為學習SPI的入門實驗,主要功能是實現使用SPI發送讀取FLASH ID的指令來讀取FLASH ID。

2 硬件設計

本文使用的外設為SPI1(正點原子F4探索者開發板)、FLASH以及USART1。
USART用來調試程序,我們還是使用USART1,因此將PB9,PB10與TX,RX相連接即可。

查閱正點原子F4探索者開發板硬件手冊,了解SPI引腳與GPIO的對應情況。


由上圖可以看出:SPI的SCK,MISO,MOSI分別與芯片的PB3,PB4,PB5連接,片選信號F_CS與PB14相連接,因此在后面程序配置的時候需要注意不能配置錯引腳。

3 軟件設計流程

① 使能SPIx和IO口時鐘
RCC_AHBxPeriphClockCmd() / RCC_APBxPeriphClockCmd();
② 初始化IO口為復用功能
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
③ 設置引腳復用映射:
GPIO_PinAFConfig();
② 初始化SPIx,設置SPIx工作模式
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
③ 使能SPIx
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
④ 編寫字節發送函數:uint8_t SPI_FLASH_ByteWrite(uint8_t data)

  • 發送數據(指令):void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);

  • 接收返回的數據:uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;

⑤ 查看SPI傳輸狀態
SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);

⑥ 編寫SPI發送函數
控制片選引腳:GPIO_ResetBits()、GPIO_SetBits();
⑦ 主函數調用
⑧ 優化程序(超時函數、宏定義)

4 代碼分析

  • 宏定義
  • /*宏定義*//*SPI GPIO 接口*/ #define FLASH_SPI SPI1 #define FLASH_SPI_CLK RCC_APB2Periph_SPI1 #define FLASH_SPI_CLK_INIT RCC_APB2PeriphClockCmd#define FLASH_SPI_SCK_PIN GPIO_Pin_3 #define FLASH_SPI_SCK_GPIO_PORT GPIOB #define FLASH_SPI_SCK_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_SCK_SOURCE GPIO_PinSource3 #define FLASH_SPI_SCK_AF GPIO_AF_SPI1#define FLASH_SPI_MOSI_PIN GPIO_Pin_5 #define FLASH_SPI_MOSI_GPIO_PORT GPIOB #define FLASH_SPI_MOSI_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_MOSI_SOURCE GPIO_PinSource5 #define FLASH_SPI_MOSI_AF GPIO_AF_SPI1#define FLASH_SPI_MISO_PIN GPIO_Pin_4 #define FLASH_SPI_MISO_GPIO_PORT GPIOB #define FLASH_SPI_MISO_GPIO_CLK RCC_AHB1Periph_GPIOB #define FLASH_SPI_MISO_SOURCE GPIO_PinSource4 #define FLASH_SPI_MISO_AF GPIO_AF_SPI1#define FLASH_SPI_CS_PIN GPIO_Pin_14 #define FLASH_SPI_CS_GPIO_PORT GPIOB #define FLASH_SPI_CS_GPIO_CLK RCC_AHB1Periph_GPIOB/*等待超時時間*/ #define SPIT_FLAG_TIMEOUT ((uint32_t)0x1000)
  • 初始化時鐘、GPIO、引腳復用
  • ================================================ SPI GPIO初始化 復用函數 ================================================ */ static void SPI_GPIO_Config(void) {GPIO_InitTypeDef GPIO_InitStructure; FLASH_SPI_CLK_INIT(FLASH_SPI_CLK, ENABLE); //使能SPI時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1)/* 使能 FLASH_SPI 及GPIO 時鐘 *//*!< SPI_FLASH_SPI_CS_GPIO, SPI_FLASH_SPI_MOSI_GPIO, SPI_FLASH_SPI_MISO_GPIO,SPI_FLASH_SPI_SCK_GPIO 時鐘使能 */RCC_AHB1PeriphClockCmd(FLASH_SPI_SCK_GPIO_CLK | FLASH_SPI_MOSI_GPIO_CLK|FLASH_SPI_MISO_GPIO_CLK|FLASH_SPI_CS_GPIO_CLK, ENABLE); //初始化GPIO時鐘//查看引腳,初始化SCK,MOSI,MISO,CS引腳GPIO//設置引腳復用 GPIO_PinAFConfig(FLASH_SPI_SCK_GPIO_PORT, FLASH_SPI_SCK_SOURCE, FLASH_SPI_SCK_AF);GPIO_PinAFConfig(FLASH_SPI_MOSI_GPIO_PORT, FLASH_SPI_MOSI_SOURCE, FLASH_SPI_MOSI_AF); GPIO_PinAFConfig(FLASH_SPI_MISO_GPIO_PORT, FLASH_SPI_MISO_SOURCE, FLASH_SPI_MISO_AF);/*!< 配置 SPI_FLASH_SPI 引腳: SCK */GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(FLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);/*!< 配置 SPI_FLASH_SPI 引腳: MISO */GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);/*!< 配置 SPI_FLASH_SPI 引腳: MOSI */ GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;GPIO_Init(FLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);/*!< 配置 SPI_FLASH_SPI 引腳: CS */GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(FLASH_SPI_CS_GPIO_PORT, &GPIO_InitStructure);}
  • SPI功能初始化
  • /* ================================================ SPI 初始化結構體初始化 ================================================ */ void SPI_Mode_Config(void) {/*!< 初始化SPI結構體函數 */SPI_InitTypeDef SPI_InitStructure;SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_2; //預分頻2SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge; //第1個跳變沿數據被采樣SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low; //串行同步時鐘的空閑狀態為低電平SPI_InitStructure.SPI_CRCPolynomial=7; //CRC值計算的多項式SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b; //SPI發送接收 8位幀結構SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex; //雙線雙向全雙工SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB; //數據傳輸從 MSB位開始SPI_InitStructure.SPI_Mode=SPI_Mode_Master; //主 SPISPI_InitStructure.SPI_NSS=SPI_NSS_Soft; //NSS信號由軟件控制SPI_Init(FLASH_SPI,&SPI_InitStructure);SPI_Cmd(FLASH_SPI,ENABLE);}
  • 使能GPIO初始化以及SPI功能初始化
  • /* ================================================ SPI FLASH 外設初始化 ================================================ */ void SPI_FLASH_Init(void) {SPI_GPIO_Config(); SPI_Mode_Config(); }
  • SPI FLASH 字節寫入函數
  • /* ================================================ 通過SPI發送一個字節 參數:要寫入的數據 返回值:錯誤代碼 ================================================ */ uint8_t SPI_FLASH_ByteWrite(uint8_t data) {//等待TXE標志=1//判斷是否超時SPITimeOut = ((uint32_t)(10 * SPIT_FLAG_TIMEOUT)); //重置等待時間while(SPI_I2S_GetFlagStatus(FLASH_SPI,SPI_I2S_FLAG_TXE) == RESET){SPITimeOut--;if(SPITimeOut == 0){return SPI_TIMEOUT_UserCallback(1);}}SPI_I2S_SendData(FLASH_SPI,data); //發送指令給FLASH//等待RXNE標志來確認發送完成,即準備讀取數據//判斷是否超時SPITimeOut = ((uint32_t)(10 * SPIT_FLAG_TIMEOUT)); //重置等待時間while(SPI_I2S_GetFlagStatus(FLASH_SPI,SPI_I2S_FLAG_RXNE) == RESET){SPITimeOut--;if(SPITimeOut == 0){return SPI_TIMEOUT_UserCallback(2);}}return SPI_I2S_ReceiveData(FLASH_SPI); //返回FLASH返回的數據}
  • SPI讀取FLASH ID函數

    查閱手冊,如果想要讀取FLASH的ID,需要給FLASH的第一個字節發送ABh,其余發送FF。
  • //讀ID0 -ID7 uint8_t SPI_FLASH_Read_ID(void) {uint8_t id;//控制片選引腳FLASH_SPI_CS_LOW();//指令代碼SPI_FLASH_ByteWrite(0xAB);SPI_FLASH_ByteWrite(0xFF);SPI_FLASH_ByteWrite(0xFF);SPI_FLASH_ByteWrite(0xFF);//接收讀取到的內容id = SPI_FLASH_ByteWrite(0xFF);FLASH_SPI_CS_HIGH();return id;}
  • 超時函數,返回錯誤代碼函數
  • /* ================================================ 錯誤代碼返回函數 參數:寫如的錯誤代碼 返回值:錯誤代碼 ================================================ */ static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode) {/* Block communication and all processes */printf("\r\nSPI 等待超時!errorCode = %d\r\n",errorCode);return errorCode; }
  • 主函數
  • int main(void) {NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置系統中斷優先級分組2delay_init(168); //延時初始化 uart_init(115200); //串口初始化波特率為115200LED_Init(); //初始化與LED連接的硬件接口 SPI_FLASH_Init(); //SPI_FLASH初始化函數printf("\r\n===================================\r\n");printf("this is id : 0x%x",SPI_FLASH_Read_ID());while(1){} }

    5 實驗效果

    下載程序至開發板,通過串口調試助手可以看到返回的FLASH ID為0x17h。

    總結

    以上是生活随笔為你收集整理的《STM32从零开始学习历程》——SPI读取FLASH ID的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。