当前位置:   article > 正文

STM32F103C8T6主从机SPI通信_stm32f103c8t6 st7565 spi1

stm32f103c8t6 st7565 spi1

SPI协议:

        SPI协议是串行外设接口的缩写,是美国摩托罗拉公司最先推出的一种同步串行传输规范,也是一种单片机外设芯片串行扩展接口,是一种高速、全双工、同步通信总线,所以可以在同一时间发送和接收数据,SPI没有定义速度限制,通常能达到甚至超过10M/bps。使用SPI通信需要四根线:MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)和CS/SS(片选),CS/SS为从设备使能信号,由主设备控制。

准备两块STM32F103C8T6单片机,两条USB转TTL下载线

串口下载工具,串口调试工具

主机发送函数:

  1. void SPI_Master_Init(void)
  2. {
  3. //初始化GPIO引脚
  4. GPIO_InitTypeDef GPIO_InitStruct;
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
  6. //配置SCK和MOSI引脚为复用推挽输出
  7. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
  8. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
  9. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  10. GPIO_Init(GPIOA,&GPIO_InitStruct);
  11. //配置MISO引脚为浮空输入
  12. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;
  13. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  14. GPIO_Init(GPIOA,&GPIO_InitStruct);
  15. //配置CS引脚为输出
  16. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;
  17. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
  18. GPIO_Init(GPIOA,&GPIO_InitStruct);
  19. //初始化SPI主机
  20. SPI_InitTypeDef SPI_InitStruct;
  21. SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工模式
  22. SPI_InitStruct.SPI_Mode = SPI_Mode_Master; //主模式
  23. SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; //8位数据
  24. SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; //时钟极性为低电平
  25. SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; //时钟相位为第一个时钟沿
  26. SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; //软件控制片选信号
  27. SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //波特率预分频值256
  28. SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; //最高有效位先传输
  29. SPI_InitStruct.SPI_CRCPolynomial = 7; //设置CRC多项式
  30. SPI_Init(SPI1,&SPI_InitStruct); //SPI初始化
  31. SPI_Cmd(SPI1, ENABLE); //使能SPI外设
  32. }
  33. void SPI_Master_Send(uint8_t data)
  34. {
  35. //等待发送缓冲区为空
  36. while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
  37. //发送数据
  38. SPI_I2S_SendData(SPI1, data);
  39. }
  40. uint8_t SPI_Master_Receive(void)
  41. {
  42. //等待接收缓冲区非空
  43. while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
  44. //读取接收数据
  45. return SPI_I2S_ReceiveData(SPI1);
  46. }

从机接收函数:

  1. //SPI从机初始化
  2. void SPI_Slave_Init(void)
  3. {
  4. // 初始化GPIO引脚
  5. GPIO_InitTypeDef GPIO_InitStructure;
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
  7. // 配置SCK、MISO和MOSI引脚为复用推挽输出
  8. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  9. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  10. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  11. GPIO_Init(GPIOA, &GPIO_InitStructure);
  12. // 配置CS引脚为浮空输入
  13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  14. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  15. GPIO_Init(GPIOA, &GPIO_InitStructure);
  16. //初始化SPI主机
  17. SPI_InitTypeDef SPI_InitStruct;
  18. SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工模式
  19. SPI_InitStruct.SPI_Mode = SPI_Mode_Slave; //从模式
  20. SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; //8位数据
  21. SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; //时钟极性为低电平
  22. SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; //时钟相位为第一个时钟沿
  23. SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; //软件控制片选信号
  24. SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //波特率预分频值256
  25. SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; //最高有效位先传输
  26. SPI_InitStruct.SPI_CRCPolynomial = 7; //设置CRC多项式
  27. SPI_Init(SPI1,&SPI_InitStruct); //SPI初始化
  28. SPI_Cmd(SPI1, ENABLE); //使能SPI外设
  29. }
  30. void SPI_Slave_Receive(void)
  31. {
  32. // 等待接收到数据
  33. while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
  34. // 读取接收缓冲区数据
  35. return SPI_I2S_ReceiveData(SPI1);
  36. }
  37. void SPI_Slave_Send(uint8_t data)
  38. {
  39. //等待发送缓冲区为空
  40. while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
  41. //发送数据
  42. SPI_I2S_SendData(SPI1, data);
  43. }

主机main函数测试

  1. uint8_t sendData = 0x11;
  2. uint8_t receivedData;
  3. while(1)
  4. {
  5. printf("我是主机\r\n");
  6. SPI_Master_Send(sendData);
  7. receivedData = SPI_Master_Receive();
  8. printf("主机发送的消息是:0x%02X\r\n", sendData);
  9. printf("接收从机的消息是:0x%02X\r\n", receivedData);
  10. }

从机main函数测试

  1. uint8_t sendData = 0x22;
  2. uint8_t receivedData;
  3. while(1)
  4. {
  5. printf("我是从机\r\n");
  6. receivedData = SPI_Slave_Receive();
  7. printf("接收主机的消息是:0x%02X\r\n", receiveData);
  8. SPI_Slave_Send(sendData);
  9. printf("从机发送的消息是:0x%02X\r\n", senddData);
  10. }

程序烧录好后,用杜邦线将主从机配置SPI的GPIO引脚相连,打开两个串口助手查看显示效果。

注意:

       1. 使用SPI主从机数据传输,如果在发送或接收数据后要添加延时函数,需要确保主从机延时一致,否则传递的数据容易发生漂移。 

        2.主机先发送,从机后接收。传递浮点型数据容易丢失小数位,可以考虑小数位放大倍数传递,或者转换成字符串的方式传递。

        SPI主从机通信,主要可以用于解决日常MCU产品设计中串口不够用,而设计成本有限不能更换芯片的问题,除了这种简单的方式,还可以使用软件模拟串口的方式,将GPIO口通过配置定时器来达到模拟串口通信的方式。

        本文仅供学习交流!

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

闽ICP备14008679号