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.mzph.cn/news/62320.shtml

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

相关文章

carbondata优化小姐

一,carbondata高效原因 carbondata文件是hdfs的列式存储格式 查询速度是spark SQL的10倍,通过多种索引技术和多次push down优化,对TB级别数据快速响应 高效的压缩,使用轻量级和和重量级压缩组合的方式,减少60~80%的空间…

【FlowDroid】一、处理流程学习

FlowDroid 一、处理流程学习 下载配置源码概况代码逻辑分析analyzeAPKFilerunInfoflowprocessEntryPointcalculateCallbacks(sourcesAndSinks)再次回到processEntryPoint 自己做一些笔记 下载配置 参照我前面的文章可以使用FlowDroid安装初体验 为了看代码了解FlowDroid如何处…

homeassistant ubuntu自启动 网络设置

命令行安装virtualbox 或者安装包 hass官网下载 haos_ova-10.4.vdi virtualbox 装hass 最少2G内存 其他省略 自启动: gnome-session-properties 添加 VBoxManage startvm hass --type headless hass为自己的虚拟机名字 网络配置如下: 要全部打开

【云原生】Kubernetes容器编排工具

目录 1. K8S介绍 1.1 k8s的由来 下载地址 1.2 docker编排与k8s编排相比 1.3 传统后端部署与k8s 的对比 传统部署 k8s部署 ​2. k8s的集群架构与组件 (1) Kube-apiserver (2)Kube-controller-manager (3&a…

微信小程序开发教学系列(9)- 小程序页面优化

第9章 小程序页面优化 在开发小程序时,页面性能优化是非常重要的一项任务。优化页面性能可以提升用户体验,使小程序更加流畅和高效。本章将介绍一些常见的页面优化方法和技巧,帮助您提升小程序的性能。 9.1 页面性能优化的基本原则 页面性…

vue实现按需加载的多种方式

1.import动态导入 const Home () > import( /* webpackChunkName: "Home" */ /views/Home.vue); 2.使用vue异步组件resolve 这种方式没有成功 //const 组件名 resolve > require([‘组件路径’],resolve) //(这种情况下一个组件生成一个js文件…

vue+elementui前端rules校验缓存问题

场景: 最近公司要求项目前端不要用element-ui,改为使用公司其他组开发的ui组件。 这个ui组件使用基本就是安装后,直接全局替换elementui的el-前缀为公司开发的xx-前缀。 替换之后,发现替换倒是很丝滑,问题不大。可以运…

大场景图片切图python脚本

大场景图片切图python脚本 同时对原图和xml标注进行切割 优点: 1、使用了overlap的分割方法 2、对边界的小目标框进行了省略 # -*- coding: utf-8 -*- """ Author : zengwb Time : 2021/4/17 Software: PyCharm """ import os i…

Python项目日志打点功能实现方法

一、入门介绍 1.1 logging和logger的区别 logging和logger是Python的logging模块中的两个关键概念,它们在功能和用途上有明显的区别。 logging是一个Python标准库,是一个用于记录日志的标准模块。它提供了一个灵活的框架,可以用来记录不同级…

Qt应用开发(基础篇)——对话框窗口 QDialog

一、前言 QDialog类继承于QWidget,是Qt基于对话框窗口(消息窗口QMessageBox、颜色选择窗口QColorDialog、文件选择窗口QFileDialog等)的基类。 QDialog窗口是顶级的窗口,一般情况下,用来当做用户短期任务(确认、输入、选择)或者和用户交流(提…

一、安装GoLang环境和开发工具

一、安装GoLang环境 GoLang中国镜像站 下载后对应的环境包以后,一路下一步就好了,安装路径的话,尽量就安装到默认的文件目录下。 二、配置Go的环境变量 右击此电脑–>属性–>高级系统设置–>环境变量,打开环境变量设置…

MySQL高阶语句之常用查询

目录 常用查询 按关键字排序 区间判断及查询不重复记录 对结果进行分组 限制结果条目 设置别名 通配符 子查询 常用查询 (增、删、改、查) 对 MySQL 数据库的查询,除了基本的查询外,有时候需要对查询的结果集进行处理。 …

设计模式之工厂模式(万字长文)

文章目录 概述工厂模式的优点包括工厂模式有几种主要的变体看一个具体需求使用传统的方式来完成传统的方式的优缺点 简单工厂模式基本介绍使用简单工厂模式简单工厂模式的优缺点优点:缺点: 工厂方法模式看一个新的需求思路 1思路 2工厂方法模式介绍工厂方…

生成式AI,赋能数字劳动力的关键工具

人们认为,生成式人工智能是一种可以让他们用自己的话来提问或生成副本和图像的工具。事实也是如此,人工智能在这两方面上都做的非常好,但让人意想不到的是,它还蕴含着改变我们个人和专业工作的巨大潜力,能帮我们访问、…

Unity记录4.5-存储-随角色加载的Tilemap

文章首发见博客:https://mwhls.top/4820.html。 无图/格式错误/后续更新请见首发页。 更多更新请到mwhls.top查看 欢迎留言提问或批评建议,私信不回。 汇总:Unity 记录 摘要:随着角色移动而动态加载的tilemap。 思路-2023/08/18 …

nextTick原理

nextTick 是 Vue 提供的一个异步方法,用于在 DOM 更新之后执行回调函数。它的原理是利用 JavaScript 的事件循环机制来实现异步执行。 具体来说,当我们调用 nextTick 方法时,Vue 会将传入的回调函数添加到一个队列中。在下一个事件循环中&am…

Django(7)-项目实战-发布会签到管理系统

本文使用django实现一个简单的发布会签到管理系统 登录功能 模板页面 sign/templates/index.html <!DOCTYPE html> <html> <head><title>Login Page</title> </head> <body><h1>发布会管理</h1><form action=&qu…

springboot实战(一)之项目搭建

环境准备 ideajdk1.8springboot版本 2.7.15 项目开始 1.打开idea&#xff0c;点击new project 2.选择spring initillizr 核对&#xff1a;Server Url是否是&#xff1a;start.spring.io&#xff0c;然后根据自己依次设置项目名称、存储位置和包名&#xff0c;如下&#xff…

北京开发APP的费用明细

开发APP项目时&#xff0c;在功能确定后需要知道有哪些可能的费用&#xff0c;安排项目预算。北京开发APP的费用明细可能会包括以下几个部分&#xff0c;每个部分都会产生一些费用。今天和大家分享APP费用明细有哪些&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&…

C语言 - 程序的分文件编写

说明过程 C语言程序可以通过分文件编写来提高代码的结构性和可维护性。下面是一个简单的示例&#xff0c;展示了C语言程序如何分文件编写&#xff1a; 创建多个源文件&#xff1a;将程序的不同部分分别写在不同的源文件中&#xff0c;每个文件包含一个或多个相关的函数。比如&…