STM32—SPI通信

news2024/12/25 0:15:16

1.SPI简介

四根通信线:SCK(Serial Clock)(时钟线)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)

同步、全双工

支持总线挂载多设备(一主多从)

所有SPI设备的SCK、MOSI、MISO分别连在一起

主机另外引出多条SS控制线(低电平有效),分别接到各从机的SS引脚

输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入

 

2.SPI时序基本单元 

起始条件:SS从高电平切换到低电平

终止条件:SS从低电平切换到高电平

 

交换一个字节(模式0)

CPOL = 0:空闲状态,SCK为低电平

CPHA = 0:SCK第一个边沿移入数据,第二个边沿移出数据 

交换一个字节(模式1)

CPOL = 0:空闲状态,SCK为低电平

CPHA = 1:SCK第一个边沿移出数据,第二个边沿移入数据

交换一个字节(模式2)

CPOL = 1:空闲状态,SCK为高电平

CPHA = 0:SCK第一个边沿移入数据,第二个边沿移出数据

 

交换一个字节(模式3)

CPOL = 1:空闲状态,SCK为高电平

CPHA = 1:SCK第一个边沿移出数据,第二个边沿移入数据

3.SPI外设简介

STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担

可配置8位/16位数据帧、高位先行/低位先行

时钟频率:f_{PCLK} / (2,4,8,16,32,64,128,256)

支持多主机模型、主或从模式

可精简为半双工/单工通信

支持DMA

兼容I2S协议

 

4.SPI基本结构

 

 

 

5.SPI相关标准库函数简介

//恢复缺省配置
void SPI_I2S_DeInit(SPI_TypeDef* SPIx);

//初始化
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);

//给结构体变量默认值
void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct);

//SPI使能
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);

//中断使能
void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);

//DMA使能
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);
//写DR数据寄存器
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);

//读DR数据寄存器
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
//获取标志位
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);

//清除标志位
void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);

//获取中断标志位
ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);

//清除中断标志位
void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);

6.案例

6.1软件SPI读写W25Q64

#include "stm32f10x.h"                  // Device header

void 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)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)BitValue);
}

uint8_t MySPI_R_MISO(void)
{
	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);
}

void MySPI_Start(void)
{
	MySPI_W_SS(0);
}

void MySPI_Stop(void)
{
	MySPI_W_SS(1);
}

uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	uint8_t ByteReceive = 0x00;
	
	for(uint8_t i = 0;i < 8;i++)
	{
		MySPI_W_MOSI(ByteSend & (0x80 >> i));
		MySPI_W_SCK(1);
		if (MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);}
		MySPI_W_SCK(0);
	}

	return ByteReceive;
}

//uint8_t MySPI_SwapByte(uint8_t ByteSend)
//{
//	uint8_t ByteReceive = 0x00;
//	
//	for(uint8_t i = 0;i < 8;i++)
//	{
//		MySPI_W_MOSI(ByteSend & (0x80 >> i));
//		ByteSend <<= 1;
//		MySPI_W_SCK(1);
//		if (MySPI_R_MISO() == 1){ByteReceive |= 0x01;}
//		MySPI_W_SCK(0);
//	}

//	return ByteReceive;
//}

#include "stm32f10x.h"                  // Device header
#include "MySPI.h"                  
#include "W25Q64_Ins.h"                 


void W25Q64_Init(void)
{
	MySPI_Init();
}

void W25Q64_ReadID(uint8_t *MID,uint16_t *DID)
{
	MySPI_Start();
	MySPI_SwapByte(W25Q64_JEDEC_ID);
	*MID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	*DID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);	
	*DID <<= 8;
	*DID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE);	
	MySPI_Stop();
}

void W25Q64_WriteEnable(void)
{
	MySPI_Start();
	MySPI_SwapByte(W25Q64_WRITE_ENABLE);
	MySPI_Stop();
}

void W25Q64_WaitBusy(void)
{
	uint32_t Timeout = 100000;
	
	MySPI_Start();
	MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1);
	while ((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01)
	{
		Timeout --;
		if(Timeout == 0)
		{
			break;
		}
	}
	MySPI_Stop();
}

void W25Q64_PageProgram(uint32_t Address,uint8_t *DataArray,uint16_t Cout)
{
	W25Q64_WriteEnable();
	
	MySPI_Start();
	MySPI_SwapByte(W25Q64_PAGE_PROGRAM);
	MySPI_SwapByte(Address  >> 16);
	MySPI_SwapByte(Address >> 8);
	MySPI_SwapByte(Address);
	for (uint16_t i = 0;i < Cout;i++)
	{
		MySPI_SwapByte(DataArray[i]);
	}
	MySPI_Stop();
	
	W25Q64_WaitBusy();
}

void W25Q64_SectorErase(uint32_t Address)
{
	W25Q64_WriteEnable();
	
	MySPI_Start();
	MySPI_SwapByte(W25Q64_SECTOR_ERASE_4KB);
	MySPI_SwapByte(Address  >> 16);
	MySPI_SwapByte(Address >> 8);
	MySPI_SwapByte(Address);
	MySPI_Stop();
	
	W25Q64_WaitBusy();
}

void W25Q64_ReadData(uint32_t Address,uint8_t *DataArray,uint32_t Cout)
{
	MySPI_Start();
	MySPI_SwapByte(W25Q64_READ_DATA);
	MySPI_SwapByte(Address  >> 16);
	MySPI_SwapByte(Address >> 8);
	MySPI_SwapByte(Address);
	for(uint32_t i = 0;i < Cout;i++)
	{
		DataArray[i] = 	MySPI_SwapByte(W25Q64_DUMMY_BYTE);
	}
	MySPI_Stop();
}

6.2硬件SPI读写W25Q64

#include "stm32f10x.h"                  // Device header

void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
}


void MySPI_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = 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);

	SPI_InitTypeDef SPI_InitStructure;
	//SPI模式
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	//配置SPI裁剪引脚,当前选择为双线全双工
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	//配置8位还是16位数据帧
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	//选择低位先行还是高位先行
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	//波特率预分频器,配置SCK时钟的频率
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
	//配置SPI模式
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
	//配置SPI模式
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	//CRC校验,当前所给为默认值
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(SPI1,&SPI_InitStructure);
	
	SPI_Cmd(SPI1,ENABLE);
	
	MySPI_W_SS(1);
}

void MySPI_Start(void)
{
	MySPI_W_SS(0);
}

void MySPI_Stop(void)
{
	MySPI_W_SS(1);
}

uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) != SET);
	
	SPI_I2S_SendData(SPI1,ByteSend);
	
	while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) != SET);

	return SPI_I2S_ReceiveData(SPI1);
}

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

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

相关文章

【Python学习-UI界面】PyQt5 小部件13-Slider 拖动条

高级布局管理器&#xff0c;允许通过拖动边界来动态改变子小部件的大小。 Splitter控件提供一个手柄&#xff0c;可以拖动以调整控件的大小 样式如下: 常用方法如下&#xff1a; 序号方法描述1addWidget将小部件添加到拆分器的布局中2indexOf返回布局中小部件的索引3insetW…

炖羊肉

炖羊肉必备的两种香辛料&#xff0c;白胡椒、白芷&#xff0c;让你炖出的羊肉软嫩&#xff0c;汤汁鲜美 在烹饪艺术的广阔领域中&#xff0c;炖羊肉作为一道经典佳肴&#xff0c;其风味的层次与深度往往取决于所选香辛料的精妙搭配。其中&#xff0c;白胡椒与白芷作为炖羊肉时…

fun状态上传,并可手动控制

文章目录 引言上传原因:矛盾点:基础工程源码: 代码实操fun状态上传fun状态下发控制 引言 上传原因: 续上一节, 我们把fun像小灯一样, 加入了预警工程, 但是我们fun其实还有其他用处, 比如我们人工手动开风扇, 排风, 所以我们需要把fun的状态上传, 然后也可以通过服务器手动控制…

EmguCV学习笔记 VB.Net 2.3 Mat类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV学习笔记目录 Vb.net EmguCV学习笔记目录 C# 笔者的博客网址&#xff1a;VB.Net-CSDN博客 教程相关说明以及如何获得pdf教…

StackStorm自动化平台

1. StackStorm概述 1.1 StackStorm介绍 StackStorm是一个开源的事件驱动自动化平台&#xff0c;它允许开发者和系统管理员自动化IT和网络操作。StackStorm结合了IT运维、DevOps和网络安全团队的需求&#xff0c;提供了一个集中式的工作流自动化解决方案&#xff0c;包括事件响…

Windows10、ARM开发板、虚拟机Ubuntu可同时上网

一、Windows10端设置 1、打开网络配置 2、打开适配器 3、将window连接的wifi网卡设置为共享模式 4、查看本地连接的ip 到此&#xff0c;window10端设置完毕 二、设置虚拟机端&#xff08;Ubuntu&#xff09; 1、打开网络配置 2、打开适配器 3、查看本地连接的网卡名称 4、配置…

超越流水线,企业研发规范落地新思路

作者&#xff1a;子丑 内容大纲&#xff1a; 1、研发规范≠流程约束 2、自动化工具→研发规范载体 3、研发规范在工具上的落地示例 4、研发规范的选型方法与常见实践 研发规范≠流程约束 这个故事特别适合研发规范的场景&#xff0c;我们要避免成为把猫绑在柱子上的信众…

[NOIP2007 普及组] 守望者的逃离 题解

题意 给定 M ( 0 ≤ M ≤ 1 0 3 ) , S ( 1 ≤ S ≤ 1 0 8 ) , T ( 1 ≤ T ≤ 3 1 0 5 ) M(0 \leq M \leq 10^3),S(1 \leq S \leq 10^8),T(1 \leq T \leq 3\times 10^5) M(0≤M≤103),S(1≤S≤108),T(1≤T≤3105)&#xff0c;守望者开始在位置 0 0 0&#xff0c;对于每一秒&…

C++调用C#方法(附踩坑点)

C调用C#方法 写在前面效果思路步骤可能的问题 写在后面 写在前面 工作需要用C调用C#写到代码&#xff0c;看来网上写的方法&#xff0c;自己也踩了一些坑&#xff0c;这里总结一下&#xff0c;我只试了CLR的方法。 主要参考了下面几篇博客 C调用C#库简单例程&#xff08;Lucky…

【BUU】[NewStarCTF 2023 公开赛道]Final -CP读取文件内容

漏洞检测 访问首页发现是ThinkPHP5 的站点 用工具扫描一下,发现存在ThinkPHP5.0.23 RCE漏洞 访问验证,写入shell 成功写入shell. 根目录发现flag,但是权限不足 提权获取flag 准备提权,这里一开始尝试了find,但是find权限不足 尝试采用cp命令,移动到web目录,发现访问还是…

MySQL InnoDB中一个update语句从执行到提交的全过程(3)

接上文MySQL InnoDB中一个update语句从执行到提交的全过程&#xff08;2&#xff09;-CSDN博客 目录 六、本地提交 怎样保证binlog和redo log的状态一致呢&#xff1f; MySQL 中的内部 XA 机制 宕机时不同状态的处理 物理落盘策略 七、主备复制 八、返回提交成功 总结一…

Windows 10/11和Linux双系统用户请勿安装最新更新 否则将无法启动

据蓝点网报道&#xff0c;Windows 10/11 最新累积更新存在已知问题&#xff0c;如果你同时安装了 Linux 双系统则会在更新后导致系统无法正常启动。 启动时会出现如下报错&#xff1a; Verifiying shim SBAT data failed: Security Policy Violation.Something has gone serio…

私域场景中的数字化营销秘诀

​在当今的商业世界&#xff0c;私域场景的营销变得愈发重要。今天咱们就来深入探讨一下私域场景中的几个关键营销手段。 一、会员管理与营销 企业一旦拥有完善的会员体系&#xff0c;数字化手段就能大放异彩。它可以助力企业对会员进行精细划分&#xff0c;深度了解会员的消费…

win11笔记本电脑 声音输出设置为扬声器 | 添加蓝牙设备 | win11环境变量设置

&#x1f947; 版权: 本文由【墨理学AI】原创首发、各位读者大大、敬请查阅、感谢三连 &#x1f389; 声明: 作为全网 AI 领域 干货最多的博主之一&#xff0c;❤️ 不负光阴不负卿 ❤️ 文章目录 win11笔记本电脑 声音输出设置为扬声器搜索设置&#xff0c;打开设置选择声音选…

AI安全-文生图

1 需求 2 接口 3 示例 大模型图像安全风险探析 - 先知社区 前言 文生图模型是一种新兴的人工智能技术,它通过对大规模文本数据的学习,能够生成逼真的图像。这种模型包含两个主要组件:一个文本编码器和一个图像生成器。 文本编码器接收文本输入,并将其转换为一种数字化的表示…

Idea开发代码注释规范

规范 类注释&#xff1a;每个类都应该有一个简短的注释&#xff0c;描述这个类的用途和主要功能。注释应该放在类的声明之前&#xff0c;使用JavaDoc格式。 /*** 这是一个示例类&#xff0c;用于演示如何编写类注释。*/ public class ExampleClass {// ... }方法注释&#xf…

【Oracle点滴积累】解决PrereqSession failed: RawInventory gets null OracleHomeInfo故障的方法

广告位招租&#xff01; 知识无价&#xff0c;人有情&#xff0c;无偿分享知识&#xff0c;希望本条信息对你有用&#xff01; 今天和大家分享在安装Oracle Critical Patch Update (Patch Number:33806138) 遇到PrereqSession failed: RawInventory gets null OracleHomeInfo故…

github官网在线通过vscode编辑器模式查看编辑代码

文章目录 背景步骤关于快捷键话外 背景 今天新发现的一个小玩意儿 步骤 在github项目主页&#xff08;我尝试了无痕模式不行&#xff09; 按键盘的.这个按键&#xff0c;就是m右边2个&#xff0c;然后就会打开这个网站 github.dev/xxx 首次进入的时候&#xff0c;会像首次…

IDEA系列(四):IDEA导入Maven工程项目并配置Tomcat启动

IDEA系列(四)&#xff1a;IDEA导入Maven工程项目并配置Tomcat启动 前言 【本篇使用IDEA版本&#xff1a;大概2020版本&#xff0c;较早了&#xff0c;不过版本大体一致】【若需要码&#xff0c;请扫描关注编程D艺术&#xff0c;回复idea2024&#xff0c;获取码使你的IDEA更加方…

Arm-v8/v9虚拟化原理---aarch64_virtualization_guide

一、相关参考&#xff08;请仅参考&#xff0c;任意一篇足矣&#xff09; 1.https://www.cnblogs.com/LoyenWang/p/13584020.html 2.https://zhuanlan.zhihu.com/p/470045640 3.万字剖析 Armv8 架构虚拟化-腾讯云开发者社区-腾讯云 4.https://zhuanlan.zhihu.com/p/5290842…