STM32F407ZGT6|SPI主从模式

news2024/11/27 16:33:49

功能:主机发送数据0x34–>从机接收数据–>通过串口将数据发送出去–>串口猎人显示0x34

必备知识点

1、SPI串行外设接口特点

高速、全双工、同步、串行
  • 高速:发送数据的速度很快
  • 全双工:两设备可同时双向通信(接收与发送)
  • 同步:使用一个时钟源
  • 串行:串行数据一位一位发(占用的外设接口少,但效率相对较低)

2、SPI四根总线及功能

NSS、SCK、MOSI、MISO
  • NSS(片选线):
    [1]每个从机都有自己的一条单独的总线与主机连接,此总线的作用就是为主机选择对应的从机进行传输数据,每个从机与主机之间的NSS总线互不相干。
    [2]片选线默认为高电平,SPI中规定通信以NSS信号线拉低为开始,拉高为结束。(软件管理下,片选线需手动拉低/硬件片选线的拉高与拉低自动设置)
  • SCK(时钟线):保持同步的时钟源(32的晶振)
  • MOSI:主器件输出数据,从器件输入数据(主器件默认为高,主器件默认为低)
    MISO:主器件输入数据,从器件输出数据(主器件默认为高,主器件默认为低)
    注意:“MOSI/MISO电平高低可能有误,但应该是这样”

1主机多从机
在这里插入图片描述
1主机1从机
在这里插入图片描述

3、物理层与协议层的一些知识

物理层:片选线(软件管理/硬件管理)
[1] SPI_NSS_Hard:硬件自动拉高拉低片选,在速率上是远比软件方式控制要高的,缺点是当STM32为主设备时,同一个SPI上面只能接一个从设备。这也就限制了SPI通信设备的数量。
[2] SPI_NSS_Soft:软件控制,GPIO控制片选拉高拉低,优点是一个SPI上面可以挂多个设备。这也是使用较多的方式。通过SPI_Cmd这个函数实现的,使能SPI,硬件自动拉低片选,取消使能SPI,硬件自动拉高片选。
[3] 注意:“一般主器件用软件管理,从器件用硬件管理”

协议层:四种通讯模式
[1] 时钟极性(CPOL):NSS总线空闲时SCK电平信号,空闲时为高电平(=1),低电平(=0)
[2] 时钟相位(CPHA):数据采样时刻,奇数边(=0),偶数边(=1)
在这里插入图片描述

在这里插入图片描述
https://www.bilibili.com/video/BV1wK411g78L/?spm_id_from=333.851.header_right.history_list.click&vd_source=c567c826b38b783f81e4cb19996400c5

https://one-piece.blog.csdn.net/article/details/119545607?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-119545607-blog-126541530.pc_relevant_3mothn_strategy_and_data_recovery&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-1-119545607-blog-126541530.pc_relevant_3mothn_strategy_and_data_recovery&utm_relevant_index=1

配置步骤

主器件

  • 一些初始化:结构体(GPIOA/SPI)
  • 使能:SPI IO/SPI外设时钟
  • 重映射:SPI(NSS/SCK/MISO/MOSI)
  • SPI(NSS/SCK/MISO/MOSI)外设接口初始化
  • SPI初始化;使能SPI;拉低片选
  • 主器件发送数据
//主
#include "stm32f4xx.h"
#include "delay.h"

int main(void)
{
    //一些初始化:结构体(GPIOA/SPI)
	GPIO_InitTypeDef GPIO_InitStructure4;//GPIOA4
	GPIO_InitTypeDef GPIO_InitStructure5;//GPIOA5
	GPIO_InitTypeDef GPIO_InitStructure6;//GPIOA6
	GPIO_InitTypeDef GPIO_InitStructure7;//GPIOA7
	SPI_InitTypeDef SPI_InitStructure;

	//使能:SPI IO/SPI外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能 SPI1 IO口
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能 SPI 外设时钟GPIOA
	
	//重映射:SPI(NSS/SCK/MISO/MOSI)
 	GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);//NSS,使用软件管理方法
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);//SCK
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);//MISO
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);//MOSI
	
	//SPI(NSS/SCK/MISO/MOSI)外设接口初始化
	GPIO_InitStructure4.GPIO_Pin = GPIO_Pin_4;
	GPIO_InitStructure4.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure4.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure4.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure4.GPIO_Speed = GPIO_Low_Speed;
	GPIO_Init(GPIOA , &GPIO_InitStructure4);
	
	GPIO_InitStructure5.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure5.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure5.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure5.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure5.GPIO_Speed = GPIO_Low_Speed;
	GPIO_Init(GPIOA , &GPIO_InitStructure5);
	
	GPIO_InitStructure6.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure6.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure6.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure6.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure6.GPIO_Speed = GPIO_Low_Speed;
	GPIO_Init(GPIOA , &GPIO_InitStructure6);
	
	GPIO_InitStructure7.GPIO_Pin = GPIO_Pin_7;
	GPIO_InitStructure7.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure7.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure7.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_InitStructure7.GPIO_Speed = GPIO_Low_Speed;
	GPIO_Init(GPIOA , &GPIO_InitStructure7);
	
	//SPI初始化;使能SPI;**拉低片选**
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//通信方式:全双工模式;包括(半双工、全双工、串行发、串行收)
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//SPI模式:主模式;包括(主、从)
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//八位实际只有7位
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//时钟极性:空闲时高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//数据在第二个跳变沿被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//传输速度为84MHz/256=328.125KHz
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//大端 小端 MSB 10000001 LSB
	SPI_InitStructure.SPI_CRCPolynomial = 7;//设置CRC校验多项式
	SPI_Init(SPI1,&SPI_InitStructure);
	
	SPI_Cmd(SPI1,ENABLE);//使能SPI1
	//NSS 置低
	GPIO_ResetBits(GPIOA, GPIO_Pin_4);
	
	//主器件发送数据
	while(1)
	{		
		if(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)==SET)//缓冲区为空
		{
			SPI_I2S_SendData(SPI1,0x34);
		}
//		SPI_I2S_ClearFlag(SPI1, SPI_I2S_FLAG_TXE);
	}
}

从器件

  • 一些初始化:结构体(GPIOA/SPI/USART/NVIC)
  • 使能:SPI IO/SPI外设时钟/USART
  • 重映射:SPI(NSS/SCK/MISO/MOSI)、USART
  • SPI(NSS/SCK/MISO/MOSI)外设接口初始化;USART外设接口初始化
  • SPI初始化;使能SPI;开启SPI接收数据中断
  • USART初始化;USART设置;使能USART
  • NVIC配置
  • 编写中断服务程序
//从
#include "stm32f4xx.h"
#include "delay.h"

int main(void)
{
	//一些初始化:结构体(GPIOA/SPI/USART/NVIC)
	GPIO_InitTypeDef GPIO_InitStructure5;//GPIOA5、6、7
	GPIO_InitTypeDef GPIO_InitStructure;//USART
	USART_InitTypeDef Usart_InitStructure;//USART
	SPI_InitTypeDef SPI_InitStructure;//SPI
	NVIC_InitTypeDef  NVIC_InitStructure;//NVIC
	
	//使能:SPI IO/SPI外设时钟/USART
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能 外设时钟GPIOA
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//使能 USART1
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能 外设SPI1

	//重映射:SPI(NSS/SCK/MISO/MOSI)、USART
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_SPI1);//NSS,使用软件管理方法
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);//SCK
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);//MISO
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);//MOSI
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//usart
//	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);//usart

	//SPI(NSS/SCK/MISO/MOSI)外设接口初始化;USART外设接口初始化
	GPIO_InitStructure5.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
//	GPIO_InitStructure5.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure5.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure5.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure5.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure5.GPIO_Speed = GPIO_Low_Speed;
	GPIO_Init(GPIOA , &GPIO_InitStructure5);

	//SPI初始化;使能SPI;开启SPI接收数据中断
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//通信方式:全双工模式;包括(半双工、全双工、串行发、串行收)
	SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;//SPI模式:从模式;包括(主、从)
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//八位实际只有7位
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//时钟极性:空闲时高电平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//数据在第二个跳变沿被采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;//从机--该处注意
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//传输速度为84MHz/256=328.125KHz
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//大端 小端 MSB 10000001 LSB
	SPI_InitStructure.SPI_CRCPolynomial = 7;//设置CRC校验多项式
	SPI_Init(SPI1,&SPI_InitStructure);
	
	SPI_Cmd(SPI1,ENABLE);//使能SPI1
	SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE);//开启相关中断
	
	//USART初始化;USART设置;使能USART
//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Low_Speed;
	GPIO_Init(GPIOA , &GPIO_InitStructure);
	
	//串口设置
	Usart_InitStructure.USART_BaudRate = 9600;//波特率
	Usart_InitStructure.USART_WordLength = USART_WordLength_8b;//八个数据位
	Usart_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	Usart_InitStructure.USART_Parity = USART_Parity_No;//奇偶校验
	Usart_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//失能硬件流
//	Usart_InitStructure.USART_Mode = USART_Mode_Tx|USART_Mode_Rx ;//发送使能
	Usart_InitStructure.USART_Mode = USART_Mode_Tx;
	USART_Init(USART1, &Usart_InitStructure); //将以上赋完值的结构体带入库函数USART_Init进行初始化
	USART_Cmd(USART1,ENABLE);//USART_CR1控制寄存器1  UE位激活USART
	
	//NVIC配置
	NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQn;//定义的初始化中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	while(1){};
	
}
	u8 U_data,S_data;
	//编写中断服务程序
void SPI1_IRQHandler(void)
{
	if(SPI_I2S_GetITStatus(SPI1,SPI_I2S_IT_RXNE)!= RESET)//接收缓冲区 0缓冲区为空;1缓冲区不为空
	{
			S_data = SPI_I2S_ReceiveData(SPI1);
			USART_SendData(USART1,S_data);
	}
//	SPI_I2S_ClearITPendingBit(SPI1, SPI_I2S_IT_RXNE);
}

注意:
[1] 每个步骤一定要理解后配置,不要配置错了
“之前就是重映射那里将SPI写成了SAI”导致了错误
[2] 连线一定要连对(MISO–MISO MOSI–MOSI NSS–NSS SCK–SCK)
在这里插入图片描述
“之前连错了MOSI–MISO,导致串口输出的数据是0xFF,因为从器件的MOSI连接的是主器件的MISO(默认为高组态,所以输出为0xFF)”

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

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

相关文章

STM32 CAN过滤器标识符学习笔记

最近看了下STM32 CAN 通讯其中标示符过滤器设置大有讲究。特别是你要使用ST库函数时,当过滤器工作在屏蔽模式下,并且你把屏蔽位设了1也就是标示符对应位必须全部匹配才能通过,这是由其要小心。 举个例子吧,过滤器长度为32位&…

【MindSpore易点通】在开发环境中如何使用MindInsight在线调试器

背景信息 在使用开发环境训练任务过程中,为方便开发人员更形象地观察到实时训练任务中的数值变化情况以分析精度问题,ModelArts在线调节器应运而生。与离线调试器的区别在于,离线调试器只能待整个任务运行完成后(收集到整个任务过…

【机器学习大杀器】Stacking堆叠模型

1.前言 Kaglle比赛中使用Stacking模型是非常常见的大杀器,这是为什么呢? 【机器学习大杀器】Stacking堆叠模型 1.前言 2.Model 3: Stacking model 2.1 description of the algorithms: 2.2 interpretation of the estimated models: 3. Extend 3.1 …

终于盼到了,Python 数据科学速查表中文版来了

近几年以来,Python 的应用场景越来越多,几乎可以应用于自然科学、工程技术、金融、通信和商业等各种领域。究其原因在于 Python 的简单易学、功能强大。 想系统地学点东西,发现很多不错的技术文档都是英文资料,发现英文竟然成为了…

数据结构考研第六章——图(内含动图)

大纲要求:图的相关算法相对较多,通常只要求掌握其基本思想和实现步骤,而算法的具体实现不是重点。 一、图的基本概念 图的概念:图G由顶点集V和边集E组成的,记为G(V,E)有向图&#x…

6_显示登录信息以及上传图片

目录一 显示登录信息二 账号设置修改用户图片一 显示登录信息 实现思路 书写一个拦截器 loginTicketInterceptor 在 preHandle 方法中获取用户发送请求时携带的 cookie书写一个专门获取cookie的工具类 CookieUtil查数据库,数据库是否存在该 ticket,判断该凭证是否有效,-凭证是…

【论文阅读】EDPLVO: Efficient Direct Point-Line Visual Odometry

一、公式及符号约定 这篇论文是将直接法的残差计算从点扩展到了线段,所以一些符号在第三章的部分提前做了约定。用Π表示投影的函数,也就是用像素坐标和内参矩阵以及深度信息,投影出点的空间坐标,反之Π-1表示的是将空间坐标投影…

Git使用详细教程

1. cmd面板的常用命令 clear:清屏cd 文件夹名称----进入文件夹cd … 进入上一级目录(两个点)dir 查看当前目录下的文件和文件夹(全拼:directory)Is 查看当前目录下的文件和文件夹touch 文件名----创建文件echo 内容 > 创建文件名----创建文件并写入内容rm 文件名…

基于udp实现回显服务器,翻译服务器

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 udp socket 要掌握的类: 1.DatagramSocket 2.DatagramPacket 一、udp版本回显服务器 服务端: 完整代码 客户端: 完整代码 udp版本翻译…

Spring注入和生命周期

目录 获取Bean对象(对象装配) 属性注入 构造注入 Setter注入 三种注入的优缺点分析 注入的注解: 一个类型多个bean对象的注入方式 1.让变量名等于bean的id 2.用Resource注解(name“bean的id”) 3.用Qualif…

Java 核心技术 0 —— Class加载 和 运行时数据区域

JVM 是 字节码的运行环境,负责装载class到JVM内部,解释编译为对应平台的机器码指令进行执行,对于JVM设计有权威的定义规范,了解 JVM 类加载各部的主要功能 和 运行时数据区域组成 很有意义。 磁盘上有一个.java文件,通…

【目标检测】swin-transformer训练自己的数据集

文章目录1. 数据集的制作1.1. Labelme制作数据集1.2 COCO数据集格式2. 配置swin-transformer3. 训练自己的数据集4. 训练5.参考链接1. 数据集的制作 1.1. Labelme制作数据集 pip install labelme然后在桌面搜索框中找到labelme,然后打开,或者直接在命令…

Python 工匠 第一章 变量与注释

1.1 基础知识 1.1.1 变量常见用法 Python 是一门动态类型的语言,因此无须提前声明变量类型;并且由于其是弱类型语言,即可以更改其变量类型。动态类型语言/弱类型语言 a 10 # 不需要提前声明变量类型 a "a" # 可以更改其变量类…

【架构师】解决方案架构师常用的5种类型架构图

0. 背景 在给不同部门的同学讲解系统时,如果用手势解释解决方案,还有很多“这块和这块通过...”在解释复杂的概念时,大部分人都会晕。我们需要一个视觉效果。有人说一个架构图不就行了吗?但架构图不是一个“放之四海而皆准”的解决…

一、springcloud-eureka服务注册与发现

SpringCloud简介 Spring Cloud 为开发者提供了工具来快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话,集群状态)。分布式系统的协调导致了样板…

04 Vue属性配置

1、ref属性 App.vue代码&#xff1a; <template><div><h1 v-text"msg" ref"myTitle"></h1><button click"showDom">点我输出上方的DOM元素</button><school ref"school" id"sch"/&…

Node.js | Express+MongoDB 实现简易用户管理系统(一)(项目搭建 | RESTful API架构 | 前后端交互)

&#x1f5a5;️ NodeJS专栏&#xff1a;Node.js从入门到精通 &#x1f5a5;️ 博主的前端之路&#xff08;源创征文一等奖作品&#xff09;&#xff1a;前端之行&#xff0c;任重道远&#xff08;来自大三学长的万字自述&#xff09; &#x1f5a5;️ TypeScript知识总结&…

【javaEE】多线程进阶(Part1 锁策略、CAS、synchronized )

目录前言/补充4. 描述一下线程池的执行流程和拒绝策略有哪些&#xff1f;【面试题&#xff01;】一、常见锁策略一&#xff09;乐观锁VS悲观锁二&#xff09;读写锁VS普通互斥锁三&#xff09;重量级锁VS轻量级锁四&#xff09;自旋锁VS挂起等待锁五&#xff09;公平锁VS非公平…

Vue框架背后的故事

文章目录前言Vue萌芽Vue名字的由来因着Vue免试进入MeteorVue逐步完善Taylor推荐VueVue因受质疑发布1.0LinusBorg加入萌生全职做Vue想法Vue在恰到好处的时机出现探索经济来源Serah Drasner加入全职投入Vue建设Vue引入国内Vue受拥国内Vue在决策背景方面的独有优势总结本期推荐前言…

JVM垃圾回收系列之垃圾收集器二

随笔 最近两个星期因为要忙公司项目上线的事情以至于发表的文章会显得碌碌庸流&#xff0c;在此以示歉意 引言 本文将介绍HotSpot中的G1GC 参考书籍&#xff1a;“深入理解Java虚拟机” 个人java知识分享项目——gitee地址 个人java知识分享项目——github地址 G1GC 介…