ToB企服应用市场:ToB评测及商务社交产业平台

标题: SPI软件模拟读写W25Q64 [打印本页]

作者: 东湖之滨    时间: 2024-9-19 02:55
标题: SPI软件模拟读写W25Q64
1.SPI初始化

  1. #include "stm32f10x.h"                  // Device header
  2. void MySPI_W_SS(uint8_t BitValue)//片选
  3. {
  4.         GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
  5. }
  6. void MySPI_W_SCK(uint8_t BitValue)//时钟线
  7. {
  8.         GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)BitValue);
  9. }
  10. void MySPI_W_MOSI(uint8_t BitValue)//MOSI
  11. {
  12.         GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)BitValue);
  13. }
  14. uint8_t MySPI_R_MISO(void)//MISO
  15. {
  16.         return(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6));
  17. }
  18. void MySPI_Init(void)
  19. {
  20.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  21.        
  22.         GPIO_InitTypeDef GPIO_InitStructure;
  23.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  24.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 |GPIO_Pin_7;//输出脚,配置成推挽输出
  25.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  26.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  27.        
  28.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  29.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//输入脚,配置成上拉输入
  30.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  31.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  32.        
  33.         MySPI_W_SS(1);//片选默认高电平
  34.         MySPI_W_SCK(0);//时钟线默认为0
  35. }
  36. void MySPI_Start(void)
  37. {
  38.         MySPI_W_SS(0);//片选低电平
  39. }
  40. void MySPI_Stop(void)
  41. {
  42.         MySPI_W_SS(1);//片选高电平
  43. }
  44. uint8_t MySPI_BitSend(uint8_t Data)//交换数据
  45. {
  46.         uint8_t i,BitReivce = 0x00;//接收数据默认为0x00
  47.         for(i=0;i<8;i++)
  48.         {
  49.                 MySPI_W_MOSI(Data & (0x80>>i));//此时模式为模式0,因为低电平将数据放入SCk,高电平读取数据
  50.             MySPI_W_SCK(1);
  51.                
  52.                 if(MySPI_R_MISO()== 1){BitReivce |= (0x80>>i);}//该语句首先判断接收到的位是否为1,通过|=来提出该位的1,否则为零
  53.             MySPI_W_SCK(0);
  54.         }
  55.         return BitReivce;
  56. }
复制代码
完成SPI基本时序单元,包罗起始条件,终止条件,互换一个字节。为了方便放标操作,封装了一些函数。
2.1基于SPI的W25Q64初始化

根据W25Q64指令表实现相关指令
  1. #include "stm32f10x.h"                  // Device header
  2. #include "MySPI.h"   
  3. #include "W25Q64_Ins.h"   
  4. void MyW25Q64_Init(void)
  5. {
  6.         MySPI_Init();
  7.        
  8. }
  9. void MyW25Q64_GetID(uint8_t *MID,uint16_t *DID)//获取id
  10. {
  11.         MySPI_Start();
  12.         MySPI_BitSend(W25Q64_JEDEC_ID);//命令码参考W25Q64_Ins头文件,发送命令码
  13.         *MID = MySPI_BitSend(W25Q64_DUMMY_BYTE);
  14.         *DID = MySPI_BitSend(W25Q64_DUMMY_BYTE);
  15.         *DID <<= 8;
  16.         *DID |= MySPI_BitSend(W25Q64_DUMMY_BYTE);//关键点,高八位低八位的处理方法
  17.        
  18.         MySPI_Stop();
  19. }
  20. //该ID为两组数据,其中前8位为厂家ID,后16位为设备ID,注意这里对16位数据的处理方式,通过该语句*DID <<= 8;将数据置为高8位
  21. //然后通过该语句*DID |= MySPI_BitSend(W25Q64_DUMMY_BYTE);将低8位存入指针,注意这里是|=
  22. void MyW25Q64_WriteEnable(void)//写入使能
  23. {
  24.         MySPI_Start();
  25.         MySPI_BitSend(W25Q64_WRITE_ENABLE);
  26.         MySPI_Stop();
  27. }
  28. void W25Q64_WaitBusy(void)//等待忙
  29. {
  30.         uint32_t Timeout = 10000;//防止卡死
  31.         MySPI_Start();
  32.         MySPI_BitSend(W25Q64_READ_STATUS_REGISTER_1);//发送命令代码
  33.         while((MySPI_BitSend(W25Q64_DUMMY_BYTE)& 0x01) == 0x01)//随意发送数据,获取返回值并取出最后一位,也就是Busy位检查是否为1,1表示忙,循环等待,直到忙结束,跳出循环
  34.         {
  35.                 Timeout --;
  36.                 if(Timeout==0)
  37.                 {
  38.                         break;
  39.                 }
  40.         }
  41.         MySPI_Stop();
  42. }
  43. void W25Q64_PageProgram(uint32_t Adress,uint8_t *DataArray,uint16_t Count)//写入操作
  44. {
  45.         uint16_t i;
  46.     MyW25Q64_WriteEnable();//写入使能
  47.         MySPI_Start();
  48.        
  49.         MySPI_BitSend(W25Q64_PAGE_PROGRAM);
  50.         MySPI_BitSend(Adress<<16);
  51.         MySPI_BitSend(Adress<<8);
  52.         MySPI_BitSend(Adress);//将24位地址三次发送
  53.         for(i=0;i<Count;i++)
  54.         {
  55.                 MySPI_BitSend(DataArray[i]);//发送数据
  56.         }
  57.         MySPI_Stop();
  58.         W25Q64_WaitBusy();//等待忙碌结束
  59. }
  60. void W25Q64_SectorErase(uint32_t Adress)//擦除
  61. {
  62.         W25Q64_WaitBusy();
  63.         MySPI_Start();
  64.         MySPI_BitSend(W25Q64_SECTOR_ERASE_4KB);
  65.         MySPI_BitSend(Adress<<16);
  66.         MySPI_BitSend(Adress<<8);
  67.         MySPI_BitSend(Adress);
  68.        
  69.         MySPI_Stop();
  70.         W25Q64_WaitBusy();
  71.        
  72. }
  73. void W25Q64_ReadDate(uint32_t Adress,uint8_t *DataArray ,uint32_t Count)
  74. {
  75.         uint32_t i;
  76.         MySPI_Start();
  77.         MySPI_BitSend(W25Q64_READ_DATA);
  78.         MySPI_BitSend(Adress<<16);
  79.         MySPI_BitSend(Adress<<8);
  80.         MySPI_BitSend(Adress);
  81.         for(i=0;i<Count;i++)
  82.         {
  83.                 DataArray[i] = MySPI_BitSend(W25Q64_DUMMY_BYTE);//数据接收
  84.         }
  85.         MySPI_Stop();
  86.         W25Q64_WaitBusy();
  87.        
  88. }
复制代码
为了方便程序的读写,对W25Q64的指令做宏定义,增长程序的可读性
2.2W25Q64头文件

  1. #ifndef __W25Q64_INS_H_
  2. #define __W25Q64_INS_H_
  3. #define W25Q64_WRITE_ENABLE                                                        0x06
  4. #define W25Q64_WRITE_DISABLE                                                0x04
  5. #define W25Q64_READ_STATUS_REGISTER_1                                0x05
  6. #define W25Q64_READ_STATUS_REGISTER_2                                0x35
  7. #define W25Q64_WRITE_STATUS_REGISTER                                0x01
  8. #define W25Q64_PAGE_PROGRAM                                                        0x02
  9. #define W25Q64_QUAD_PAGE_PROGRAM                                        0x32
  10. #define W25Q64_BLOCK_ERASE_64KB                                                0xD8
  11. #define W25Q64_BLOCK_ERASE_32KB                                                0x52
  12. #define W25Q64_SECTOR_ERASE_4KB                                                0x20
  13. #define W25Q64_CHIP_ERASE                                                        0xC7
  14. #define W25Q64_ERASE_SUSPEND                                                0x75
  15. #define W25Q64_ERASE_RESUME                                                        0x7A
  16. #define W25Q64_POWER_DOWN                                                        0xB9
  17. #define W25Q64_HIGH_PERFORMANCE_MODE                                0xA3
  18. #define W25Q64_CONTINUOUS_READ_MODE_RESET                        0xFF
  19. #define W25Q64_RELEASE_POWER_DOWN_HPM_DEVICE_ID                0xAB
  20. #define W25Q64_MANUFACTURER_DEVICE_ID                                0x90
  21. #define W25Q64_READ_UNIQUE_ID                                                0x4B
  22. #define W25Q64_JEDEC_ID                                                                0x9F
  23. #define W25Q64_READ_DATA                                                        0x03
  24. #define W25Q64_FAST_READ                                                        0x0B
  25. #define W25Q64_FAST_READ_DUAL_OUTPUT                                0x3B
  26. #define W25Q64_FAST_READ_DUAL_IO                                        0xBB
  27. #define W25Q64_FAST_READ_QUAD_OUTPUT                                0x6B
  28. #define W25Q64_FAST_READ_QUAD_IO                                        0xEB
  29. #define W25Q64_OCTAL_WORD_READ_QUAD_IO                                0xE3
  30. #define W25Q64_DUMMY_BYTE                                                        0xFF
  31. #endif
复制代码
3.main函数实验

  1. #include "stm32f10x.h"                  // Device header
  2. #include "Delay.h"
  3. #include "OLED.h"
  4. #include "MyW25Q64.h"
  5. uint8_t DataArray[4] = {0x01,0x02,0x03,0x04};//写入数据注意不要超过256个,超出新数据会覆盖地址开头数据
  6. uint8_t ArrayRead[4];//读数据没有个数限制
  7. uint8_t MID;
  8. uint16_t DID;
  9. int main(void)
  10. {
  11.         OLED_Init();
  12.         MyW25Q64_Init();
  13.         MyW25Q64_GetID(&MID,&DID);
  14.         OLED_ShowString(1, 1, "MID:   DID:");
  15.         OLED_ShowString(2, 1, "W:");
  16.         OLED_ShowString(3, 1, "R:");
  17.        
  18.         OLED_ShowHexNum(1, 5, MID, 2);
  19.         OLED_ShowHexNum(1, 12, DID, 4);
  20.        
  21.         W25Q64_SectorErase( 0x00000);
  22.         W25Q64_PageProgram(0x00000,DataArray,4);//数据写入地址0x00000处,内容为数组DataArray的数据
  23.        
  24.         W25Q64_ReadDate(0x00000,ArrayRead,4);//读取地址0x00000处数据
  25.         OLED_ShowHexNum(2, 3, DataArray[0], 2);
  26.         OLED_ShowHexNum(2, 6, DataArray[1], 2);
  27.         OLED_ShowHexNum(2, 9, DataArray[2], 2);
  28.         OLED_ShowHexNum(2, 12, DataArray[3], 2);
  29.        
  30.         OLED_ShowHexNum(3, 3, ArrayRead[0], 2);
  31.         OLED_ShowHexNum(3, 6, ArrayRead[1], 2);
  32.         OLED_ShowHexNum(3, 9, ArrayRead[2], 2);
  33.         OLED_ShowHexNum(3, 12, ArrayRead[3], 2);
  34.         while (1)
  35.         {
  36.                
  37.                
  38.                
  39.         }
  40. }
复制代码
4.功能实现



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4