当前位置:   article > 正文

STM32——软件SPI协议解析_stm32软件spi

stm32软件spi

         目录

一、SPI简介        

二、硬件基础

三、SPI基本的通讯单元

0.SPI移位寄存器工作原理:

1.起始条件:

2.终止条件: 

3.交换一个字节:

 四、软件SPI读写STM32F103ZET6板载W25Q16的ID号

1.硬件前提:

2.软件部分: 

1.初始化引脚:

2. 发送9h指令读取ID号。

3.打印在OLED屏幕上:

4.现象:


一、SPI简介        

        SPI的英文全称为Serial Peripheral Interface,是一种通用数据总线。较为重要的端口为MOSI(主机输出,从机输入)、MISO(主机输入,从机输出)、SCL(总线时钟)、CS(片选信号)。

二、硬件基础

        如下图所示,主机的MOSI与从机的SDI(Slave Data Input)相连,主机的MISO与从机的SDO(Slave Data Output),主机片选信号CS与从机片选相连(Chip Select)通常低电平有效,时钟总线相连一起。根据输入输出特性,在软件SPI中,将MOSI、SCL、CS配置为推挽输出将MISO配置成上拉输入即可。

        

三、SPI基本的通讯单元

0.SPI移位寄存器工作原理:

        SPI主机与从机通讯实际上时两者的移位寄存器交换数据的过程,在时钟信号SCL的推动下,主机发送一位,从机也发送一位,两者互换数据,交换8次之后,便完成了一个字节的传输。

        代码前提:

  1. void MySPI_W_CS(uint8_t value)
  2. {
  3. GPIO_WriteBit(SPI_PORT,SPI_CS_PIN,(BitAction)value);
  4. }
  5. void MySPI_W_SCL(uint8_t value)
  6. {
  7. GPIO_WriteBit(SPI_PORT,SPI_SCL_PIN,(BitAction)value);
  8. }
  9. void MySPI_W_MOSI(uint8_t value)
  10. {
  11. GPIO_WriteBit(SPI_PORT,SPI_MOSI_PIN,(BitAction)value);
  12. }
  13. uint8_t MySPI_R_MISO(void )
  14. {
  15. return GPIO_ReadInputDataBit(SPI_PORT,SPI_MISO_PIN);;
  16. }

1.起始条件:

        片选信号由高至低,即选中从机芯片通讯的过程。

  1. void MySPI_Start(void )
  2. {
  3. MySPI_W_CS(0);
  4. }

2.终止条件: 

        片选信号由低至高,即不选从机芯片的过程。

  1. void MySPI_Stop(void )
  2. {
  3. MySPI_W_CS(1);
  4. }

3.交换一个字节:

        介绍一种最常用的通讯模式:CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。

  1. uint8_t MySPI_SwapData(uint8_t Data)
  2. {
  3. uint8_t temp=0x00;
  4. for (int i = 0; i < 8; i++)
  5. {
  6. MySPI_W_MOSI(Data & (0x80>>i));
  7. MySPI_W_SCL(1);
  8. if(MySPI_R_MISO()==1)
  9. {
  10. temp|=(0x80>>i);
  11. }
  12. MySPI_W_SCL(0);
  13. }
  14. return temp;
  15. }

 四、软件SPI读写STM32F103ZET6板载W25Q16的ID号

1.硬件前提:

        多数商家所售STM32F103ZET6自带一块支持SPI通讯的W25Q16,如下图:

        原理图如下:观察可知,所接的PB12、13、14、15也为板上ZET6班上对应的硬件SPI资源,本文中我们使用软件时序模拟SPI。

 

        本文中我们读出该设备ID号 :查看手册可知:MID为EF(十六进制)DID为4015(十六进制)。

2.软件部分: 

1.初始化引脚:

  1. void MySPI_Init(void )
  2. {
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  6. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
  7. GPIO_InitStructure.GPIO_Pin=SPI_CS_PIN|SPI_SCL_PIN|SPI_MOSI_PIN;
  8. GPIO_Init(SPI_PORT,&GPIO_InitStructure);
  9. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  10. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
  11. GPIO_InitStructure.GPIO_Pin=SPI_MISO_PIN;
  12. GPIO_Init(SPI_PORT,&GPIO_InitStructure);
  13. MySPI_W_CS(1);
  14. MySPI_W_SCL(0);
  15. }

2. 发送9h指令读取ID号。

  1. void W25Q16_Init(void )
  2. {
  3. MySPI_Init();
  4. }
  5. void W25Q16_Read_ID(uint8_t* MID,uint16_t* DID)
  6. {
  7. MySPI_Start();
  8. MySPI_SwapData(0x9F);
  9. *MID=MySPI_SwapData(0xFF);
  10. *DID=MySPI_SwapData(0xFF);
  11. *DID<<=8;
  12. *DID|=MySPI_SwapData(0xFF);
  13. MySPI_Stop();
  14. }

3.打印在OLED屏幕上:

  1. #include "main.h"
  2. static int i=0;
  3. int main(void)
  4. {
  5. uint8_t MID=0;
  6. uint16_t DID=0;
  7. uart_init(115200);
  8. delay_init();
  9. OLED_Init();
  10. OLED_Clear();
  11. W25Q16_Init();
  12. W25Q16_Read_ID(&MID,&DID);
  13. while(1)
  14. {
  15. for (; i < 1; ++i) {
  16. OLED_Init();
  17. OLED_Clear();
  18. }
  19. OLED_ShowString(1,0,"MID:",16);
  20. OLED_ShowString(1,2,"DID:",16);
  21. OLED_ShowHexNum(40,0,MID,2);
  22. OLED_ShowHexNum(40,2,DID,4);
  23. }
  24. return 0;
  25. }

4.现象:

        符合最终的现象,正确读出设备ID号!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/826617
推荐阅读
相关标签
  

闽ICP备14008679号