目錄
一、SPI介紹
SPI 是英語Serial Peripheral interface的縮寫,顧名思義就是串行外圍設備接口。是Motorola首先在其MC68HCXX系列處理器上定義的。SPI,是一種高速的,全雙工,同步的通信總線,並且在芯片的管腳上只佔用四根線,節約了芯片的管腳,同時爲PCB的佈局上節省空間,提供方便,主要應用在 EEPROM,FLASH,實時時鐘,AD轉換器,還有數字信號處理器和數字信號解碼器之間。
正是簡單易用的特性,如NRF24L01、VS1053、SD卡等皆集成了這種通信協議
二、SPI接口框圖
三、SPI優缺點
SPI接口是在CPU和外圍低速器件之間進行同步串行數據傳輸,在主器件的移位脈衝下,數據按位傳輸,低位在前,高位在後,爲全雙工通信,數據傳輸速度總體來說比I2C總線要快,速度可達到幾Mbps。
信號線少,協議簡單,相對數據速率高。
缺點:沒有指定的流控制,沒有應答機制確認是否接收到數據
四、SPI工作原理總結
- 硬件上爲4根線。
- 主機和從機都有一個串行移位寄存器,主機通過向它的SPI串行寄存器寫入一個字節來發起一次傳輸。
- 串行移位寄存器通過MOSI信號線將字節傳送給從機,從機也將自己的串行移位寄存器中的內容通過MISO信號線返回給主機。這樣,兩個移位寄存器中的內容就被交換。
- 外設的寫操作和讀操作是同步完成的。如果只進行寫操作,主機只需忽略接收到的字節;反之,若主機要讀取從機的一個字節,就必鬚髮送一個空字節來引發從機的傳輸。
多個設備使用SPI的應用舉例
五、時序圖
時序爲 SPI_CR1 寄存器中的 LSBFIRST 位復位時的時序
SPI_CPHA的值將會影響SPI_CPOL的值
六、SPI程序編寫過程
//①使能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);
//④SPI傳輸數據
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.c:
#include "spi.h"
//以下是SPI模塊的初始化代碼,配置成主機模式
//SPI口初始化
//這裏針是對SPI1的初始化
void SPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能SPI1時鐘
//GPIOFB3,4,5初始化設置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5複用功能輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//複用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推輓輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3複用爲 SPI1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4複用爲 SPI1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5複用爲 SPI1
//這裏只針對SPI口初始化
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//復位SPI1
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止復位SPI1
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(SPI1, &SPI_InitStructure); //根據SPI_InitStruct中指定的參數初始化外設SPIx寄存器
SPI_Cmd(SPI1, ENABLE); //使能SPI外設
SPI1_ReadWriteByte(0xff);//啓動傳輸
}
//SPI1速度設置函數
//SPI速度=fAPB2/分頻係數
//@ref SPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256
//fAPB2時鐘一般爲84Mhz:
void SPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判斷有效性
SPI1->CR1&=0XFFC7;//位3-5清零,用來設置波特率
SPI1->CR1|=SPI_BaudRatePrescaler; //設置SPI1速度
SPI_Cmd(SPI1,ENABLE); //使能SPI1
}
//SPI1 讀寫一個字節
//TxData:要寫入的字節
//返回值:讀取到的字節
u8 SPI1_ReadWriteByte(u8 TxData)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//等待發送區空
SPI_I2S_SendData(SPI1, TxData); //通過外設SPIx發送一個byte 數據
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一個byte
return SPI_I2S_ReceiveData(SPI1); //返回通過SPIx最近接收的數據
}
七、W25Q12xx的原理及應用
W25Q128將16M的容量分爲256個塊(Block),每個塊大小爲64K字節,每個塊又分爲16個扇區(Sector),每個扇區4K個字節。W25Q128的最小擦除單位爲一個扇區,也就是每次必須擦除4K個字節。這樣我們需要給W25Q128開闢一個至少4K的緩存區,這樣對SRAM要求比較高,要求芯片必須有4K以上SRAM才能很好的操作。
W25Q128的擦寫週期多達10W次,具有20年的數據保存期限,支持電壓爲2.7~3.6V,W25Q128支持標準的SPI,還支持雙輸出/四輸出的SPI,最大SPI時鐘可以到80Mhz(雙輸出時相當於160Mhz,四輸出時相當於320M),更多的W25Q128的介紹,請參考W25Q128的DATASHEET。
W25Q12xx可根據原理圖查看,使用的是SPI總線通信協議
比如原子的原理圖
7.1 分析W25Q128指令
可參考W25Qxx的數據手冊,這裏列出W25Q128部分指令:
比如讀取設備的ID的指令:0x90000000
7.2 擦除扇區:
7.3 部分常用設備讀取指令:
0x90FFFFFF |
讀取廠商ID |
0x20xxxxxx |
擦除扇區地址 |
0x05FFFFFF |
讀取flash狀態 |
0x02|addr|data |
寫入數據 |
0x03 | 讀取數據 |
每次操作前要使能寫操作,且給一個低電平。結束時要給其爲高電平,再失能寫操作。也就是通過操作片選引腳來確定是否使能或失能。
W25Q12xx.c:
#include "w25qxx.h"
#include "spi.h"
#include "delay.h"
#include "usart.h"
u16 W25QXX_TYPE=W25Q128; //默認是W25Q128
//4Kbytes爲一個Sector
//16個扇區爲1個Block
//W25Q128
//容量爲16M字節,共有128個Block,4096個Sector
//初始化SPI FLASH的IO口
void W25QXX_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB時鐘
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG時鐘
//GPIOB14
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;//PB14
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//輸出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推輓輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//PG7
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
GPIO_SetBits(GPIOG,GPIO_Pin_7);//PG7輸出1,防止NRF干擾SPI FLASH的通信
W25QXX_CS=1; //SPI FLASH不選中
SPI1_Init(); //初始化SPI
SPI1_SetSpeed(SPI_BaudRatePrescaler_2); //設置爲42M時鐘,高速模式
W25QXX_TYPE=W25QXX_ReadID(); //讀取FLASH ID.
}
//讀取W25QXX的狀態寄存器
//BIT7 6 5 4 3 2 1 0
//SPR RV TB BP2 BP1 BP0 WEL BUSY
//SPR:默認0,狀態寄存器保護位,配合WP使用
//TB,BP2,BP1,BP0:FLASH區域寫保護設置
//WEL:寫使能鎖定
//BUSY:忙標記位(1,忙;0,空閒)
//默認:0x00
u8 W25QXX_ReadSR(void)
{
u8 byte=0;
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_ReadStatusReg); //發送讀取狀態寄存器命令
byte=SPI1_ReadWriteByte(0Xff); //讀取一個字節
W25QXX_CS=1; //取消片選
return byte;
}
//寫W25QXX狀態寄存器
//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以寫!!!
void W25QXX_Write_SR(u8 sr)
{
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_WriteStatusReg); //發送寫取狀態寄存器命令
SPI1_ReadWriteByte(sr); //寫入一個字節
W25QXX_CS=1; //取消片選
}
//W25QXX寫使能
//將WEL置位
void W25QXX_Write_Enable(void)
{
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_WriteEnable); //發送寫使能
W25QXX_CS=1; //取消片選
}
//W25QXX寫禁止
//將WEL清零
void W25QXX_Write_Disable(void)
{
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_WriteDisable); //發送寫禁止指令
W25QXX_CS=1; //取消片選
}
//讀取芯片ID
//返回值如下:
//0XEF13,表示芯片型號爲W25Q80
//0XEF14,表示芯片型號爲W25Q16
//0XEF15,表示芯片型號爲W25Q32
//0XEF16,表示芯片型號爲W25Q64
//0XEF17,表示芯片型號爲W25Q128
u16 W25QXX_ReadID(void)
{
u16 Temp = 0;
W25QXX_CS=0;
SPI1_ReadWriteByte(0x90);//發送讀取ID命令
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
Temp|=SPI1_ReadWriteByte(0xFF)<<8;
Temp|=SPI1_ReadWriteByte(0xFF);
W25QXX_CS=1;
return Temp;
}
//讀取SPI FLASH
//在指定地址開始讀取指定長度的數據
//pBuffer:數據存儲區
//ReadAddr:開始讀取的地址(24bit)
//NumByteToRead:要讀取的字節數(最大65535)
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_ReadData); //發送讀取命令
SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //發送24bit地址
SPI1_ReadWriteByte((u8)((ReadAddr)>>8));
SPI1_ReadWriteByte((u8)ReadAddr);
for(i=0;i<NumByteToRead;i++)
{
pBuffer[i]=SPI1_ReadWriteByte(0XFF); //循環讀數
}
W25QXX_CS=1;
}
//SPI在一頁(0~65535)內寫入少於256個字節的數據
//在指定地址開始寫入最大256字節的數據
//pBuffer:數據存儲區
//WriteAddr:開始寫入的地址(24bit)
//NumByteToWrite:要寫入的字節數(最大256),該數不應該超過該頁的剩餘字節數!!!
void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 i;
W25QXX_Write_Enable(); //SET WEL
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_PageProgram); //發送寫頁命令
SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //發送24bit地址
SPI1_ReadWriteByte((u8)((WriteAddr)>>8));
SPI1_ReadWriteByte((u8)WriteAddr);
for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);//循環寫數
W25QXX_CS=1; //取消片選
W25QXX_Wait_Busy(); //等待寫入結束
}
//無檢驗寫SPI FLASH
//必須確保所寫的地址範圍內的數據全部爲0XFF,否則在非0XFF處寫入的數據將失敗!
//具有自動換頁功能
//在指定地址開始寫入指定長度的數據,但是要確保地址不越界!
//pBuffer:數據存儲區
//WriteAddr:開始寫入的地址(24bit)
//NumByteToWrite:要寫入的字節數(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u16 pageremain;
pageremain=256-WriteAddr%256; //單頁剩餘的字節數
if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大於256個字節
while(1)
{
W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
if(NumByteToWrite==pageremain)break;//寫入結束了
else //NumByteToWrite>pageremain
{
pBuffer+=pageremain;
WriteAddr+=pageremain;
NumByteToWrite-=pageremain; //減去已經寫入了的字節數
if(NumByteToWrite>256)pageremain=256; //一次可以寫入256個字節
else pageremain=NumByteToWrite; //不夠256個字節了
}
};
}
//寫SPI FLASH
//在指定地址開始寫入指定長度的數據
//該函數帶擦除操作!
//pBuffer:數據存儲區
//WriteAddr:開始寫入的地址(24bit)
//NumByteToWrite:要寫入的字節數(最大65535)
u8 W25QXX_BUFFER[4096];
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)
{
u32 secpos;
u16 secoff;
u16 secremain;
u16 i;
u8 * W25QXX_BUF;
W25QXX_BUF=W25QXX_BUFFER;
secpos=WriteAddr/4096;//扇區地址
secoff=WriteAddr%4096;//在扇區內的偏移
secremain=4096-secoff;//扇區剩餘空間大小
//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//測試用
if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大於4096個字節
while(1)
{
W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//讀出整個扇區的內容
for(i=0;i<secremain;i++)//校驗數據
{
if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除
}
if(i<secremain)//需要擦除
{
W25QXX_Erase_Sector(secpos);//擦除這個扇區
for(i=0;i<secremain;i++) //複製
{
W25QXX_BUF[i+secoff]=pBuffer[i];
}
W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//寫入整個扇區
}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//寫已經擦除了的,直接寫入扇區剩餘區間.
if(NumByteToWrite==secremain)break;//寫入結束了
else//寫入未結束
{
secpos++;//扇區地址增1
secoff=0;//偏移位置爲0
pBuffer+=secremain; //指針偏移
WriteAddr+=secremain;//寫地址偏移
NumByteToWrite-=secremain; //字節數遞減
if(NumByteToWrite>4096)secremain=4096; //下一個扇區還是寫不完
else secremain=NumByteToWrite; //下一個扇區可以寫完了
}
};
}
//擦除整個芯片
//等待時間超長...
void W25QXX_Erase_Chip(void)
{
W25QXX_Write_Enable(); //SET WEL
W25QXX_Wait_Busy();
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_ChipErase); //發送片擦除命令
W25QXX_CS=1; //取消片選
W25QXX_Wait_Busy(); //等待芯片擦除結束
}
//擦除一個扇區
//Dst_Addr:扇區地址 根據實際容量設置
//擦除一個山區的最少時間:150ms
void W25QXX_Erase_Sector(u32 Dst_Addr)
{
//監視falsh擦除情況,測試用
printf("fe:%x\r\n",Dst_Addr);
Dst_Addr*=4096;
W25QXX_Write_Enable(); //SET WEL
W25QXX_Wait_Busy();
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_SectorErase); //發送扇區擦除指令
SPI1_ReadWriteByte((u8)((Dst_Addr)>>16)); //發送24bit地址
SPI1_ReadWriteByte((u8)((Dst_Addr)>>8));
SPI1_ReadWriteByte((u8)Dst_Addr);
W25QXX_CS=1; //取消片選
W25QXX_Wait_Busy(); //等待擦除完成
}
//等待空閒
void W25QXX_Wait_Busy(void)
{
while((W25QXX_ReadSR()&0x01)==0x01); // 等待BUSY位清空
}
//進入掉電模式
void W25QXX_PowerDown(void)
{
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_PowerDown); //發送掉電命令
W25QXX_CS=1; //取消片選
delay_us(3); //等待TPD
}
//喚醒
void W25QXX_WAKEUP(void)
{
W25QXX_CS=0; //使能器件
SPI1_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
W25QXX_CS=1; //取消片選
delay_us(3); //等待TRES1
}
W25Q12xx.h:
#ifndef __W25QXX_H
#define __W25QXX_H
#include "sys.h"
//W25X系列/Q系列芯片列表
//W25Q80 ID 0XEF13
//W25Q16 ID 0XEF14
//W25Q32 ID 0XEF15
//W25Q64 ID 0XEF16
//W25Q128 ID 0XEF17
#define W25Q80 0XEF13
#define W25Q16 0XEF14
#define W25Q32 0XEF15
#define W25Q64 0XEF16
#define W25Q128 0XEF17
extern u16 W25QXX_TYPE; //定義W25QXX芯片型號
#define W25QXX_CS PBout(14) //W25QXX的片選信號
//////////////////////////////////////////////////////////////////////////////////
//指令表
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_FastReadDual 0x3B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_PowerDown 0xB9
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
void W25QXX_Init(void);
u16 W25QXX_ReadID(void); //讀取FLASH ID
u8 W25QXX_ReadSR(void); //讀取狀態寄存器
void W25QXX_Write_SR(u8 sr); //寫狀態寄存器
void W25QXX_Write_Enable(void); //寫使能
void W25QXX_Write_Disable(void); //寫保護
void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead); //讀取flash
void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//寫入flash
void W25QXX_Erase_Chip(void); //整片擦除
void W25QXX_Erase_Sector(u32 Dst_Addr); //扇區擦除
void W25QXX_Wait_Busy(void); //等待空閒
void W25QXX_PowerDown(void); //進入掉電模式
void W25QXX_WAKEUP(void); //喚醒
#endif
main.c:
main.c:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "spi.h"
#include "w25qxx.h"
#include "key.h"
//要寫入到W25Q16的字符串數組
const u8 TEXT_Buffer[]={"Explorer STM32F4 SPI TEST"};
#define SIZE sizeof(TEXT_Buffer)
int main(void)
{
u8 key;
u16 i=0;
u8 datatemp[SIZE];
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設置系統中斷優先級分組2
delay_init(168); //初始化延時函數
uart_init(115200); //初始化串口波特率爲115200
LED_Init(); //初始化LED
KEY_Init(); //按鍵初始化
W25QXX_Init(); //W25QXX初始化
while(W25QXX_ReadID()!=W25Q128) //檢測不到W25Q128
{
printf("W25Q128 Check Failed!");
delay_ms(500);
printf("Please Check! ");
delay_ms(500);
LED0=!LED0; //DS0閃爍
}
while(1)
{
key=KEY_Scan(0);
if(key==KEY1_PRES)//KEY1按下,寫入24C02
{
printf("Start Write W25Q128....");
//從倒數第100個地址處開始,寫入SIZE長度的數據
W25QXX_Write((u8*)TEXT_Buffer,FLASH_SIZE-100,SIZE);
printf("W25Q128 Write Finished!"); //提示傳送完成
}
if(key==KEY0_PRES)//KEY0按下,讀取字符串並顯示
{
printf("Start Read W25Q128.... ");
//從倒數第100個地址處開始,讀出SIZE個字節
W25QXX_Read(datatemp,FLASH_SIZE-100,SIZE);
printf("The Data Readed Is: \r\n ");//提示傳送完成
printf("%s\r\n ",datatemp);
}
}
}