【物联网】了解SPI通信:串行外设接口的基本工作原理,51、stm32实现SPI

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上运维知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注运维)
img

正文

- 配置SPI控制器的工作模式(主模式或从模式)并设置相应的时钟极性和相位。
   - 配置SPI控制器的数据大小(8位或16位)。
   - 配置SPI控制器的时钟频率。
   - 使能SPI控制器。

  1. 选中从设备:
       - 将片选引脚拉低(具体引脚根据硬件连接决定),选中要进行通信的从设备。

  2. 数据传输:
       - 主设备向SPI数据寄存器写入要发送的数据。
       - 等待数据传输完成,可以通过查询状态寄存器的标志位或中断的方式来判断。
       - 从设备接收数据后,可以通过从SPI数据寄存器中读取数据。

  3. 解选从设备:
       - 将片选引脚拉高,解选从设备。

#include <reg51.h>

// 初始化SPI控制器
void SPI_Init()
{
  // 配置SPI控制器的工作模式、时钟极性和相位、数据大小等
  // ...
}

// 选中从设备
void SPI_SelectSlave()
{
  // 将片选引脚拉低,选中从设备
  // ...
}

// 解选从设备
void SPI_DeselectSlave()
{
  // 将片选引脚拉高,解选从设备
  // ...
}

// 主设备发送和接收数据
unsigned char SPI_Transfer(unsigned char txData)
{
  // 先将要发送的数据写入SPI数据寄存器
  SPDR = txData;

  // 等待数据传输完成
  while ((SPSR & (1 << SPIF)) == 0)
  {
    // 等待数据传输完成
  }

  // 从SPI数据寄存器中读取接收到的数据
  return SPDR;
}

int main()
{
  // 初始化SPI控制器
  SPI_Init();

  // 选中从设备
  SPI_SelectSlave();

  // 发送和接收数据
  unsigned char txData = 0xAA;
  unsigned char rxData = SPI_Transfer(txData);

  // 解选从设备
  SPI_DeselectSlave();

  while (1)
  {
    // 主循环
  }
}

2. STM32使用HAL库开发SPI通信

实现的步骤:

使用STM32实现SPI通信需要以下步骤:

  1. 配置GPIO引脚:首先,您需要在STM32微控制器上配置SPI相关的GPIO引脚。这些引脚用于连接SPI总线和外部器件。您需要根据具体的STM32型号和使用的引脚进行配置。

  2. 初始化SPI控制器:使用STM32的HAL库或CubeMX软件工具,您可以初始化SPI控制器。这包括设置SPI模式(主设备或从设备)、位传输顺序、数据大小等参数。

  3. 配置时钟和速率:设置SPI的时钟源和通信速率。您可以根据需求选择适当的时钟源和速率配置。

  4. 选中从设备:如果您是主设备,您需要通过控制SPI的片选引脚(SS引脚)来选中要与之通信的从设备。将相应的片选引脚置低以选择从设备。

  5. 传输数据:使用SPI的数据寄存器将数据发送到外部器件,并接收器件返回的数据。

#include "stm32f4xx_hal.h"

SPI_HandleTypeDef hspi;

// SPI初始化函数
void SPI_Init(void)
{
  hspi.Instance = SPI1; // 根据实际情况选择SPI外设
  hspi.Init.Mode = SPI_MODE_MASTER; // 主设备模式
  hspi.Init.Direction = SPI_DIRECTION_2LINES; // 全双工通信模式
  hspi.Init.DataSize = SPI_DATASIZE_8BIT; // 数据大小为8位
  hspi.Init.CLKPolarity = SPI_POLARITY_LOW; // 时钟极性低
  hspi.Init.CLKPhase = SPI_PHASE_1EDGE; // 时钟相位第一边沿
  hspi.Init.NSS = SPI_NSS_SOFT; // 通过软件方式控制片选引脚
  hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; // 时钟预分频器256
  hspi.Init.FirstBit = SPI_FIRSTBIT_MSB; // 高位先传输
  hspi.Init.TIMode = SPI_TIMODE_DISABLE; // 不使用TI模式
  hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // 不使用SPI校验功能
  hspi.Init.CRCPolynomial = 10; // 不使用SPI校验功能
  if (HAL_SPI_Init(&hspi) != HAL_OK)
  {
    Error_Handler();
  }
}

// 主设备发送和接收数据函数
void SPI_Transfer(uint8_t* txData, uint8_t* rxData, uint16_t size)
{
  HAL_SPI_TransmitReceive(&hspi, txData, rxData, size, HAL_MAX_DELAY);
}

int main(void)
{
  // 系统初始化
  
  // 配置SPI引脚
  
  // 初始化SPI控制器
  SPI_Init();

  // 主设备选中从设备
  HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_RESET);

  // 发送和接收数据
  uint8_t txData[] = {0xAA, 0xBB, 0xCC};
  uint8_t rxData[3];
  SPI_Transfer(txData, rxData, 3);

  // 主设备取消选中从设备
  HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port, SPI1_NSS_Pin, GPIO_PIN_SET);

  while (1)
  {
    // 主循环
  }
}

3. STM32使用标准库开发SPI通信

#include "stm32f4xx.h"

// SPI初始化函数
void SPI_Init(void)
{
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  
  SPI_InitTypeDef spiInit;
  spiInit.SPI_Mode = SPI_Mode_Master;
  spiInit.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  spiInit.SPI_DataSize = SPI_DataSize_8b;
  spiInit.SPI_CPOL = SPI_CPOL_Low;
  spiInit.SPI_CPHA = SPI_CPHA_1Edge;
  spiInit.SPI_NSS = SPI_NSS_Soft;
  spiInit.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
  spiInit.SPI_FirstBit = SPI_FirstBit_MSB;
  spiInit.SPI_CRCPolynomial = 7;
  SPI_Init(SPI1, &spiInit);
  
  SPI_Cmd(SPI1, ENABLE);
}

// 主设备发送和接收数据函数
void SPI_Transfer(uint8_t* txData, uint8_t* rxData, uint16_t size)
{
  for (uint16_t i = 0; i < size; i++)
  {
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
    {
      // 等待发送缓冲区空
    }
    
    SPI_I2S_SendData(SPI1, txData[i]);
    
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
    {
      // 等待接收缓冲区非空
    }
    
    rxData[i] = SPI_I2S_ReceiveData(SPI1);
  }
}

int main(void)
{
  // 系统初始化
  
  // 配置SPI引脚
  
  // 初始化SPI控制器
  SPI_Init();

  // 主设备选中从设备
  GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_RESET);

  // 发送和接收数据
  uint8_t txData[] = {0xAA, 0xBB, 0xCC};
  uint8_t rxData[3];
  SPI_Transfer(txData, rxData, 3);

  // 主设备取消选中从设备
  GPIO_WriteBit(GPIOA, GPIO_Pin_4, Bit_SET);
  
  while (1)
  {
    // 主循环
  }
}

以上代码使用了标准库提供的函数进行SPI控制器的初始化和数据传输。在SPI传输函数SPI\_Transfer中,我们通过查询标志位的方式判断发送和接收缓冲区的状态,并使用SPI\_I2S\_SendDataSPI\_I2S\_ReceiveData函数发送和接收数据。

七、总结

SPI通信是一种常用的串行通信协议,用于微控制器和外部器件之间的通信。它具有全双工、同步、串行和硬件控制等特点,可以通过少量的引脚连接实现高速数据传输。

在进行SPI通信时,主设备驱动模式下主设备控制整个通信过程,而从设备驱动模式下每个从设备在主设备的控制下依次发送和接收数据。

SPI通信被广泛应用于各种嵌入式系统和电子设备中,特别是在与外部器件交互的场景中,如存储器扩展、传感器和执行器、显示设备、网络通信模块、音频设备等。

为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!

这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。

本份面试集锦涵盖了

  • 174 道运维工程师面试题
  • 128道k8s面试题
  • 108道shell脚本面试题
  • 200道Linux面试题
  • 51道docker面试题
  • 35道Jenkis面试题
  • 78道MongoDB面试题
  • 17道ansible面试题
  • 60道dubbo面试题
  • 53道kafka面试
  • 18道mysql面试题
  • 40道nginx面试题
  • 77道redis面试题
  • 28道zookeeper

总计 1000+ 道面试题, 内容 又全含金量又高

  • 174道运维工程师面试题

1、什么是运维?

2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?

3、现在给你三百台服务器,你怎么对他们进行管理?

4、简述raid0 raid1raid5二种工作模式的工作原理及特点

5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

7、Tomcat和Resin有什么区别,工作中你怎么选择?

8、什么是中间件?什么是jdk?

9、讲述一下Tomcat8005、8009、8080三个端口的含义?

10、什么叫CDN?

11、什么叫网站灰度发布?

12、简述DNS进行域名解析的过程?

13、RabbitMQ是什么东西?

14、讲一下Keepalived的工作原理?

15、讲述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注运维)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注运维)
[外链图片转存中…(img-zgzizPeP-1713206750950)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 27
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值