SPI软件模拟读写W25Q64

ops/2024/12/22 19:37:07/

1.SPI初始化

#include "stm32f10x.h"                  // Device headervoid MySPI_W_SS(uint8_t BitValue)//片选
{GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
}void MySPI_W_SCK(uint8_t BitValue)//时钟线
{GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)BitValue);
}void MySPI_W_MOSI(uint8_t BitValue)//MOSI
{GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)BitValue);
}uint8_t MySPI_R_MISO(void)//MISO
{return(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6));
}void MySPI_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 |GPIO_Pin_7;//输出脚,配置成推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//输入脚,配置成上拉输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);MySPI_W_SS(1);//片选默认高电平MySPI_W_SCK(0);//时钟线默认为0
}void MySPI_Start(void)
{MySPI_W_SS(0);//片选低电平
}void MySPI_Stop(void)
{MySPI_W_SS(1);//片选高电平
}uint8_t MySPI_BitSend(uint8_t Data)//交换数据
{uint8_t i,BitReivce = 0x00;//接收数据默认为0x00for(i=0;i<8;i++){MySPI_W_MOSI(Data & (0x80>>i));//此时模式为模式0,因为低电平将数据放入SCk,高电平读取数据MySPI_W_SCK(1);if(MySPI_R_MISO()== 1){BitReivce |= (0x80>>i);}//该语句首先判断接收到的位是否为1,通过|=来提出该位的1,否则为零MySPI_W_SCK(0);}return BitReivce;
}

完成SPI基本时序单元,包括起始条件,终止条件,交换一个字节。为了方便放标操作,封装了一些函数。

2.1基于SPI的W25Q64初始化

根据W25Q64指令表实现相关指令

#include "stm32f10x.h"                  // Device header
#include "MySPI.h"   
#include "W25Q64_Ins.h"   void MyW25Q64_Init(void)
{MySPI_Init();}void MyW25Q64_GetID(uint8_t *MID,uint16_t *DID)//获取id
{MySPI_Start();MySPI_BitSend(W25Q64_JEDEC_ID);//命令码参考W25Q64_Ins头文件,发送命令码*MID = MySPI_BitSend(W25Q64_DUMMY_BYTE);*DID = MySPI_BitSend(W25Q64_DUMMY_BYTE);*DID <<= 8;*DID |= MySPI_BitSend(W25Q64_DUMMY_BYTE);//关键点,高八位低八位的处理方法MySPI_Stop();
}
//该ID为两组数据,其中前8位为厂家ID,后16位为设备ID,注意这里对16位数据的处理方式,通过该语句*DID <<= 8;将数据置为高8位
//然后通过该语句*DID |= MySPI_BitSend(W25Q64_DUMMY_BYTE);将低8位存入指针,注意这里是|=void MyW25Q64_WriteEnable(void)//写入使能
{MySPI_Start();MySPI_BitSend(W25Q64_WRITE_ENABLE);MySPI_Stop();
}void W25Q64_WaitBusy(void)//等待忙
{uint32_t Timeout = 10000;//防止卡死MySPI_Start();MySPI_BitSend(W25Q64_READ_STATUS_REGISTER_1);//发送命令代码while((MySPI_BitSend(W25Q64_DUMMY_BYTE)& 0x01) == 0x01)//随意发送数据,获取返回值并取出最后一位,也就是Busy位检查是否为1,1表示忙,循环等待,直到忙结束,跳出循环{Timeout --;if(Timeout==0){break;}}MySPI_Stop();
}void W25Q64_PageProgram(uint32_t Adress,uint8_t *DataArray,uint16_t Count)//写入操作
{uint16_t i;MyW25Q64_WriteEnable();//写入使能MySPI_Start();MySPI_BitSend(W25Q64_PAGE_PROGRAM);MySPI_BitSend(Adress<<16);MySPI_BitSend(Adress<<8);MySPI_BitSend(Adress);//将24位地址三次发送for(i=0;i<Count;i++){MySPI_BitSend(DataArray[i]);//发送数据}MySPI_Stop();W25Q64_WaitBusy();//等待忙碌结束
}void W25Q64_SectorErase(uint32_t Adress)//擦除
{W25Q64_WaitBusy();MySPI_Start();MySPI_BitSend(W25Q64_SECTOR_ERASE_4KB);MySPI_BitSend(Adress<<16);MySPI_BitSend(Adress<<8);MySPI_BitSend(Adress);MySPI_Stop();W25Q64_WaitBusy();}void W25Q64_ReadDate(uint32_t Adress,uint8_t *DataArray ,uint32_t Count)
{uint32_t i;MySPI_Start();MySPI_BitSend(W25Q64_READ_DATA);MySPI_BitSend(Adress<<16);MySPI_BitSend(Adress<<8);MySPI_BitSend(Adress);for(i=0;i<Count;i++){DataArray[i] = MySPI_BitSend(W25Q64_DUMMY_BYTE);//数据接收}MySPI_Stop();W25Q64_WaitBusy();}

为了方便程序的读写,对W25Q64的指令做宏定义,增加程序的可读性

2.2W25Q64头文件

#ifndef __W25Q64_INS_H_
#define __W25Q64_INS_H_#define W25Q64_WRITE_ENABLE							0x06
#define W25Q64_WRITE_DISABLE						0x04
#define W25Q64_READ_STATUS_REGISTER_1				0x05
#define W25Q64_READ_STATUS_REGISTER_2				0x35
#define W25Q64_WRITE_STATUS_REGISTER				0x01
#define W25Q64_PAGE_PROGRAM							0x02
#define W25Q64_QUAD_PAGE_PROGRAM					0x32
#define W25Q64_BLOCK_ERASE_64KB						0xD8
#define W25Q64_BLOCK_ERASE_32KB						0x52
#define W25Q64_SECTOR_ERASE_4KB						0x20
#define W25Q64_CHIP_ERASE							0xC7
#define W25Q64_ERASE_SUSPEND						0x75
#define W25Q64_ERASE_RESUME							0x7A
#define W25Q64_POWER_DOWN							0xB9
#define W25Q64_HIGH_PERFORMANCE_MODE				0xA3
#define W25Q64_CONTINUOUS_READ_MODE_RESET			0xFF
#define W25Q64_RELEASE_POWER_DOWN_HPM_DEVICE_ID		0xAB
#define W25Q64_MANUFACTURER_DEVICE_ID				0x90
#define W25Q64_READ_UNIQUE_ID						0x4B
#define W25Q64_JEDEC_ID								0x9F
#define W25Q64_READ_DATA							0x03
#define W25Q64_FAST_READ							0x0B
#define W25Q64_FAST_READ_DUAL_OUTPUT				0x3B
#define W25Q64_FAST_READ_DUAL_IO					0xBB
#define W25Q64_FAST_READ_QUAD_OUTPUT				0x6B
#define W25Q64_FAST_READ_QUAD_IO					0xEB
#define W25Q64_OCTAL_WORD_READ_QUAD_IO				0xE3#define W25Q64_DUMMY_BYTE							0xFF#endif

3.main函数实验

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyW25Q64.h"uint8_t DataArray[4] = {0x01,0x02,0x03,0x04};//写入数据注意不要超过256个,超出新数据会覆盖地址开头数据
uint8_t ArrayRead[4];//读数据没有个数限制
uint8_t MID;
uint16_t DID;
int main(void)
{OLED_Init();MyW25Q64_Init();MyW25Q64_GetID(&MID,&DID);OLED_ShowString(1, 1, "MID:   DID:");OLED_ShowString(2, 1, "W:");OLED_ShowString(3, 1, "R:");OLED_ShowHexNum(1, 5, MID, 2);OLED_ShowHexNum(1, 12, DID, 4);W25Q64_SectorErase( 0x00000);W25Q64_PageProgram(0x00000,DataArray,4);//数据写入地址0x00000处,内容为数组DataArray的数据W25Q64_ReadDate(0x00000,ArrayRead,4);//读取地址0x00000处数据OLED_ShowHexNum(2, 3, DataArray[0], 2);OLED_ShowHexNum(2, 6, DataArray[1], 2);OLED_ShowHexNum(2, 9, DataArray[2], 2);OLED_ShowHexNum(2, 12, DataArray[3], 2);OLED_ShowHexNum(3, 3, ArrayRead[0], 2);OLED_ShowHexNum(3, 6, ArrayRead[1], 2);OLED_ShowHexNum(3, 9, ArrayRead[2], 2);OLED_ShowHexNum(3, 12, ArrayRead[3], 2);while (1){}
}

4.功能实现


http://www.ppmy.cn/ops/114277.html

相关文章

小阿轩yx-通过state模块定义主机状态

小阿轩yx-通过state模块定义主机状态 前言 前面学习了远程执行模块&#xff0c;这些模块的执行类似语段 shell 脚本&#xff0c;每次执行都会触发一次相同的功能&#xff0c;在大量的 minion 上运行远程命令当然是重要的&#xff0c;但是对于 minion 的环境控制&#xff0c;使…

云服务器docker中Hbase整合java-api需要放行的接口

在使用 Docker 部署 HBase 并通过 Java API 进行访问时&#xff0c;确保通信畅通非常重要。如果 HBase 部署在云服务器或虚拟机中&#xff0c;你需要在云服务器的安全组中放行一些关键端口&#xff0c;确保外部或本地的 Java 应用可以正确访问 Docker 容器中的 HBase 服务。 1…

网络安全-webshell绕过,hash碰撞,webshell绕过原理

目录 一、题目 1.1 1.2 1.3 1.4 1.5 二、绕过动态检测引擎的一次尝试 三、一个比赛中的webshell 四、webshell绕过的原理以及哈希碰撞 五、JSP解释流程导致的绕过&#xff08;QT比赛&#xff09; 5.1环境 5.2例子 一、题目 这里我们通过几道题目来给大家讲解 1.…

【数据结构】排序算法---计数排序

文章目录 1. 定义2. 算法步骤3. 动图演示4. 性质5. 算法分析6. 代码实现C语言PythonJavaGo 结语 1. 定义 计数排序又称为鸽巢原理&#xff0c;是对哈希直接定址法的变形应用。计数排序不是基于比较的排序算法&#xff0c;其核心在于将输入的数据值转化为键存储在额外开辟的数组…

某集群管理系统存在任意文件读取漏洞

你为什么要拼命努力&#xff1f;父母的白发&#xff0c;想去的地方很远&#xff0c;想要的东西很贵&#xff0c;喜欢的人很优秀&#xff0c;周围人的嘲笑&#xff0c;以及&#xff0c;天生傲骨。 漏洞描述 利用漏洞&#xff0c;攻击者可以读取 Windows 或 Linux 服务器上的任…

推荐一款PS VR2电脑PC适配器 / 转接板方案

一、引言 随着虚拟现实技术的不断发展&#xff0c;PS VR2 为用户带来了沉浸式的游戏和娱乐体验。然而&#xff0c;为了让 PS VR2 能够与电脑连接&#xff0c;充分发挥其性能并拓展使用场景&#xff0c;需要开发一款电脑适配器 / 转接板。本技术文档方案旨在详细阐述该适配器 / …

汽车应用生态系统的飞跃

在过去的几年里&#xff0c;汽车系统经历了前所未有的变革&#xff0c;驾驶员和乘客对于车内体验的期待已远远超越了传统的驾驶范畴。随着技术的不断进步&#xff0c;基于Android Automotive OS&#xff08;AAOS&#xff09;和Google Automotive Services&#xff08;GAS&#…

Android 用线程池实现一个简单的任务队列(Kotlin)

关于线程池,Kotlin和java的使用方式一样 在Android中,很多人喜欢用Handler的postDelayed() 去实现延时任务. 要使用postDelayed(),去实现延时任务队列,就不可避免要使用递归. 但是这样做,代码的简洁性,和书写的简易,就远不如使用线程池. 使用线程池的简单程度: private val…