之前用STM32的SPI需要控制很多外部芯片,可是一个SPI的外设只有一个片选,要实现独立片选一主多从,怎么实现呢?

SPI总线拓扑

一般地,SPI总线按照下图方式进行连接,一主多从。

如上图:

  • 每个从设备都有独立的片选引脚,主机同一时间段内,与一个从设备进行通信,也即选中一个从设备。

  • MOSI/MISO/SCLK并联在一起

  • MISO须是三态门,当从设备未选中时,该脚须设置为高阻态,而不能是输出态,否则会影响总线

  • 对于MOSI/SCLK,虽然并联在一起,但是由于仅一个输出,多输入。

但是你看STM32的SPI外设,一个SPI仅有一个NSS信号,以STM32F407的SPI2为例:

那么要实现前面说的一主多从,怎么办呢?有朋友说,直接用GPIO去模拟不就可以了。

不错,SPI总线要用GPIO模拟还是很容易的,但是这样做波特率做不高,需要占用CPU时间,效率比较低!而用SPI外设控制器,底层bit流的收发由外设控制器实现,用GPIO模拟则需要CPU参与。

怎么破呢?

菊花链拓扑

这种方案,省引脚。但是要移位控制,相对独立片选效率还是低不少。

独立片选拓扑

SPI外设的MOSI、MISO、SCK还是照用不误,但是片选我们不用,设置成通用输出模式,再用其他的GPIO片选从芯片即可。

上代码看看:

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(hspi->Instance==SPI1){__HAL_RCC_SPI1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**SPI1 GPIO ConfigurationPA5     ------> SPI1_SCKPA6     ------> SPI1_MISOPA7     ------> SPI1_MOSIPA15     ------> SPI1_NSS 但是这里不用*/GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*__HAL_RCC_GPIOC_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);*/ }
}

初始化SPI外设

#define SPI_CS1                        GPIO_PIN_1
#define SPI_CS1_PORT                   GPIOC
#define SPI_CS2                        GPIO_PIN_2
#define SPI_CS2_PORT                   GPIOC
#define SPI_CS3                        GPIO_PIN_3
#define SPI_CS3_PORT                   GPIOC
static void init_spi(SPI_HandleTypeDef * spi_handle)
{/* SPI1 parameter configuration*/spi_handle->Instance = SPI1;spi_handle->Init.Mode = SPI_MODE_MASTER;spi_handle->Init.Direction = SPI_DIRECTION_2LINES;spi_handle->Init.DataSize = SPI_DATASIZE_8BIT;spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW;spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE;spi_handle->Init.NSS = SPI_NSS_HARD_OUTPUT;spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB;spi_handle->Init.TIMode = SPI_TIMODE_DISABLE;spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;spi_handle->Init.CRCPolynomial = 10;ASSERT (HAL_SPI_Init(spi_handle) != HAL_OK);GPIO_InitTypeDef  GPIO_InitStructure;__HAL_RCC_GPIOC_CLK_ENABLE();GPIO_InitStructure.Pin = SPI_CS1;GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStructure.Pull = GPIO_NOPULL;GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;HAL_GPIO_Init(SPI_CS1_PORT, &GPIO_InitStructure); GPIO_InitStructure.Pin = SPI_CS2;HAL_GPIO_Init(SPI_CS2_PORT, &GPIO_InitStructure);  GPIO_InitStructure.Pin = SPI_CS3;HAL_GPIO_Init(SPI_CS3_PORT, &GPIO_InitStructure);
}

从而原来SPI的收发函数前后加上片选信号即可:

typedef enum
{  SPI_CH_1=0,SPI_CH_2,SPI_CH_3,SPI_CH_LAST,
} SPI_CH;
static HAL_StatusTypeDef SPI_Select(SPI_CH ch)
{switch (ch){case SPI_CH_1:HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_RESET);break;case SPI_CH_2:HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_RESET);break;case SPI_CH_3:HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_RESET);break;       default:return HAL_ERROR;}  return HAL_OK;
}
static HAL_StatusTypeDef SPI_DeSelect(SPI_CH ch)
{switch (ch){case SPI_CH_1:HAL_GPIO_WritePin(SPI_CS1_PORT,SPI_CS1,GPIO_PIN_SET);break;case SPI_CH_2:HAL_GPIO_WritePin(SPI_CS2_PORT,SPI_CS2,GPIO_PIN_SET);break;case SPI_CH_3:HAL_GPIO_WritePin(SPI_CS3_PORT,SPI_CS3,GPIO_PIN_SET);break;       default:return HAL_ERROR;}return HAL_OK;
}HAL_StatusTypeDef SPI_TransmitReceive(SPI_CH ch,SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,uint32_t Timeout)
{HAL_StatusTypeDef ret; if(ch>=SPI_CH_LAST)return HAL_ERROR;  SPI_Select(ch);ret = HAL_SPI_TransmitReceive(hspi,pTxData,pRxData,Size,Timeout);SPI_DeSelect(ch);return ret;
}HAL_StatusTypeDef SPI_Transmit(SPI_CH ch,SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{HAL_StatusTypeDef ret; if(ch>=SPI_CH_LAST)return HAL_ERROR;  SPI_Select(ch);ret = HAL_SPI_Transmit(hspi,pData,Size,Timeout);SPI_DeSelect(ch);return ret;
}

如此一来,一个SPI外设就可以控制多个从芯片了。你如果有兴趣,不妨照这个思路试试看。

1.中国芯片替代方案公司名单公布(70个类别)

2.为什么原理图总画不好?这些技巧要知道

3.嵌入式设备如何显示IP属地?

4.RISC-V面向MCU/MPU、RTOS,但面临挑战。。。

5.单片机固件自更新的一个方法!

6.玄铁杯RISC-V应用创新大赛正式开赛,现开放报名!

免责声明:本文系网络转载,版权归原作者所有。如涉及作品版权问题,请与我们联系,我们将根据您提供的版权证明材料确认版权并支付稿酬或者删除内容。

STM32的SPI外设片选只有一个怎么破?相关推荐

  1. 关于STM32的SPI外设时钟分频对应的SCK速率

    以STM32F103为例, 经过system_stm32f10x.c文件中的SystemInit()函数之后,这里是指的默认时钟配置如下图所示: STM32F103的系统框架图如下所示: 可见:SPI ...

  2. 基于stm32、spi协议的Fatfs文件系统移植(附完整代码下载)

    开发环境:Window 7 32bit 开发工具:Keil uVision4 硬件:stm32f103vct6 目录 1.硬件设计: 2.软件设计 1.SPI收发数据 2.向SD卡发送的命令格式: 3 ...

  3. 【STM32】SPI协议通信详解

    目录 一.SPI协议简介 二.SPI物理层 三.SPI协议层 1.通讯的起始和停止信号 2.数据有效性 3.时钟信号的相位和极性(重点) 四.SPI 特性及架构(重点) 1.通信引脚 2.时钟控制逻辑 ...

  4. stm32中spi可以随便接吗_stm32之SPI通信协议实例详解

    之前一直对SPI通信一知半解,所以想抽空把它搞得明白一些.考虑到之前是结合Flash芯片来学的,十分不直观,而且主要把时间和精力都花在Flash芯片的datasheet和驱动上了,SPI通信也没学好. ...

  5. 【嵌入式】STM32实现SPI双机通信的一些细节(2)片选总结

    [嵌入式]STM32实现SPI双机通信的一些细节(2)SPI软硬件片选总结 SPI片选总结 坑爹的手册示意图 理想中的硬件片选 主机软件片选就对了 从机硬件片选 从机软件片选 代码 主机软件片选SPI ...

  6. 高通平台SPI外设的片选信号配置

    spi master 和spi device有各自的dts配置: 这是spi master的配置示例,也就是spi控制器 这是一个spi device的配置示例,也就是spi外设(从设备) 一个spi ...

  7. 【STM32】SPI 实验代码详解

    友情链接:[小项目关键技术]硬件通信三种方式.串口.IIC.SPI 文章目录 main.c spi.c spi.h SPI 是英语 Serial Peripheral interface 的缩写,顾名 ...

  8. 基于STM32的SPI基本介绍

    STM32---SPI(DMA)通信的总结(库函数操作) 本文主要由7项内容介绍SPI并会在最后附上测试源码供参考: 1.     SPI的通信协议 2.     SPI通信初始化(以STM32为从机 ...

  9. 【STM32】SPI程序示例

    00. 目录 文章目录 00. 目录 01. SPI简介 02. 功能描述 03. 硬件模块 04. 软件设计 05. 结果验证 06. 附录 07. 声明 01. SPI简介 SPI 是英语 Ser ...

最新文章

  1. mysql 从零开始_MySQL从零开始:01 数据库简介
  2. 深入体验c语言项目开发 光盘,深入体验C语言项目开发
  3. linux下安装oracle集群,【Oracle 集群】Linux下Oracle RAC集群搭建之Oracle DataBase安装(八)...
  4. java 匿名访问权限_java-春季安全性allowAll()不允许匿名访问
  5. 话里话外:装备制造业企业迫切需要实现信息化综合集成
  6. Windows Server 2008 R2 之二十一远程桌面服务RD之二
  7. java paint调用,求教 如何调用这个paint
  8. 一:ActiveMQ知识整理
  9. Win10安装JDK与配置环境变量
  10. python 高阶函数之filter
  11. JavaScript高级技巧
  12. oracle财务系统与erp,浅谈Oracle ERP财务系统在中煤建安集团的应用
  13. c语言自学教程——博文总结
  14. 使用python对微信好友进行数据分析
  15. 解决iOS8下ALAssetsLibrary创建相册的bug
  16. 安卓修改软件安装时间_LaTeX软件安装教程
  17. 用力过猛的“中产阶级教育
  18. 商店卖西瓜 10斤c语言,算法,西瓜切十刀,最多是多少块?
  19. Chango的数学Shader世界(十四)细线间断,发光闪烁,TAA削弱处理
  20. at命令不生效 linux_linux中at命令详解

热门文章

  1. php获取android版本,php-获取Android应用的类别-在服务器端
  2. 有什么实用的电脑录音软件
  3. JavaScript 原型和原型链
  4. CSS基础(3)- 选择器
  5. Java文件压缩工具类ZipUtils学习笔记
  6. 举头望明月打计算机术语,2016年猴年中秋灯谜大全
  7. 利用twitter官网提供的api 及tweepy库 爬取tweets
  8. 你的点子将去往何方,澌灭无闻,还是改变世界?
  9. 无线WIFI网络系统介绍
  10. 页面截图导出为PDF,以及PDF强行截断分页问题的处理