当前位置:   article > 正文

STM32—SPI通信_stm32 spi模式3

stm32 spi模式3

1.SPI简介

四根通信线:SCK(Serial Clock)(时钟线)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、SS(Slave Select)

同步、全双工

支持总线挂载多设备(一主多从)

所有SPI设备的SCK、MOSI、MISO分别连在一起

主机另外引出多条SS控制线(低电平有效),分别接到各从机的SS引脚

输出引脚配置为推挽输出,输入引脚配置为浮空或上拉输入

 

2.SPI时序基本单元 

起始条件:SS从高电平切换到低电平

终止条件:SS从低电平切换到高电平

 

交换一个字节(模式0)

CPOL = 0:空闲状态,SCK为低电平

CPHA = 0:SCK第一个边沿移入数据,第二个边沿移出数据 

交换一个字节(模式1)

CPOL = 0:空闲状态,SCK为低电平

CPHA = 1:SCK第一个边沿移出数据,第二个边沿移入数据

交换一个字节(模式2)

CPOL = 1:空闲状态,SCK为高电平

CPHA = 0:SCK第一个边沿移入数据,第二个边沿移出数据

 

交换一个字节(模式3)

CPOL = 1:空闲状态,SCK为高电平

CPHA = 1:SCK第一个边沿移出数据,第二个边沿移入数据

3.SPI外设简介

STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担

可配置8位/16位数据帧、高位先行/低位先行

时钟频率:f_{PCLK} / (2,4,8,16,32,64,128,256)

支持多主机模型、主或从模式

可精简为半双工/单工通信

支持DMA

兼容I2S协议

 

4.SPI基本结构

 

 

 

5.SPI相关标准库函数简介

  1. //恢复缺省配置
  2. void SPI_I2S_DeInit(SPI_TypeDef* SPIx);
  3. //初始化
  4. void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
  5. //给结构体变量默认值
  6. void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct);
  7. //SPI使能
  8. void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
  9. //中断使能
  10. void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);
  11. //DMA使能
  12. void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);
  1. //写DR数据寄存器
  2. void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
  3. //读DR数据寄存器
  4. uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
  1. //获取标志位
  2. FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
  3. //清除标志位
  4. void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
  5. //获取中断标志位
  6. ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
  7. //清除中断标志位
  8. void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);

6.案例

6.1软件SPI读写W25Q64

  1. #include "stm32f10x.h" // Device header
  2. void MySPI_W_SS(uint8_t BitValue)
  3. {
  4. GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
  5. }
  6. void MySPI_W_SCK(uint8_t BitValue)
  7. {
  8. GPIO_WriteBit(GPIOA,GPIO_Pin_5,(BitAction)BitValue);
  9. }
  10. void MySPI_W_MOSI(uint8_t BitValue)
  11. {
  12. GPIO_WriteBit(GPIOA,GPIO_Pin_7,(BitAction)BitValue);
  13. }
  14. uint8_t MySPI_R_MISO(void)
  15. {
  16. return GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6);
  17. }
  18. void MySPI_Init(void)
  19. {
  20. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  21. GPIO_InitTypeDef GPIO_InitStructure;
  22. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  23. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
  24. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  25. GPIO_Init(GPIOA,&GPIO_InitStructure);
  26. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  27. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  28. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  29. GPIO_Init(GPIOA,&GPIO_InitStructure);
  30. MySPI_W_SS(1);
  31. MySPI_W_SCK(0);
  32. }
  33. void MySPI_Start(void)
  34. {
  35. MySPI_W_SS(0);
  36. }
  37. void MySPI_Stop(void)
  38. {
  39. MySPI_W_SS(1);
  40. }
  41. uint8_t MySPI_SwapByte(uint8_t ByteSend)
  42. {
  43. uint8_t ByteReceive = 0x00;
  44. for(uint8_t i = 0;i < 8;i++)
  45. {
  46. MySPI_W_MOSI(ByteSend & (0x80 >> i));
  47. MySPI_W_SCK(1);
  48. if (MySPI_R_MISO() == 1){ByteReceive |= (0x80 >> i);}
  49. MySPI_W_SCK(0);
  50. }
  51. return ByteReceive;
  52. }
  53. //uint8_t MySPI_SwapByte(uint8_t ByteSend)
  54. //{
  55. // uint8_t ByteReceive = 0x00;
  56. //
  57. // for(uint8_t i = 0;i < 8;i++)
  58. // {
  59. // MySPI_W_MOSI(ByteSend & (0x80 >> i));
  60. // ByteSend <<= 1;
  61. // MySPI_W_SCK(1);
  62. // if (MySPI_R_MISO() == 1){ByteReceive |= 0x01;}
  63. // MySPI_W_SCK(0);
  64. // }
  65. // return ByteReceive;
  66. //}
  1. #include "stm32f10x.h" // Device header
  2. #include "MySPI.h"
  3. #include "W25Q64_Ins.h"
  4. void W25Q64_Init(void)
  5. {
  6. MySPI_Init();
  7. }
  8. void W25Q64_ReadID(uint8_t *MID,uint16_t *DID)
  9. {
  10. MySPI_Start();
  11. MySPI_SwapByte(W25Q64_JEDEC_ID);
  12. *MID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
  13. *DID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
  14. *DID <<= 8;
  15. *DID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE);
  16. MySPI_Stop();
  17. }
  18. void W25Q64_WriteEnable(void)
  19. {
  20. MySPI_Start();
  21. MySPI_SwapByte(W25Q64_WRITE_ENABLE);
  22. MySPI_Stop();
  23. }
  24. void W25Q64_WaitBusy(void)
  25. {
  26. uint32_t Timeout = 100000;
  27. MySPI_Start();
  28. MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1);
  29. while ((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01)
  30. {
  31. Timeout --;
  32. if(Timeout == 0)
  33. {
  34. break;
  35. }
  36. }
  37. MySPI_Stop();
  38. }
  39. void W25Q64_PageProgram(uint32_t Address,uint8_t *DataArray,uint16_t Cout)
  40. {
  41. W25Q64_WriteEnable();
  42. MySPI_Start();
  43. MySPI_SwapByte(W25Q64_PAGE_PROGRAM);
  44. MySPI_SwapByte(Address >> 16);
  45. MySPI_SwapByte(Address >> 8);
  46. MySPI_SwapByte(Address);
  47. for (uint16_t i = 0;i < Cout;i++)
  48. {
  49. MySPI_SwapByte(DataArray[i]);
  50. }
  51. MySPI_Stop();
  52. W25Q64_WaitBusy();
  53. }
  54. void W25Q64_SectorErase(uint32_t Address)
  55. {
  56. W25Q64_WriteEnable();
  57. MySPI_Start();
  58. MySPI_SwapByte(W25Q64_SECTOR_ERASE_4KB);
  59. MySPI_SwapByte(Address >> 16);
  60. MySPI_SwapByte(Address >> 8);
  61. MySPI_SwapByte(Address);
  62. MySPI_Stop();
  63. W25Q64_WaitBusy();
  64. }
  65. void W25Q64_ReadData(uint32_t Address,uint8_t *DataArray,uint32_t Cout)
  66. {
  67. MySPI_Start();
  68. MySPI_SwapByte(W25Q64_READ_DATA);
  69. MySPI_SwapByte(Address >> 16);
  70. MySPI_SwapByte(Address >> 8);
  71. MySPI_SwapByte(Address);
  72. for(uint32_t i = 0;i < Cout;i++)
  73. {
  74. DataArray[i] = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
  75. }
  76. MySPI_Stop();
  77. }

6.2硬件SPI读写W25Q64

  1. #include "stm32f10x.h" // Device header
  2. void MySPI_W_SS(uint8_t BitValue)
  3. {
  4. GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
  5. }
  6. void MySPI_Init(void)
  7. {
  8. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  9. RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);
  10. GPIO_InitTypeDef GPIO_InitStructure;
  11. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  13. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  14. GPIO_Init(GPIOA,&GPIO_InitStructure);
  15. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  16. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
  17. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18. GPIO_Init(GPIOA,&GPIO_InitStructure);
  19. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  20. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  21. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22. GPIO_Init(GPIOA,&GPIO_InitStructure);
  23. SPI_InitTypeDef SPI_InitStructure;
  24. //SPI模式
  25. SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  26. //配置SPI裁剪引脚,当前选择为双线全双工
  27. SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  28. //配置8位还是16位数据帧
  29. SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  30. //选择低位先行还是高位先行
  31. SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  32. //波特率预分频器,配置SCK时钟的频率
  33. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
  34. //配置SPI模式
  35. SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  36. //配置SPI模式
  37. SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  38. SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  39. //CRC校验,当前所给为默认值
  40. SPI_InitStructure.SPI_CRCPolynomial = 7;
  41. SPI_Init(SPI1,&SPI_InitStructure);
  42. SPI_Cmd(SPI1,ENABLE);
  43. MySPI_W_SS(1);
  44. }
  45. void MySPI_Start(void)
  46. {
  47. MySPI_W_SS(0);
  48. }
  49. void MySPI_Stop(void)
  50. {
  51. MySPI_W_SS(1);
  52. }
  53. uint8_t MySPI_SwapByte(uint8_t ByteSend)
  54. {
  55. while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) != SET);
  56. SPI_I2S_SendData(SPI1,ByteSend);
  57. while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) != SET);
  58. return SPI_I2S_ReceiveData(SPI1);
  59. }
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号