STM32 进阶SPI案例1:软件模拟SPI读写FLASH

需求描述

基于寄存器操作,使用软件模拟SPI协议,完成读写FLASH。

硬件电路设计

寄存器代码书写

main.c

#include "usart1.h"
#include "string.h"
#include <stdio.h>
#include "m24c02.h"
#include "soft_spi.h"
#include "W25Q32.h"
​
int main(void){Usart1_Init();W25Q32_Init();uint8_t buffer[1001] = {0};W25Q32_EraseSetor(0x00,0x00);W25Q32_PageWrite(0x00,0x00,0x00,0x00,"abcde",5);W25Q32_ReadData(0x00,0x00,0x00,0x00,buffer,1000);printf("%s\n",buffer);while (1){}}

soft_spi.h

#ifndef __SOFT_SPI_H__
#define __SOFT_SPI_H__
​
#include "stm32f10x.h"
​
#define SCK_HIGH (GPIOA->ODR |= GPIO_ODR_ODR5)
#define SCK_LOW (GPIOA->ODR &= ~GPIO_ODR_ODR5)
​
#define MOSI_HIGH (GPIOA->ODR |= GPIO_ODR_ODR7)
#define MOSI_LOW (GPIOA->ODR &= ~GPIO_ODR_ODR7)
​
#define CS_HIGH (GPIOA->ODR |= GPIO_ODR_ODR13)
#define CS_LOW (GPIOA->ODR &= ~GPIO_ODR_ODR13)
​
#define MISO_READ (GPIOA->IDR & GPIO_IDR_IDR6)
​
void SPI_Init(void);
​
void SPI_Start(void);
​
void SPI_Stop(void);
​
uint8_t SPI_SwapByte(uint8_t byte);
​
#endif /* __SOFT_SPI_H__ */
​

soft_spi.c

#include "soft_spi.h"
​
void SPI_Init(void)
{// 1. GPIOA// 1.1 先放时钟RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
​// new * 模式0SCK_LOW;
​// 1.2 PA5 时钟 通用推挽GPIOA->CRL &= ~GPIO_CRL_CNF5;GPIOA->CRL |= GPIO_CRL_MODE5;// 1.3 PA6 输入信号 浮空输入GPIOA->CRL &= ~GPIO_CRL_CNF6_1;GPIOA->CRL |= GPIO_CRL_CNF6_0;GPIOA->CRL &= ~GPIO_CRL_MODE6;// 1.4 PA7 数据输出 通用推挽GPIOA->CRL &= ~GPIO_CRL_CNF7;GPIOA->CRL |= GPIO_CRL_MODE7;
​// 2. GPIOC// 2.1 放GPIOC的时钟RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;// new * 片选拉高 表示 不通讯CS_HIGH;
​// 2.2. PC13 片选使能信号 通用推挽GPIOC->CRH &= ~GPIO_CRH_CNF13;GPIOC->CRH |= GPIO_CRH_MODE13;
}
​
void SPI_Start(void)
{CS_LOW;
}
​
void SPI_Stop(void)
{CS_HIGH;
}
​
// mode0 上升沿的时候读数据 下降沿的时候发数据
uint8_t SPI_SwapByte(uint8_t byte)
{
​uint8_t receive_byte = 0;for (uint8_t i = 0; i < 8; i++){// for循环里面 是不是处理的bit// 1. 上升沿之前 先把MO的数据偷偷放好if (byte & 0x80){MOSI_HIGH;}else{MOSI_LOW;}// 2. 一个bit发完之后 左移一下byte <<= 1;// 3. 拉高一下 创造一个上升沿SCK_HIGH;receive_byte <<= 1;if (MISO_READ){receive_byte |= 1;}
​// 4. 拉低一下 让时钟进入空闲 再偷着读数据SCK_LOW;// !! 此处违反了协议 因为协议要求 高电平时数据交换}
​return receive_byte;
}

W25Q32.h

#ifndef __W25Q32_H__
#define __W25Q32_H__
​
#include "soft_spi.h"
​
void W25Q32_Init(void);
​
void W25Q32_JEDECID(uint8_t * mfid,uint8_t * memType,uint8_t * cap);
​
void W25Q32_WriteEnable(void);
​
void W25Q32_WriteDisable(void);
​
uint8_t w25Q32_ReadStatus(void);
​
void W25Q32_PageWrite(uint8_t block_addr,uint8_t sector_addr,uint8_t page_addr,uint8_t page_inner_addr,uint8_t * pData,uint8_t len
);
​
​
void W25Q32_EraseSetor(uint8_t block_addr,uint8_t sector_addr
);
​
​
void W25Q32_ReadData(uint8_t block_addr,uint8_t sector_addr,uint8_t page_addr,uint8_t page_inner_addr,uint8_t * pData,uint8_t len
);
#endif /* __W25Q32_H__ */

W25Q32.c

#include "W25Q32.h"
​
#define DUMMY 0xff
​
void W25Q32_Init(void){SPI_Init();
}
​
void W25Q32_JEDECID(uint8_t * mfid,uint8_t * memType,uint8_t * cap){SPI_Start();SPI_SwapByte(0x9f);// 制造商ID* mfid = SPI_SwapByte(DUMMY);// 存储器类型* memType = SPI_SwapByte(DUMMY);// 容量* cap = SPI_SwapByte(DUMMY);SPI_Stop();
}
​
void W25Q32_WriteEnable(void){SPI_Start();SPI_SwapByte(0x06);SPI_Stop();
}
​
uint8_t w25Q32_ReadStatus(void){SPI_Start();SPI_SwapByte(0x05);uint8_t status = SPI_SwapByte (DUMMY);SPI_Stop();return status; 
}
​
void W25Q32_WriteDisable(void){SPI_Start();SPI_SwapByte(0x04);SPI_Stop();
}
​
void W25Q32_WaitBusyFinish(void){SPI_Start();SPI_SwapByte(0x05);while (1){uint8_t status = SPI_SwapByte(DUMMY);if ((status & 0x01) == 0){SPI_Stop();return;}}
}
​
void W25Q32_PageWrite(uint8_t block_addr,uint8_t sector_addr,uint8_t page_addr,uint8_t page_inner_addr,uint8_t * pData,uint8_t len
)
{//先判断忙不忙W25Q32_WaitBusyFinish();//再打开写使能W25Q32_WriteEnable();
​SPI_Start();//1.页写的指令是0x02SPI_SwapByte(0x02);//2.先发24位地址的高8位SPI_SwapByte(block_addr);//3.再发中间8位(需要将4位的段地址 和4位的页地址合并)SPI_SwapByte(sector_addr << 4 | (page_addr & 0x0f));//4.最后低8位地址,业内地址不需要合并SPI_SwapByte(page_addr);//5.有多少数据发多少数据for (uint8_t i = 0; i < len; i++){SPI_SwapByte(pData[i]);}//6. 结束通讯SPI_Stop();
}
​
void W25Q32_EraseSetor(uint8_t block_addr,uint8_t sector_addr
){W25Q32_WaitBusyFinish();W25Q32_WriteEnable();
​SPI_Start();SPI_SwapByte(0x20);SPI_SwapByte(block_addr);SPI_SwapByte(sector_addr << 4);SPI_SwapByte(0x00);SPI_Stop();
}
​
void W25Q32_ReadData(uint8_t block_addr,uint8_t sector_addr,uint8_t page_addr,uint8_t page_inner_addr,uint8_t * pData,uint8_t len
){W25Q32_WaitBusyFinish();
​SPI_Start();SPI_SwapByte(0x03);
​//2.先发24位地址的高8位SPI_SwapByte(block_addr);//3.再发中间8位(需要将4位的段地址 和4位的页地址合并)SPI_SwapByte(sector_addr << 4 | (page_addr & 0x0f));//4.最后低8位地址,业内地址不需要合并SPI_SwapByte(page_addr);
​for (uint8_t i = 0; i < len; i++){pData[i] = SPI_SwapByte(DUMMY);}SPI_Stop();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/491184.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt WORD/PDF(一)使用 QtPdfium库实现 PDF 预览

文章目录 一、简介二、下载 QtPdfium三、加载 QtPdfium 动态库四、Demo 使用 关于QT Widget 其它文章请点击这里: QT Widget 姊妹篇: Qt WORD/PDF&#xff08;一&#xff09;使用 QtPdfium库实现 PDF 操作 Qt WORD/PDF&#xff08;二&#xff09;使用 QtPdfium库实现…

【SpringCloud】OpenFeign配置时间Decode

文章目录 1.自定义反序列化器2.配置类与自定义 ObjectMapper客户端 需求&#xff1a;OpenFeign配置自定义decode&#xff0c;解析http请求返回的时间字符串 1.自定义反序列化器 Date 自定义反序列化器 import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.j…

java程序设计2(二)

自动装箱和自动拆箱&#xff1a;基本数据类型和包装类型之间可以直接相互转换的包装类通常可以区分有效数据和无效数据&#xff0c;例如&#xff1a;0和nullString类 获取字符串的方式 【企业面试】 String str1 "hello"; 这种获取字符串的方式&#xff0c;在串池…

百度地图JavaScript API核心功能指引

百度地图JavaScript API是一套由JavaScript语言编写的应用程序接口&#xff0c;它能够帮助您在网站中构建功能丰富、交互性强的地图应用&#xff0c;包含了构建地图基本功能的各种接口&#xff0c;提供了诸如本地搜索、路线规划等数据服务。百度地图JavaScript API支持HTTP和HT…

让 Win10 上网本 Debug 模式 QUDPSocket 信号槽 收发不丢包的方法总结

在前两篇文章里&#xff0c;我们探讨了不少UDP丢包的解决方案。经过几年的摸索测试&#xff0c;其实方法非常简单, 无需修改代码。 1. Windows 下设置UDP缓存 这个方法可以一劳永逸解决UDP的收发丢包问题&#xff0c;只要添加注册表项目并重启即可。即使用Qt的信号与槽&#…

【他山之石】Leading-Trim: The Future of Digital Typesetting:数字排版的未来 —— Leading-Trim

文章目录 【他山之石】Leading-Trim: The Future of Digital Typesetting&#xff1a;数字排版的未来 —— Leading-TrimHow an emerging CSS standard can fix old problems and raise the bar for web apps1. The problem with text boxes today2. How we got here: a histor…

MySQL基础大全(看这一篇足够!!!)

文章目录 前言一、初识MySQL1.1 数据库基础1.2 数据库技术构成1.2.1 数据库系统1.2.2 SQL语言1.2.3 数据库访问接口 1.3 什么是MySQL 二、数据库的基本操作2.1 数据库创建和删除2.2 数据库存储引擎2.2.1 MySQL存储引擎简介2.2.2 InnoDB存储引擎2.2.3 MyISAM存储引擎2.2.4 存储引…

uniapp/HBuilder X引入weex报错weex is not defined

出现错误&#xff1a; ‍[⁠ReferenceError⁠]‍ {message: "weex is not defined"} 在www.iconfont.cn把想要的图标放进个人项目中并且下载css文件&#xff1a; 进入HBuilder自己创建的项目中添加一个目录common&#xff0c;添加一个文件free-icon.css 把刚才下载…

Python随机抽取Excel数据并在处理后整合为一个文件

本文介绍基于Python语言&#xff0c;针对一个文件夹下大量的Excel表格文件&#xff0c;基于其中每一个文件&#xff0c;随机从其中选取一部分数据&#xff0c;并将全部文件中随机获取的数据合并为一个新的Excel表格文件的方法。 首先&#xff0c;我们来明确一下本文的具体需求。…

【数据分析】表结构数据特征、获取、使用

文章目录 表结构数据事实表及维度表表结构数据特征-1表结构数据特征-2处理缺失值-1表结构数据特征-3确定主键的方法“应用”表格结构数据、“引用”表结构数据关系型数据库管理系统商业智能系统-BIETL功能数据仓库 - DWOLAP表结构数据的横向合并表结构数据的横向合并1表结构数据…

【计算机网络】Layer4-Transport layer

目录 传输层协议How demultiplexing works in transport layer&#xff08;传输层如何进行分用&#xff09;分用&#xff08;Demultiplexing&#xff09;的定义&#xff1a;TCP/UDP段格式&#xff1a; UDPUDP的特点&#xff1a;UDP Format端口号Trivial File Transfer Protocol…

深入剖析MyBatis的架构原理

架构设计 简要画出 MyBatis 的架构图 >> ​​ Mybatis 的功能架构分为哪三层&#xff1f; API 接口层 提供给外部使用的接口 API&#xff0c;开发人员通过这些本地 API 来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。MyBatis 和数据库的…

CTF 攻防世界 Web: FlatScience write-up

题目名称-FlatScience 网址 index 目录中没有发现提示信息&#xff0c;链接会跳转到论文。 目前没有发现有用信息&#xff0c;尝试目录扫描。 目录扫描 注意到存在 robots.txt 和 login.php。 访问 robots.txt 这里表明还存在 admin.php admin.php 分析 在这里尝试一些 sql…

智能客户服务:科技赋能下的新体验

在当今这个数字化时代&#xff0c;客户服务已经不仅仅是简单的售后服务&#xff0c;它已竞争的关键要素之一。随着人工智能、大数据、云计算等技术的飞速发展&#xff0c;智能客户服务正逐步改变着传统的服务模式&#xff0c;为企业和消费者带来了前所未有的新体验。 一、智能客…

发布/部署WebApi服务器(IIS+.NET8+ASP.NETCore)

CS软件授权注册系统-发布/部署WebApi服务器(IIS.NET8ASP.NETCore) 目录 本文摘要VS2022配置发布VS2022发布WebApiIIS服务器部署WebApi 将程序文件复制到云服务器添加网站配置应用程序池配置dns域名配置端口阿里云ECS服务器配置19980端口配置https协议 (申请ssl证书)测试WebAp…

安卓 文件管理相关功能记录

文件管理细分为图片、视频、音乐、文件四类 目录 权限 静态声明权限 动态检查和声明权限方法 如何开始上述动态申请的流程 提示 图片 获取图片文件的对象列表 展示 删除 视频 获取视频文件的对象列表 获取视频file列表 按日期装载视频文件列表 展示 播放 删除…

找出1000以内的所有回文数

找出1000以内的所有回文数 方法概述检查回文数的方法伪代码C代码实现代码解析运行结果在计算机科学中,回文数是一种具有对称性质的数,即从左向右读和从右向左读都是相同的。例如,121、1331、12321都是回文数。本文将利用数据结构、C语言和算法的知识来编写一个程序,找出100…

如何在NGINX中实现基于IP的访问控制(IP黑白名单)?

大家好&#xff0c;我是锋哥。今天分享关于【如何在NGINX中实现基于IP的访问控制&#xff08;IP黑白名单&#xff09;&#xff1f;】面试题。希望对大家有帮助&#xff1b; 如何在NGINX中实现基于IP的访问控制&#xff08;IP黑白名单&#xff09;&#xff1f; 1000道 互联网大…

数据结构day3作业

一、完整功能【顺序表】的创建 【seqList.h】 #ifndef __SEQLIST_H__ #define __SEQLIST_H__#include <stdio.h> #include <string.h> #include <stdlib.h>//宏定义&#xff0c;线性表的最大容量 #define MAX 30//类型重定义&#xff0c;表示要存放数据的类…

云计算HCIP-OpenStack02

书接上回&#xff1a; 云计算HCIP-OpenStack01-CSDN博客 7.OpenStack核心服务 7.1Horizon&#xff1a;界面管理服务 Horizon提供了OpenStack中基于web界面的管理控制页面&#xff0c;用户或者是管理员都需要通过该服务进行OpenStack的访问和控制 界面管理服务需要依赖于keyston…