SPI2外设驱动-W25Q64 SPI接口初始化

前言

(1)本系列是基于STM32的项目笔记,内容涵盖了STM32各种外设的使用,由浅入深。

(2)小编使用的单片机是STM32F105RCT6,项目笔记基于小编的实际项目,但是博客中的内容适用于各种单片机开发的同学学习和使用。

学习目标

  1. W25Q64硬件设计。
  2. 学习SPI通讯协议。
  3. 完成25Q64芯片的SPI驱动程序编写。

硬件原理图

从上图可以看出 25Q64连接的是单片机的SPI2接口,通过SPI2来通讯的。

SPI通讯原理简单介绍(理解)

典型连线图

简单原理分析

SCK:决定SPI的通信速率,即 数据传输速率。

数据:1高电平 0 低电平。

SPI的四种通讯模式

https://mp.weixin.qq.com/s/ytAad2jdKczzdhD3b92apA

可以看一下上面的资料。

首先我们要了解两个特殊寄存器 分别是 CPOL (Clock POlarity)和 CPHA (Clock PHAse)。

CPOL:配置SPI总线的极性

CPHA:配置SPI总线的相位

SPI总线极性的概念: 空闲的时候时钟信号是高电平还是低电平

CPOL = 1; SCK 空闲是高电平

CPOL = 0; SCK 空闲是低电平

SPI总线的相位的概念

一个时钟周期有2个跳变沿,相位决定从那个跳变开始采集数据

CPHA = 0; 表示从第一个跳变 开始采集

CPHA = 1; 表示从第二个跳变 开始采集

SPI四种模式

模式0: CPOL = 0; CPHA = 0;

模式1:CPOL = 0; CPHA = 1;

模式2:CPOL = 1; CPHA = 0;

模式3:CPOL = 1; CPHA = 1;

数据传输方向

高位在前:MSB

低位在前: LSB

SPI的单线 和双线 模式

单线:一般用于OLED屏幕单向通讯

双向:一般用于芯片之间的双向通讯

特别说明: 一般情况下,我们不用刻意去学习四种模式的具体细节,一般芯片资料里面都会告诉你芯片支持的模式。

25Q64 SPI2的初始化操作

hal_flash.c代码

#include "stm32F10x.h"
#include "hal_flash.h"void hal_spi2Init(void)
{SPI_InitTypeDef  SPI_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;/* Enable SPI2 and GPIOA clocks */RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);/* Configure SPI2 pins: NSS, SCK, MISO and MOSI */GPIO_InitStructure.GPIO_Pin = SPI2_SCK_PIN | SPI2_MISO_PIN | SPI2_MOSI_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(SPI2_SCK_PORT, &GPIO_InitStructure);//SPI2 NSS GPIO_InitStructure.GPIO_Pin = SPI2_NSS_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(SPI2_NSS_PORT, &GPIO_InitStructure);GPIO_SetBits(SPI2_NSS_PORT,SPI2_NSS_PIN);/* SPI2 configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI1设置为两线全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;	                     //设置SPI1为主模式SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                  //SPI发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;	 		                   //串行时钟在不操作时,时钟为高电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;		                   //第二个时钟沿开始采样数据SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;			                     //NSS信号由软件(使用SSI位)管理SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;				         //数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;						               //CRC值计算的多项式SPI_Init(SPI2, &SPI_InitStructure);/* Enable SPI2  */SPI_Cmd(SPI2, ENABLE); 											  //使能SPI2外设hal_spi2CSDrive(1);//空闲时将片选信号拉高,初始化为空闲状态}  void hal_spi2CSDrive(unsigned char sta)
{if(sta)GPIO_SetBits(SPI2_NSS_PORT,SPI2_NSS_PIN);		elseGPIO_ResetBits(SPI2_NSS_PORT,SPI2_NSS_PIN);
}//SPIx 读写一个字节
//返回值:读取到的字节
unsigned char  hal_spi2ReadWriteByte(unsigned char  TxData)
{		unsigned char retry=0;				 while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE)==RESET)//等待发送区空	{retry++;if(retry>200)return 0;}	SPI_I2S_SendData(SPI2,TxData);	retry=0;while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE)==RESET)//等待发送区空	{retry++;if(retry>200)return 0;}	  						    return SPI_I2S_ReceiveData(SPI2);//SPI2->DR;          //返回收到的数据						    
}

hal_flash.h代码

#ifndef _HAL_FLASH_H
#define _HAL_FLASH_H#define SPI2_SCK_PORT       GPIOB
#define SPI2_SCK_PIN        GPIO_Pin_13#define SPI2_MOSI_PORT       GPIOB
#define SPI2_MOSI_PIN        GPIO_Pin_15#define SPI2_MISO_PORT       GPIOB
#define SPI2_MISO_PIN        GPIO_Pin_14#define SPI2_NSS_PORT       GPIOB
#define SPI2_NSS_PIN        GPIO_Pin_12void hal_spi2Init(void);
void hal_spi2CSDrive(unsigned char sta);
unsigned char  hal_spi2ReadWriteByte(unsigned char  TxData);#endif

SPI2接口初始化流程(拆解代码分析)

● 定义SPI通讯的端口

● 打开相关时钟

● 初始化SPI2相关的GPIO口

● 初始化SPI2相关参数

● 片选CS初始化 拉高

定义SPI通讯的端口
#define SPI2_SCK_PORT       GPIOB
#define SPI2_SCK_PIN        GPIO_Pin_13#define SPI2_MOSI_PORT       GPIOB
#define SPI2_MOSI_PIN        GPIO_Pin_15#define SPI2_MISO_PORT       GPIOB
#define SPI2_MISO_PIN        GPIO_Pin_14#define SPI2_NSS_PORT       GPIOB//其实就是CS,片选引脚
#define SPI2_NSS_PIN        GPIO_Pin_12
打开相关时钟
/* Enable SPI2 and GPIOA clocks */RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
初始化SPI2相关的GPIO口
/* Configure SPI2 pins: NSS, SCK, MISO and MOSI */GPIO_InitStructure.GPIO_Pin = SPI2_SCK_PIN | SPI2_MISO_PIN | SPI2_MOSI_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(SPI2_SCK_PORT, &GPIO_InitStructure);//SPI2 NSS   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_12);
初始化SPI2相关参数
/* SPI2 configuration */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI2设置为两线全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master;	   //设置SPI2为主模式SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;   //SP2发送接收8位帧结构SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;	//串行时钟在不操作时,时钟为高电平SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//第二个时钟沿开始采样数据SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由软件(使用SSI位)管理SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7;		//CRC值计算的多项式SPI_Init(SPI2, &SPI_InitStructure);/* Enable SPI2  */SPI_Cmd(SPI2, ENABLE); 					//使能SPI2外设
25Q64片选操作,拉高
void hal_spi2CSDrive(unsigned char sta)
{if(sta)GPIO_SetBits(GPIOB,GPIO_Pin_12);		elseGPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
SPI数据读写函数
SPI读写数据操作原理

SPI 读写操作图示分析

代码分析
//SPIx 读写一个字节
//返回值:读取到的字节
unsigned char  hal_spi2ReadWriteByte(unsigned char  TxData)
{		unsigned char retry=0;				 while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE)==RESET)//等待发送区空	{retry++;if(retry>200)return 0;}	SPI_I2S_SendData(SPI2,TxData);	retry=0;while(SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE)==RESET)//	
{retry++;if(retry>200)return 0;}	  						    return SPI_I2S_ReceiveData(SPI2);//SPI2->DR;          //返回收到的数据			    
}

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

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

相关文章

【LeetCode-中等题】73. 矩阵置零

题目 题解一&#xff1a;使用标记数组 public void setZeroes(int[][] matrix) {int m matrix.length;int n matrix[0].length;boolean[] row new boolean[m];boolean[] col new boolean[n];for(int i0; i< m;i){for(int j 0;j<n;j){if (matrix[i][j] 0) row[i]col…

【C++精华铺】9.STL string

目录 1. string类的优势 2. string类的常用接口 2.1 常用构造 1. 空串构造&#xff1a;string(); 2. C串构造&#xff1a;string(const char* s); 3. 拷贝构造&#xff1a;string(const string& str); 4. 字符填充构造&#xff1a;string(size_t n, char c); 5. 迭代…

数据结构之哈希

哈希 1. 哈希概念2. 哈希冲突3. 哈希冲突解决3.1 哈希表的闭散列3.2 哈希表的开散列 2. 哈希的应用2.1 位图2.2 布隆过滤器 哈希&#xff08;Hash&#xff09;是一种将任意长度的二进制明文映射为较短的二进制串的算法。它是一种重要的存储方式&#xff0c;也是一种常见的检索方…

【Linux网络】TCP UDP socket HTTP webSocket之间的区别

目录 一、OSI & TCP/IP模型 二、几者之间的关系 三、HTTP 四、Socket 五、WebSocket 5.1、WebSocket 优点 一、OSI & TCP/IP模型 首先我们要了解OSI七层模型&#xff0c;和预支对应的TCP/IP 四层的模型。 用下面的图可以看出&#xff0c;TCP UDP 工作在传输层&…

Android Studio开发之路 (五)导入OpenCV以及报错解决

一、步骤 官网下载opencv包&#xff08;我下的是4.7.0&#xff09;并解压&#xff0c;openvc官网 先创建一个空项目&#xff0c;简单跑一下能正常输出helloworld 点击file->new->Import Module选择解压之后的opencv-android-sdk文件夹中的SDk文件夹&#xff0c; modu…

Visual Studio 2022的MFC框架——theApp全局对象

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天我们来重新审视一下Visual Studio 2022下开发工具的MFC框架知识。 MFC中的WinMain函数是如何与MFC程序中的各个类组织在一起的呢&#xff1f;MFC程序中的类是如何与WinMain函数关联起来的呢&#xff1f…

【LeetCode 】数组简介

集合列表和数组 本文中介绍的概念为适用于所有编程语言的抽象理论&#xff0c;具体实现会由编程语言的不同而稍有差别。 具体介绍数组之前&#xff0c;我们先来了解一下集合、列表和数组的概念之间的差别。 集合 集合一般被定义为&#xff1a;由一个或多个确定的元素所构成的…

Vue中使用element-plus中的el-dialog定义弹窗-内部样式修改-v-model实现-demo

效果图 实现代码 <template><el-dialog class"no-code-dialog" v-model"isShow" title"没有收到验证码&#xff1f;"><div class"nocode-body"><div class"tips">请尝试一下操作</div><d…

把Android手机变成电脑摄像头

一、使用 DroidCam 使用 DroidCam&#xff0c;你可以将手机作为电脑摄像头和麦克风。一则省钱&#xff0c;二则可以在紧急情况下使用&#xff0c;比如要在电脑端参加一个紧急会议&#xff0c;但电脑却没有摄像头和麦克风。 DroidCam 的安卓端分为免费的 DroidCam 版和收费的 …

《软件开发的201个原则》阅读笔记 120-161条

目录 使用有效的测试完成度标准 原则122 达成有效的测试覆盖 原则123 不要在单元测试之前集成 原则 124 测量你的软件 原则125 分析错误的原因 对错不对人 原则127 好的管理比好的技术更重要 使用恰当的方法 原则 129 不要相信你读到的一切 原则130 理解客户的优先级 原…

用QT实现MVP模式

近些天用qt 作项目,遇到参数界面.偷闲写个mvp模式示例. mvp模式重要的有两点 1 低耦合: 界面与后端数据类,不直接引用,可方便替换. 2 形成界面驱动-界面更新的闭环.:通过函数指针类技术,让数据自动回流. MVP (Model-View-Presenter) 视图&#xff08;View&#xff09;: 接…

git Update failed cannot lock ref

报错详情 解决方案 百度了很多方案&#xff0c;过滤出了有效方案 去该项目下的.git文件里找到报错文件&#xff0c;本例中即为&#xff1a;.git/refs/tags/pre-RELEASE-PRE-20230817-03 删除该文件&#xff0c;重新pull&#xff0c;pull成功问题解决

openapi中job提交

openapi中job提交 简介创建job查看job查看job 的描述查看job 的日志 简介 这里使用微软OpenPAI, 在nvidia的GPU设备上进行job测试。 创建job protocolVersion: 2 name: lenet_gpu_pytorch112_jiaxiaolei_20230825_1013 type: job jobRetryCount: 0 prerequisites:- type: doc…

大红喜庆版UI猜灯谜小程序源码/猜字谜微信小程序源码

今天给大家带来一款UI比较喜庆的猜灯谜小程序&#xff0c;大家看演示图的时候当然也是可以看得到那界面是多么的喜庆&#xff0c;而且新的一年也很快就来了,所以种种的界面可能都比较往喜庆方面去变吧。 这款小程序搭建是免服务器和域名的&#xff0c;只需要使用微信开发者工具…

Spring Cloud Nacos详解

目录 1、Spring Cloud Nacos详细介绍2、Spring Cloud Nacos具体案列 Spring Cloud Nacos 是一个由阿里巴巴集团开发的开源分布式系统服务发现、配置管理和服务管理的平台。Nacos 支持多种服务发现方式&#xff0c;包括 DNS 方式、HTTP 和 RPC 方式&#xff0c;同时提供了灵活的…

vue-element-admin最新版4.4实现多个url路由匹配到一个路径时,左侧菜单保持高亮状态

文章目录 环境&#xff1a;需求&#xff1a;原因分析&#xff1a;如何解决&#xff1a; 环境&#xff1a; vue-admin-template-4.4版本&#xff08;vue2&#xff09; 需求&#xff1a; 当我访问申请开户时&#xff0c;也希望支付菜单能保持高亮状态。 原因分析&#xff1a; …

【UniApp开发小程序】私聊功能uniapp界面实现 (买家、卖家 沟通商品信息)【后端基于若依管理系统开发】

文章目录 效果显示WebSocket连接使用全局变量WebSocket连接细节 最近和自己聊天的用户信息界面效果界面代码最近的聊天内容太长日期时间显示未读消息数量显示 私聊界面界面展示代码实现英文长串不换行问题聊天区域自动滑动到底部键盘呼出&#xff0c;聊天区域收缩&#xff0c;聊…

lnmp架构-nginx

1 Nginx服务的部署 前面高可用负载均衡做流量均摊只是用到 iso 前四层 下面针对某个请求 在七层模型 上做 apache也是可以的 但是 apache一般吞吐性能没有nigix 强 nigix可以做负载均衡器 也可以做常规的web服务器 作为网站的发布服务器 官网下载好之后 直接拖到软件中 源…

Qt 自定义提示框 右下角冒泡

网页右下角上经常会出现一些提示性的信息&#xff0c;B/S有的东西&#xff0c;C/S当然也可以有&#xff0c;就像QQ的消息提示一样&#xff01; 实现一个类似的东西并不困难&#xff0c;只要想明白原理实现起来就很简单了&#xff01; 实现原理&#xff1a; &#xff08;1&#…

yo!这里是Linux权限入门理解

目录 前言 权限概念 权限管理 分类 1.用户 2.文件&&目录 表示 设置 1.chmod指令 2.chown指令 3.chgrp指令 4.umask指令 粘滞位 后记 前言 对于Linux基本指令&#xff0c;基本上就是操作文件或者目录&#xff0c;但是&#xff0c;是谁可以操作文件或目录&…