【通信协议】SPI总线

news2024/9/23 7:23:48

目录

SPI简介

硬件电路

SPI模式

软件模拟初始化 

时序基本单元

起始条件

终止条件

发送与接收

 SPI基本单元代码 

MySPI.h

MySPI.c  


SPI简介

SPI(Serial Peripheral Interface),即串行外围设备接口,是由Motorola公司开发的一种高速全双工通用数据总线。它被广泛地使用在要求通讯速率较高的场合。

特征

  • 同步,全双工,串行
  • 通讯速率较高
  • 支持总线挂载多设备(一主多从)
  • 四条通信线
  • 短距离

通信线

SCK(Serial Clock):串行时钟线,主机生成时钟,主机和从机根据电平边沿(上升沿或下降沿)发送数据位、接收数据位

MOSI(Master Output Slave Input):主机输出,从机输入

MISO(Master Input Slave Output):主机输入,从机输出

SS(Slave Select):指定主机与哪个从机通信,同一时间主机只能选择一个从机,故只能设置一个SS低为电平。未被选中(NSS引脚为高电平)的从设备会忽略总线上的数据传输

传输速度

SPI总线上的主设备必须在通信开始时候配置并生成相应的时钟信号。从理论上讲,只要实际可行,时钟速率就可以是你想要的任何速率,当然这个速率受限于每个系统能提供多大的系统时钟频率,以及最大的速率。

硬件电路

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

主机另外引出多条SS控制线,分别接到各从机的SS引脚

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

当从机的SS引l脚为高电平,也就是从机未被选中时,它的MISO引脚,必须切换为高阻态,在SS为低电平时,MISO才允许变为推挽输出。在SS未被选中的状态,从机的MISO引脚必须关断输出,即配置输出为高阻态。

SPI模式

SPI 根据时钟极性和时钟相位的不同可以有4种工作模式,通常在编写 SPI 设备驱动程序时需要特别注意从设备的时钟相位与时钟极性,如果与主设备不一致时,一般都不能进行正常的通信

  1. 模式0(CKPL=0,CKPH=0):

    • 时钟极性(Clock Polarity)为0,表示时钟空闲状态为低电平。
    • 时钟相位(Clock Phase)为0,表示数据在时钟信号的奇数边沿(时钟上升沿)进行采样和稳定。
  2. 模式1(CKPL=0,CKPH=1):

    • 时钟极性为0,时钟空闲状态为低电平。
    • 时钟相位为1,数据在时钟信号的偶数边沿(时钟下降沿)进行采样和稳定。
  3. 模式2(CKPL=1,CKPH=0):

    • 时钟极性为1,时钟空闲状态为高电平。
    • 时钟相位为0,数据在时钟信号的奇数边沿(时钟下降沿)进行采样和稳定。
  4. 模式3(CKPL=1,CKPH=1):

    • 时钟极性为1,时钟空闲状态为高电平。
    • 时钟相位为1,数据在时钟信号的偶数边沿(时钟上升沿)进行采样和稳定。

软件模拟初始化 

根据SPI硬件规定:

MISO(Master Input Slave Output),SCK(Serial Clock),SS(Slave Select)均配置为推挽输出

MISO(Master Input Slave Output)配置为上拉输入

GPIO的其它参数的理解可以阅读下方博客,这里不再赘述。

【STM32】GPIO和AFIO标准库使用框架_gpio afio-CSDN博客

本篇软件模拟使用SPI的模式0 

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);//推挽输出默认输出低电平
	
	MySPI_W_SS(1);//不选择从机,空闲状态
	MySPI_W_SCK(0);//模式0空闲时的SCK
	
	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);
	
}

时序基本单元

起始条件

SS(Slave Select)从高电平切换到低电平

void MySPI_Start(void)
{
//初始化时已经配置空闲状态时为高电平,现拉低选择从机
	MySPI_W_SS(0);
}

终止条件

SS从低电平切换到高电平

void MySPI_Stop(void)
{
//通讯过程中,SS为低电平,拉高代表通讯结束
	MySPI_W_SS(1);
}

发送与接收

SPI只有主模式和从模式之分,没有读和写的说法,外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。也就是说,你发一个数据必然会收到一个数据;你要收一个数据必须也要先发一个数据。

硬件SPI,主机SCK电平变化与数据读写几乎同时进行,但软件SPI,程序是一条一条执行的,软件模拟就先变化时钟,再读写数据位,不是同时进行的

交换一个字节(模式0)

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

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

在SS下降沿的时候,主机和从机就需要移出数据,那样SCK的第一个边沿才能移入数据

uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	uint8_t i, ByteReceive = 0x00;
	
	for (i = 0; i < 8; i ++)
	{
		MySPI_W_MOSI(ByteSend & (0x80 >> i));//第一次在SS下降沿时发送数据为位,之后SCK下降沿时发送数据位
		MySPI_W_SCK(1);
		if (MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);}//SCK上升沿时接收数据位
		MySPI_W_SCK(0);
	}
	
	return ByteReceive;
}

 SPI基本单元代码 

MySPI.h

#ifndef __MYSPI_H
#define __MYSPI_H

void MySPI_Init(void);
void MySPI_Start(void);
void MySPI_Stop(void);
uint8_t MySPI_SwapByte(uint8_t ByteSend);

#endif

MySPI.c  

#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);//推挽输出默认输出低电平
	
	MySPI_W_SS(1);
	MySPI_W_SCK(0);
	
	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);
	

}

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 i, ByteReceive = 0x00;
	
	for (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;
}

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

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

相关文章

在 FPGA 上实现以太网的“低级”指南

如今&#xff0c;我们日常的网络连接大多是通过无线方式进行的&#xff0c;因此很容易忘记以太网。但它仍然是一种有用的标准&#xff0c;是一个可靠的高吞吐量网络链接的好方法。为此&#xff0c;[Robert Feranec] 和 [Stacy Rieck] 编写了一个关于如何在 FPGA 上使用以太网的…

uniapp实现苹果账号登录

appleLogin(){uni.showToast({title: 正在进行苹果账户登录...,icon: none})uni.login({provider: apple,success: (loginRes) > {uni.getUserInfo({provider: apple,success: async(userInfoRes) > {console.log(用户信息, userInfoRes)// userInfoRes.userInfo.identit…

Python和MATLAB和R对比敏感度函数导图

&#x1f3af;要点 深度学习网络两种选择的强制选择对比度检测贝叶斯自适应估计对比敏感度函数空间观察对比目标量化视觉皮质感知差异亮度、红/绿值、蓝/黄值色彩空间改变OpenCV图像对比度对比敏感度函数模型空间对比敏感度估计眼球运动医学研究空间时间颜色偏心率对比敏感度函…

技术债务已接管经济

“技术债务”一词通常指软件开发过程中的捷径或次优方法。它表现为设计不良的代码、缺乏文档和过时的组件。虽然正确编写的代码和文档是永恒的&#xff0c;但组件和方法却不是。随着时间的推移&#xff0c;软件及其组件可能会成为技术债务。自 40 年前的 20 世纪 80 年代软件行…

Qt使用usbcan通信

一.usbcan环境搭建 可以参照我的这篇博客&#xff1a;USBCAN-II/II使用方法以及qt操作介绍 二.项目效果展示 三.项目代码 这部分代码仅仅展示了部分功能&#xff0c;仅供参考。 #include"ControlCAN.h" #include<QDebug> #include <windows.h> #incl…

位运算,CF 878A - Short Program

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 878A - Short Program 二、解题报告 1、思路分析 顺序处理每个操作&…

数据结构(双向链表)代码详细注释

双向链表 1》双向链表的定义 双向链表也叫双链表&#xff0c;与单向链表不同的是&#xff0c;每一个节点有三个区域组成&#xff1a;两个指针域&#xff0c;一个数据域。 前指针域&#xff1a;存储前驱节点的内存地址 后指针域&#xff1a;存储后继节点的内存地址 数据域&…

Oracle归档日志满了,导致程序打不开,如何解决。

加油&#xff0c;新时代打工人&#xff01; 归档日志错误&#xff0c;登录不上&#xff0c;只能用system 角色登录&#xff0c; 错误提示 oracle 错误257 archiver error connect internal only until freed 解决cmd进入rman RMAN&#xff08;Recovery Manager&#xff09;是一…

喜报 | 麒麟信安“信创云桌面解决方案”在浙江省委党校应用实施,荣膺国家级示范案例

近日&#xff0c;国家工信部网络安全产业发展中心公布了2023年信息技术应用创新解决方案入围获奖名单&#xff0c;麒麟信安“信创云桌面解决方案”在浙江省委党校成功应用实施&#xff0c;获评国家工信部2023年信息技术应用创新解决方案党务政务领域应用示范案例。 据悉&#…

Python、R用RFM模型、机器学习对在线教育用户行为可视化分析|附数据、代码

全文链接&#xff1a;https://tecdat.cn/?p37409 分析师&#xff1a;Chunni Wu 随着互联网的不断发展&#xff0c;各领域公司都在拓展互联网获客渠道&#xff0c;为新型互联网产品吸引新鲜活跃用户&#xff0c;刺激用户提高购买力&#xff0c;从而进一步促进企业提升综合实力和…

Linux--进程管理和性能相关工具

文章目录 进程状态进程的基本状态其他更多态运行(Running或R)可中断睡眠(Interruptible Sleep 或 S)不可中断睡眠(Uninterruptible Sleep 或 D)停止(Stopped 或 T)僵尸(Zombie 或 Z) 状态转换 进程管理相关工具进程树pstreepstree -ppstree -T 进程信息psps输出属性查看进程的父…

C语言-从键盘输入一个字符串,将其中的小写字母全部转换成大写字母,然后输出到一个磁盘文件test中保存,输人的字符串以“!”结束

题目要求&#xff1a; 从键盘输入一个字符串,将其中的小写字母全部转换成大写字母,然后输出到一个磁盘文件test中保存,输人的字符串以"!”结束 1.实现程序&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() {FILE* fp fopen("…

新160个crackme - 038-Eternal Bliss.3

运行分析 需要输入注册码 PE分析 VB程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 使用VB Decompiler静态分析&#xff0c;找到关键函数入口点402AC4 ida跳转至402AC4&#xff0c;按F5反汇编&#xff0c;发现有407行代码&#xff0c;配合VB Decompiler得到的代码…

力扣面试经典算法150题:跳跃游戏 II

跳跃游戏 II 今天的题目是力扣面试经典150题中的数组的中等难度题&#xff1a;跳跃游戏II。 题目链接&#xff1a;https://leetcode.cn/problems/jump-game-ii/description/?envTypestudy-plan-v2&envIdtop-interview-150 题目描述 给定一个非负整数数组 nums&#xff0…

springboot框架中filter过滤器的urlPatterns的匹配源码

如下图所示&#xff0c;我使用WebFilter注解的方式定义了一个过滤器&#xff0c;同时定义了过滤器的过滤条件 urlPatterns为/*,可能很多人都知道filter的/*代表所有URL都匹配&#xff0c;但是源码在哪里呢 先打断点看一下调用链 然后跟着调用链慢慢点&#xff0c;看看哪里开始…

redis面试(二十)读写锁WriteLock

写锁WriteLock 和读锁一样&#xff0c;在这个地方执行自己的lua脚本&#xff0c;我们去看一下 和read没有多大的区别 KEYS[1] anyLock ARGV[1] 30000 ARGV[2] UUID_01:threadId_01:write hget anyLock mode&#xff0c;此时肯定是没有的&#xff0c;因为根本没这个锁 …

LangGPT结构化提示词编写实践 #书生大模型实战营#

1.闯关任务&#xff1a; 背景问题&#xff1a;近期相关研究发现&#xff0c;LLM在对比浮点数字时表现不佳&#xff0c;经验证&#xff0c;internlm2-chat-1.8b (internlm2-chat-7b)也存在这一问题&#xff0c;例如认为13.8<13.11。 任务要求&#xff1a;利用LangGPT优化提示…

电脑如何恢复删除的照片?4种实用恢复办法

在日常生活中&#xff0c;我们经常会因为各种原因误删电脑中的照片&#xff0c;而这些照片往往承载着珍贵的回忆。那么&#xff0c;如果不小心删除了照片&#xff0c;我们该如何恢复呢&#xff1f;下面就为大家介绍几种实用的恢复方法。 一、使用回收站恢复 当我们在电脑上删…

【C++】单例模式的解析与应用

C单例模式&#xff1a;深入解析与实战应用 一、单例模式的基本概念二、C中单例模式的实现方式2.1 懒汉式&#xff08;线程不安全&#xff09;2.2 懒汉式&#xff08;线程安全&#xff09;2.3 饿汉式2.4 静态内部类&#xff08;C11及以后&#xff09; 三、单例模式的优缺点四、实…

基于Transformer进行乳腺癌组织病理学图像分类的方法比较

为了提高视觉变压器的精度和泛化能力,近年来出现了基于Poolingbased Vision Transformer (PiT)、卷积视觉变压器(CvT)、CrossFormer、CrossViT、NesT、MaxViT和分离式视觉变压器(SepViT)等新模型。 它们被用于BreakHis和IDC数据集上的图像分类,用于数字乳腺癌组织病理学。在B…