STM32通过软件实现SPI

前言

当我们发现STM32上的硬件SPI引脚已被占用时,为了实现SPI通信功能,我们可以转而采用软件SPI作为替代方案。然而,需要注意的是,相较于硬件SPI,软件SPI的性能可能会受到一定程度的影响,因为软件实现需要更多的CPU周期和资源来模拟硬件的行为。尽管如此,在硬件资源受限或特定应用需求下,软件SPI仍然是一个可行的选择。

SPI基本原理

SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种由Motorola(摩托罗拉)公司推出并发展的同步串行接口技术。它主要应用于嵌入式系统中的短距离通信,是一种高速的、全双工、同步的通信总线。

SPI通信协议具有高速传输、简单灵活、可靠稳定等特点,在各种嵌入式系统中得到广泛应用。SPI通信协议由四根信号线组成,包括时钟线(SCK)、主端输出从端输入线(MOSI)、主端输入从端输出线(MISO)和片选线(SS)。其中,时钟线由主设备控制,用于同步数据传输;MOSI和MISO分别用于主设备向从设备发送数据和从设备向主设备发送数据;片选线用于选择从设备,可以有多个从设备,通过片选线来选择具体的从设备进行通信。

SPI设备之间采用全双工模式通信,是一个主机和一个或者多个从机的主从模式。主机负责初始化帧,这个数据传输帧可以用于读与写两种操作,片选线可以从多个从机选择一个来响应主机的请求。

然而,SPI也有其缺点,比如没有指定的流控制,没有应答机制确认是否接收到数据,因此在数据传输的可靠性上存在一些缺陷。

总的来说,SPI是一种非常实用的串行通信协议,尤其适用于连接微控制器和外围设备,如存储器芯片、传感器、显示屏等。

我这里进行一个简单的描述,具体的原理有人写的比我更好

文章:SPI原理超详细讲解—值得一看

STM32软件SPI实现步骤(主机模式)

选择合适的GPIO引脚模拟SPI接口

我这里使用的是STM32CubeMX来生成代码,使用的芯片是STM32F103RCT6,但是未使用CubeMX来配置引脚,所以我这里将给出代码。引脚分配如下(我这里的应用是驱动LCD,所以默认使用主机模式):

SCL=SCLKSDA=MOSIRSTCS
PB4PB5PB6PB8

代码如下(这里我的应用是驱动LCD,所以命名的就是LCD):

#define LCD_SCL_PORT GPIOB
#define LCD_SCL_PIN GPIO_PIN_4

#define LCD_SDA_PORT GPIOB
#define LCD_SDA_PIN GPIO_PIN_5

#define LCD_RST_PORT GPIOB
#define LCD_RST_PIN GPIO_PIN_6

#define LCD_DC_PORT GPIOB
#define LCD_DC_PIN GPIO_PIN_7

#define LCD_CS_PORT GPIOB
#define LCD_CS_PIN GPIO_PIN_8

#define LCD_SCL_H HAL_GPIO_WritePin(LCD_SCL_PORT,LCD_SCL_PIN,GPIO_PIN_SET);
#define LCD_SCL_L HAL_GPIO_WritePin(LCD_SCL_PORT,LCD_SCL_PIN,GPIO_PIN_RESET);

#define LCD_SDA_H HAL_GPIO_WritePin(OLED_SDA_PORT,LCD_SDA_PIN,GPIO_PIN_SET);
#define LCD_SDA_L HAL_GPIO_WritePin(OLED_SDA_PORT,LCD_SDA_PIN,GPIO_PIN_RESET);

#define LCD_RST_H HAL_GPIO_WritePin(LCD_RST_PORT,LCD_RST_PIN,GPIO_PIN_SET);
#define LCD_RST_L HAL_GPIO_WritePin(LCD_RST_PORT,LCD_RST_PIN,GPIO_PIN_RESET);

#define LCD_DC_H HAL_GPIO_WritePin(LCD_DC_PORT,LCD_DC_PIN,GPIO_PIN_SET);
#define LCD_DC_L HAL_GPIO_WritePin(LCD_DC_PORT,LCD_DC_PIN,GPIO_PIN_RESET);

#define LCD_CS_H HAL_GPIO_WritePin(LCD_CS_PORT,LCD_CS_PIN,GPIO_PIN_SET);
#define LCD_CS_L HAL_GPIO_WritePin(LCD_CS_PORT,LCD_CS_PIN,GPIO_PIN_RESET);

#define LCD_BL_H HAL_GPIO_WritePin(LCD_BL_PORT,LCD_BL_PIN,GPIO_PIN_SET);
#define LCD_BL_L HAL_GPIO_WritePin(LCD_BL_PORT,LCD_BL_PIN,GPIO_PIN_RESET);

编写软件SPI的初始化代码

void LCD_GPIO_Init(void) {
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  __HAL_RCC_GPIOB_CLK_ENABLE();

  GPIO_InitStruct.Pin = LCD_SCL_PIN | LCD_SDA_PIN | LCD_BL_PIN | LCD_CS_PIN | LCD_RST_PIN | LCD_DC_PIN;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

对引脚的初始化完毕之后,那就是实现基本的函数,接收和发送函数

实现SPI数据的发送和接收功能

发送函数

void SPI_Transmit(uint8_t byte) {
  uint16_t counter;
  LCD_CS_L;
  for (counter = 0; counter < 8; counter++) {
	LCD_SCL_L;
	if ((byte & 0x80) == 0) {
	  LCD_SDA_L;
	} else
	  LCD_SDA_H;
	byte = byte << 1;
	LCD_SCL_H;
  }
  LCD_CS_H;
}

接收函数(使用接收函数,需要将SDA引脚模式改为输入模式)

uint8_t SPI_ReceiveByte(){
	uint8_t i;
	uint8_t byte = 0;
	for(i = 7;i >= 0; i--){
		LCD_SCL_L;
		if(HAL_GPIO_ReadPin(LCD_SDA_PORT,LCD_SDA_PIN)){
			byte |= (1 << i);
		}
		LCD_SCL_H;
	}
	return byte;
}

以上就是实现SPI发送和接受的基本功能函数。

实际应用SPI驱动LCD屏幕

直接复制代码会显得文章特别长,所以我这里使用了代码小抄来分享我的代码,这里需要说明的是我LCD屏幕是1.4寸的,它的驱动芯片为ST7735S

LCD.c->https://codecopy.cn/post/gfio1s

LCD.h->https://codecopy.cn/post/ezgqo8

lcdfont.h->https://codecopy.cn/post/ky0cam

总结

虽然软件SPI相比于硬件SPI的性能比较弱,但是可以为我们解决引脚占用的问题,它的灵活性也比较高,可以不限特定的硬件引脚。但是它的缺点也比较明显,就是它的传输速度较低,无法满足高速的传输需求,将会增加处理的负载,影响系统的整体性能。所以可以使用硬件SPI的情况下,则还是推荐使用硬件SPI为宜。

如果有不对的地方,欢迎指正!
本人博客:https://www.lfengsir.cn

  • 17
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32系列微控制器中的SPI(串行外设接口)是通过硬件模块实现的。然而,我们可以通过软件来模拟SPI的功能。 在使用软件模拟SPI之前,需要首先了解SPI的基本原理。SPI是一种同步全双工通信协议,它使用主从设备之间的交互式通信来传输数据。SPI的基本组成包括一个主设备和一个或多个从设备,以及一对数据线(MOSI 和 MISO)、一个时钟线(SCLK)和一个片选线(SS)。 要在STM32实现软件模拟SPI,我们首先需要定义并初始化相关的GPIO引脚作为模拟SPI的数据线、时钟线和片选线。然后,我们可以编写一些函数来模拟SPI的各个功能,如发送数据、接收数据和选择从设备。 通过模拟SPI的发送数据函数,我们可以模拟SPI主设备通过数据线发送数据。在这个函数中,我们可以使用GPIO库函数来控制数据线的状态(高电平或低电平),以模拟SPI传输。 接收数据函数模拟SPI主设备接收从设备通过数据线传输的数据。在这个函数中,我们可以使用GPIO库函数来检测数据线上的电平状态,并将其转换为二进制数据。 选择从设备函数模拟SPI主设备选择特定的从设备。在这个函数中,我们可以使用GPIO库函数来控制片选线的状态,以便选择特定的从设备进行通信。 通过这些函数的组合,我们可以在STM32中模拟SPI的基本功能。然而,需要注意的是,软件模拟SPI可能会导致通信速度较慢,并且对于高频率的数据传输可能存在一定的限制。因此,在实际应用中,使用硬件SPI模块通常更为合适和可靠。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值