普通GPIO模拟SPI通信协议(软件SPI)

article/2025/9/21 11:46:10

在工作中偶尔会遇到SPI不够用的情况,而我们又要去使用SPI通信协议,此时就需要我们自己去模拟SPI通信协议。我们知道SPI通信协议有四种模式,它们分别如下所示:
这里写图片描述
下面是我基于ATSAM4SD16B芯片在Atmel Studio上用普通GPIO模拟的SPI通信协议的代码:

#include "ioport.h"
#include "pio.h"
#include "delay.h"
#include "SAM4S_FSA.h"
#include <assert.h>// Define 4 SPI pins
#define CS       IOPORT_CREATE_PIN(PIOA, 8)
#define SCLK     IOPORT_CREATE_PIN(PIOA, 7)
#define MOSI     IOPORT_CREATE_PIN(PIOA, 23)
#define MISO     IOPORT_CREATE_PIN(PIOA, 20)#define SPIDelay  delay_us(1)// Define SPI communication mode
typedef enum SPIMode
{Mode_1,   /* Clock Polarity is 0 and Clock Phase is 0 */Mode_2,   /* Clock Polarity is 0 and Clock Phase is 1 */Mode_3,   /* Clock Polarity is 1 and Clock Phase is 0 */Mode_4,   /* Clock Polarity is 1 and Clock Phase is 1 */
}SPIMode;// Define SPI type
typedef enum SPIType
{SPIMaster,SPISlave,
}SPIType;// Define SPI attribute
typedef struct SpiStruct
{unsigned int ui_CS;unsigned int ui_SCLK;unsigned int ui_MOSI;unsigned int ui_MISO;SPIMode spiMode;SPIType spiType;
}Spi_t;// Function prototypes
void v_SPIInitSimulate(Spi_t* p_Spi);
void v_CSIsEnableSimulate(Spi_t* p_Spi, int i_IsEnable);
void v_SPIWriteSimulate(Spi_t* p_Spi, unsigned char* puc_Data, int i_DataLength);
void v_SPIReadSimulate(Spi_t* p_Spi, unsigned char* puc_Data, int i_DataLength);// Define SPI pins
Spi_t Spi_0 = 
{.ui_CS = CS,.ui_SCLK = SCLK,.ui_MOSI = MOSI,.ui_MISO = MISO,.spiMode = Mode_1,.spiType = SPIMaster,
};/*
Brief: SPI protocol initiate
Input: p_Spi, which spi use
Output: None
Return: None
Author: Andy Lai
*/
void v_SPIInitSimulate(Spi_t* p_Spi)
{assert(p_Spi != NULL);if(p_Spi->spiMode == SPIMaster){ioport_set_pin_dir(p_Spi->ui_CS, IOPORT_DIR_OUTPUT);ioport_set_pin_dir(p_Spi->ui_SCLK, IOPORT_DIR_OUTPUT);ioport_set_pin_dir(p_Spi->ui_MOSI, IOPORT_DIR_OUTPUT);ioport_set_pin_dir(p_Spi->ui_MISO, IOPORT_DIR_INPUT);}else{ioport_set_pin_dir(p_Spi->ui_CS, IOPORT_DIR_INPUT);ioport_set_pin_dir(p_Spi->ui_SCLK, IOPORT_DIR_INPUT);ioport_set_pin_dir(p_Spi->ui_MOSI, IOPORT_DIR_INPUT);ioport_set_pin_dir(p_Spi->ui_MISO, IOPORT_DIR_OUTPUT);}pio_set_pin_high(p_Spi->ui_CS);switch(p_Spi->spiMode){case Mode_1:case Mode_2:pio_set_pin_low(p_Spi->ui_SCLK);break;case Mode_3:case Mode_4:pio_set_pin_high(p_Spi->ui_SCLK);break;}
}/*
Brief: CS low level signal enable and high level signal disable
Input: (1)p_Spi, which spi use(2)i_IsEnable, Chip select(Slave select) enable flag
Output: None
Return: None
Author: Andy Lai
*/
void v_CSIsEnableSimulate(Spi_t* p_Spi, int i_IsEnable)
{assert(p_Spi != NULL);if(i_IsEnable){pio_set_pin_low(p_Spi->ui_CS);}else{pio_set_pin_high(p_Spi->ui_CS);}
}/*
Brief: Use SPI to write a byte data
Input: (1)p_Spi, which spi use(2)uc_Bt, write byte data
Output: None
Return: None
Author: Andy Lai
*/
static void v_SPIWriteByte(Spi_t* p_Spi, unsigned char uc_Bt)
{int i = 0;assert(p_Spi != NULL);switch(p_Spi->spiMode){case Mode_1: /* Clock Polarity is 0 and Clock Phase is 0 */pio_set_pin_low(p_Spi->ui_SCLK);for(i = 7; i >= 0; i--){pio_set_pin_low(p_Spi->ui_SCLK);SPIDelay;pio_set_pin_high(p_Spi->ui_SCLK);if(uc_Bt & (1 << i)){pio_set_pin_high(p_Spi->ui_MOSI);}else{pio_set_pin_low(p_Spi->ui_MOSI);}SPIDelay;}pio_set_pin_low(p_Spi->ui_SCLK);break;case Mode_2: /* Clock Polarity is 0 and Clock Phase is 1 */pio_set_pin_low(p_Spi->ui_SCLK);for(i = 7; i >= 0; i--){pio_set_pin_high(p_Spi->ui_SCLK);if(uc_Bt & (1 << i)){pio_set_pin_high(p_Spi->ui_MOSI);}else{pio_set_pin_low(p_Spi->ui_MOSI);}SPIDelay;pio_set_pin_low(p_Spi->ui_SCLK);SPIDelay;}pio_set_pin_low(p_Spi->ui_SCLK);break;case Mode_3: /* Clock Polarity is 1 and Clock Phase is 0 */pio_set_pin_high(p_Spi->ui_SCLK);for(i = 7; i >= 0; i--){pio_set_pin_high(p_Spi->ui_SCLK);if(uc_Bt & (1 << i)){pio_set_pin_high(p_Spi->ui_MOSI);}else{pio_set_pin_low(p_Spi->ui_MOSI);}SPIDelay;pio_set_pin_low(p_Spi->ui_SCLK);SPIDelay;}pio_set_pin_high(p_Spi->ui_SCLK);break;case Mode_4: /* Clock Polarity is 1 and Clock Phase is 1 */pio_set_pin_high(p_Spi->ui_SCLK);for(i = 7; i >= 0; i--){pio_set_pin_low(p_Spi->ui_SCLK);if(uc_Bt & (1 << i)){pio_set_pin_high(p_Spi->ui_MOSI);}else{pio_set_pin_low(p_Spi->ui_MOSI);}SPIDelay;pio_set_pin_high(p_Spi->ui_SCLK);SPIDelay;}pio_set_pin_high(p_Spi->ui_SCLK);break;default:break;}
}/*
Brief: Use SPI protocol to write data
Input: (1)p_Spi, which spi use(2)puc_Data, write data string(3)i_DataLength, write data length
Output: None
Return: None
Author: Andy Lai
*/
void v_SPIWriteSimulate(Spi_t* p_Spi, unsigned char* puc_Data, int i_DataLength)
{int i = 0;assert(p_Spi != NULL);assert(puc_Data != NULL);assert(i_DataLength > 0);v_CSIsEnableSimulate(p_Spi, 1);delay_us(8);// Write datafor(i = 0; i < i_DataLength; i++){v_SPIWriteByte(p_Spi, puc_Data[i]);}delay_us(8);v_CSIsEnableSimulate(p_Spi, 0);
}/*
Brief: Read a byte data from SPI
Input: p_Spi, which spi use
Output: None
Return: Read data
Author: Andy Lai
*/
static unsigned char uc_SPIReadByte(Spi_t* p_Spi)
{int i = 0;unsigned char uc_ReadData = 0;assert(p_Spi != NULL);switch(p_Spi->spiMode){case Mode_1: /* Clock Polarity is 0 and Clock Phase is 0 */pio_set_pin_low(p_Spi->ui_SCLK);for(i = 0; i < 8; i++){pio_set_pin_low(p_Spi->ui_SCLK);SPIDelay;pio_set_pin_high(p_Spi->ui_SCLK);uc_ReadData = uc_ReadData << 1;uc_ReadData |= pio_get_pin_value(p_Spi->ui_MISO);SPIDelay;}pio_set_pin_low(p_Spi->ui_SCLK);break;case Mode_2: /* Clock Polarity is 0 and Clock Phase is 1 */pio_set_pin_low(p_Spi->ui_SCLK);for(i = 0; i < 8; i++){pio_set_pin_high(p_Spi->ui_SCLK);SPIDelay;pio_set_pin_low(p_Spi->ui_SCLK);uc_ReadData = uc_ReadData << 1;uc_ReadData |= pio_get_pin_value(p_Spi->ui_MISO);SPIDelay;}pio_set_pin_low(p_Spi->ui_SCLK);break;case Mode_3: /* Clock Polarity is 1 and Clock Phase is 0 */pio_set_pin_high(p_Spi->ui_SCLK);for(i = 0; i < 8; i++){pio_set_pin_high(p_Spi->ui_SCLK);SPIDelay;pio_set_pin_low(p_Spi->ui_SCLK);uc_ReadData = uc_ReadData << 1;uc_ReadData |= pio_get_pin_value(p_Spi->ui_MISO);SPIDelay;}pio_set_pin_high(p_Spi->ui_SCLK);break;case Mode_4:  /* Clock Polarity is 1 and Clock Phase is 1 */pio_set_pin_high(p_Spi->ui_SCLK);for(i = 0; i < 8; i++){pio_set_pin_low(p_Spi->ui_SCLK);SPIDelay;pio_set_pin_high(p_Spi->ui_SCLK);uc_ReadData = uc_ReadData << 1;uc_ReadData |= pio_get_pin_value(p_Spi->ui_MISO);SPIDelay;}pio_set_pin_high(p_Spi->ui_SCLK);break;default:break;}return uc_ReadData;
}/*
Brief: Use SPI to read data
Input: (1)p_Spi, which SPI use;    (2)i_DataLength, the length of data that need to read
Output: puc_Data, need to get data
Return: None
Author: Andy Lai
*/
void v_SPIReadSimulate(Spi_t* p_Spi, unsigned char* puc_Data, int i_DataLength)
{int i = 0;assert(p_Spi != NULL);assert(i_DataLength > 0);v_CSIsEnableSimulate(p_Spi, 1);delay_us(8);// Read datafor(i = 0; i < i_DataLength; i++){puc_Data[i] = uc_SPIReadByte(p_Spi);}delay_us(8);v_CSIsEnableSimulate(p_Spi, 0);
}

参考博客:http://blog.csdn.net/yangzheng_yz/article/details/50470577


http://chatgpt.dhexx.cn/article/baoiNvmu.shtml

相关文章

SPI 协议

一. 概念 1. 通常SPI通信要求4根线&#xff0c;分别是MOSI(mast output salve input), MISO, CLK, CS。 2. 当发送和接受数据的工作都准备好了&#xff0c;只要有时钟CLK,就发送数据&#xff0c;没有时钟就不发送&#xff0c;而且一个时钟周期发送一位(bit)数据&#xff0c;所…

SPI通信协议(SPI总线)学习

转载自&#xff1a;https://www.cnblogs.com/deng-tao/p/6004280.html 1、什么是SPI&#xff1f; SPI是串行外设接口(Serial Peripheral Interface)的缩写。是 Motorola 公司推出的一 种同步串行接口技术&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总…

SPI通信

1 SPI的简介及基本特点 1 SPI的简单介绍 最近工作中使用了SPI通信方式来做TM4C129和STM32之间的通信&#xff0c;为了更好地解决问题就学习了SPI原理的相关内容&#xff0c;完成了项目之后&#xff0c;也对这种通信方式有了较为深入的了解&#xff0c;现在来对SPI的使用方法进…

详解SPI通信协议

一、SPI简介 SPI&#xff0c;即Serial Peripheral Interface的英文缩写。从字面意思看就是串行外部设备接口&#xff0c;是一种全双工、高速、同步的通信总线。 SPI最早是摩托罗拉公司开发的全双工同步串行总线&#xff0c;用于微控制器&#xff08;MCU&#xff09;连接外部设…

stm32中常见的通信协议之SPI

目录 1.SPI总线2.SPI的寻址方式3.SPI的工作原理总结4.SPI的通讯过程5.SPI的极性和相位6.IIC和SPI的异同7.stm32中SPI配置中常用的寄存器8.stm32中相关库函数 1.SPI总线 SPI是串行外设接口的缩写&#xff0c;SPI是一种高速的、全双工、同步的串行通信协议&#xff1b;SPI采用主…

【通信协议】一文搞懂SPI

SPI总线简介 SPI(Serial Peripheral Interface)是 Motorola 公司推出的一种同步串行接口技术&#xff0c;是一种高速的&#xff0c;全双工&#xff0c;同步的通信总线。 接口定义 SPI接口共有4根信号线&#xff0c;分别是&#xff1a;片选信号、时钟信号、串行输出信号、串行…

SPI 通信协议 最详细解读!!!

SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外围接口&#xff09;是一种高速、全双工、同步的通信总线&#xff0c;主要应用在EEPROM、FLASH、实时时钟、AD转换器上&#xff0c;以及数字信号处理器和数字信号解码器之间。 信号线 SPI有四根信号线&#xff1a;…

SPI 通信协议详解

SPI通信协议详解 写在最前: 本文讲述了SPI通信协议的基本内容包括如下 SPI的基础知识SPI的读写时序 本文重点参考 英文维基百科 中文维基百科 百度百科 注意: 倘若读者有足够的耐心和英文水平&#xff0c;强烈建议自行去英文维基百科去阅读相关知识。 相关链接&#xff1a; SPI…

通信协议篇——SPI通信

通信协议篇——SPI通信 1.简介 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种高速、同步、全双工串行通信总线&#xff0c;采用主从机通信模式&#xff0c;主要应用在EEPROM&#xff0c;FLASH&#xff0c;实时时钟&#xff0c;AD转换器等。 2.原理 通信方…

SPI接口通信协议详解:SPI时序、2线、3线、4线SPI及4种常用工作模式

简介 SPI通信原理比I2C要简单&#xff0c;它主要是主从方式通信。这种模式通常只有一个主机和一个或者多个从机&#xff0c;标准的SPI是4根线&#xff0c;分别是SSEL(片选&#xff0c;也写作 SCS)、SCLK(时钟&#xff0c;也写作SCK)、MOSI(主机输出从机输入Master Output/Slav…

详解UART、I2C、SPI常用通信协议(全是细节)

前言 UART、I2C和SPI是我们在嵌入式开发中比较常见的通信协议了&#xff0c;没有最好的通信协议&#xff0c;每个通信协议都有自己的优缺点。如果想要通信速度快&#xff0c;SPI 将是理想的选择&#xff1b;如果用户想要连接多个设备而不是过于复杂&#xff0c;I2C 将是理想的选…

【总线】SPI 通信协议

目录 SPI总线协议概述 串行与并行通信 SPI通信介绍 SPI的工作原理 时钟 从属选择 多个从机 常规方法 菊花链方法 MOSI 和 MISO SPI 数据传输的步骤 SPI 的优缺点 优点 缺点 文章参考 SPI总线协议概述 SPI是许多不同设备使用的通用通信协议。例如&#xff0c;SD卡…

SPI通信协议详解,一篇就够!

一、什么是SPI&#xff1f; SPI 的英文全称为 Serial Peripheral Interface&#xff0c;顾名思义为串行外设接口。SPI 是一种同步串行通信接口规范&#xff0c;主要应用于嵌入式系统中的短距离通信。该接口由摩托罗拉在20世纪80年代中期开发&#xff0c;后发展成了行业规范。 …

2021年游戏项目的十大编程语言:C++、Java、C#均上榜

在这个技术驱动的世界里&#xff0c;游戏行业是全球增长最快的行业之一。在每一款华丽精美的电子游戏背后&#xff0c;都有一种编程语言&#xff0c;为用户提供优质的体验。游戏开发者利用顶级的编程语言来构建游戏。不同的游戏项目使用了不同的编程语言&#xff0c;这取决于游…

2021 编程语言排行榜

点击“终码一生”&#xff0c;关注&#xff0c;置顶公众号 每日技术干货&#xff0c;第一时间送达&#xff01; IEEE Spectrum 发布了 2021 年编程语言排行榜&#xff0c;官方的标题是&#xff1a;Python 在新技术领域依然是主导地位。 Python 近几年随着大数据、数据挖掘、人…

2020 年最牛逼的 10 门编程语言

先看再点赞&#xff0c;给自己一点思考的时间&#xff0c;微信搜索【沉默王二】关注这个有颜值却假装靠才华苟且的程序员。 本文 GitHub github.com/itwanger 已收录&#xff0c;里面还有我精心为你准备的一线大厂面试题。 对于很多初学编程的人来说&#xff0c;尤其是马上要入…

世界上到底有多少种编程语言?

最近&#xff0c;网站上看到一个很有意思的问题&#xff1a;世界上到底有多少种编程语言&#xff1f; 查遍网络之后&#xff0c;仍然没有找到准确答案&#xff0c;只知道几千的数量是有的&#xff0c;但是我们常用的也就几十来个&#xff0c;其中最常见的便是Java、Python、C、…

世界上最难的5种编程语言

世界上最难的5种编程语言 每个程序员都熟悉许多编程语言。许多编程语言都是高级的&#xff0c;它们的语法是人类可读的。然而&#xff0c;也有一些低级语言&#xff0c;对于一个人来说&#xff0c;读起来很困难&#xff0c;但是可以理解。然而&#xff0c;您是否遇到过一种既不…

2018年最流行的十大编程语言,有你用的吗?

对于编程界的初学者来说&#xff0c;最大的困难是决定从何处入手&#xff0c;或者应掌握哪种语言才能在职场上平步青云。有时&#xff0c;专业程序员也面临学习一门新语言似乎更卓有成效的情形。 无论是什么原因&#xff0c;下面列出了世界上最流行的编程语言&#xff0c;以便了…

5月编程排行榜出炉,最佳编程语言是谁?

技术的发展日新月异&#xff0c;作为开发者&#xff0c;应该时刻关注这些变化&#xff0c;不断学习才能跟上时代步伐。 编程语言层出不穷&#xff0c;关于“ 最佳编程语言 ”的争论也从未停止&#xff0c;网友们各抒己见...... 网友A&#xff1a; 人生苦短&#xff0c;我选Pyt…