[RISC-V MCU 应用开发] 第五十一章、CH32V103应用教程——SPI-全双工通信,硬件控...

[复制链接]
 楼主| RISCVLAR 发表于 2021-1-12 19:58 | 显示全部楼层 |阅读模式
本帖最后由 RISCVLAR 于 2021-1-12 19:58 编辑

CH32V103应用教程——SPI-全双工通信,硬件控制NSS模式

本章教程主要在SPI双线全双工模式下进行主从收发实验,并采用硬件控制NSS方式。

1、SPI简介及相关函数介绍
关于SPI主从模式下的全双工发送和接收数据,其软件配置过程在第50章已经介绍,在此不再赘述。
关于CH32V103 SPI具体信息,可参考CH32V103应用手册。SPI标准库函数在第十五章节已介绍,在此不再赘述。

2、硬件设计
本章教程主要进行SPI主从模式下的全双工发送和接收数据,需用到两个开发板,且由于采用全双工模式,因此主设备和从设备均要使用MOSI引脚和MISO引脚以及SCK引脚进行通讯。此处使用外设为SPI1,主设备和从设备MOSI对应引脚均为PA7引脚、MISO对应引脚均为PA6引脚,将主设备PA6、PA7引脚与从设备PA6、PA7引脚一一对应连接起来,此外还需将两个开发板SPI1对应的SCK引脚PA5连接起来,且由于采用硬件控制NSS方式,因此需要将两个开发板对应NSS引脚PA4连接起来。
此外,由于两个开发板需要同时进行上电传输,因此将两个开发板的3.3V引脚和GND引脚进行连接。

3软件设计
本章教程主要进行SPI主从模式下的全双工发送和接收数据,且采用硬件控制NSS方式,具体程序如下:
spi.h文件
  1. #ifndef __SPI_H
  2. #define __SPI_H

  3. #include "ch32v10x_conf.h"

  4. /* SPI Mode Definition */
  5. #define HOST_MODE    0
  6. #define SLAVE_MODE   1

  7. /* SPI Communication Mode Selection */
  8. //#define SPI_MODE   HOST_MODE
  9. #define SPI_MODE   SLAVE_MODE

  10. #define  Size  18

  11. extern u16 TxData[Size];
  12. extern u16 RxData[Size];

  13. void SPI_FullDuplex_Init(void);

  14. #endif
spi.c文件
  1. #include "spi.h"

  2. /* Global Variable */

  3. u16 TxData[Size] = { 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606,
  4.                      0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616,
  5.                      0x2121, 0x2222, 0x2323, 0x2424, 0x2525, 0x2626 };
  6. u16 RxData[Size];

  7. /*******************************************************************************
  8. * Function Name  : SPI_FullDuplex_Init
  9. * Description    : Configuring the SPI for full-duplex communication.
  10. * Input          : None
  11. * Return         : None
  12. *******************************************************************************/
  13. void SPI_FullDuplex_Init(void)
  14. {
  15.     GPIO_InitTypeDef GPIO_InitStructure;
  16.     SPI_InitTypeDef SPI_InitStructure;

  17.     RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE );

  18. #if (SPI_MODE == HOST_MODE)
  19.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  20.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  21.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  23.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  24.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  25.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  26.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  27.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  28.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  29.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  30.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  31.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  32.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  33.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  34. #elif (SPI_MODE == SLAVE_MODE)
  35.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  36.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  37.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  38.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  39.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  40.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  41.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  42.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  43.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  44.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  45.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  46.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  47.     GPIO_Init( GPIOA, &GPIO_InitStructure );

  48. #endif

  49.     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

  50. #if (SPI_MODE == HOST_MODE)
  51.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

  52. #elif (SPI_MODE == SLAVE_MODE)
  53.     SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;

  54. #endif

  55.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
  56.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  57.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  58.     SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
  59.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
  60.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
  61.     SPI_InitStructure.SPI_CRCPolynomial = 7;
  62.     SPI_Init( SPI1, &SPI_InitStructure );

  63.     SPI_SSOutputCmd( SPI1, ENABLE );

  64.     SPI_Cmd( SPI1, ENABLE );
  65. }
spi.c文件主要包括1个函数:SPI_FullDuplex_Init函数。SPI_FullDuplex_Init函数主要进行SPI1全双工通信模式下的主机和从机配置。首先,由于采用全双工通信方式,且采用硬件控制NSS引脚,因此需要对主机和从机的NSS引脚、SCK引脚、MOSI引脚和MISO引脚进行GPIO初始化配置。此外,还需要进行主机和从机配置,此配置可根据CH32V103应用手册主模式和从模式配置步骤进行,主要对SPI通信的通信方向、主从模式、数据帧大小、时钟极性、时钟相位、NSS引脚使用方式、波特率等进行配置,可对照手册参考标准库函数ch32v10x_spi.c文件中SPI_Init函数进行配置。
main.c文件
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : main.c
  3. * Author             : WCH
  4. * Version            : V1.0.0
  5. * Date               : 2020/04/30
  6. * Description        : Main program body.
  7. *******************************************************************************/

  8. #include "debug.h"
  9. #include "spi.h"
  10. #include "string.h"

  11. /*
  12. *@Note
  13. 硬件NSS模式,Master/Slave 模式数据收发:
  14. Master:SPI1_NSS(PA4)、SPI1_SCK(PA5)、SPI1_MISO(PA6)、SPI1_MOSI(PA7)。
  15. Slave :SPI1_NSS(PA4)、SPI1_SCK(PA5)、SPI1_MISO(PA6)、SPI1_MOSI(PA7)。

  16. 本例程演示在硬件 NSS 模式下,Master 和 Slave 同时全双工收发。
  17. 注:两块板子分别下载 Master 和 Slave 程序,同时上电。
  18.        硬件连线:PA4 —— PA4
  19.             PA5 —— PA5
  20.             PA6 —— PA6
  21.             PA7 —— PA7
  22. */
  23. /*******************************************************************************
  24. * Function Name  : main
  25. * Description    : Main program.
  26. * Input          : None
  27. * Return         : None
  28. *******************************************************************************/
  29. int main(void)
  30. {
  31.     u8 i=0;
  32.     u8 j=0;
  33.     u8 value;

  34.     Delay_Init();
  35.     USART_Printf_Init(115200);
  36.     printf("SystemClk:%d\r\n",SystemCoreClock);

  37. #if (SPI_MODE == SLAVE_MODE)
  38.     printf("Slave Mode\r\n");
  39.     Delay_Ms(1000);

  40. #endif

  41.     SPI_FullDuplex_Init();

  42. #if (SPI_MODE == HOST_MODE)
  43.     printf("Host Mode\r\n");
  44.     Delay_Ms(2000);

  45. #endif

  46.     while(1)
  47.     {
  48.         while( ( i<18 ) || ( j<18 ))
  49.         {
  50.             if( i<18 )
  51.             {
  52.                 if( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_TXE ) != RESET )
  53.                 {
  54.                     SPI_I2S_SendData( SPI1, TxData[i] );
  55.                     i++;
  56.                 }
  57.             }

  58.             if( j<18 )
  59.             {
  60.                 if( SPI_I2S_GetFlagStatus( SPI1, SPI_I2S_FLAG_RXNE ) != RESET )
  61.                 {
  62.                     RxData[j] = SPI_I2S_ReceiveData( SPI1 );
  63.                     j++;
  64.                 }
  65.             }
  66.         }

  67.         for( i=0; i<18; i++ )
  68.         {
  69.          printf( "Rxdata:%04x\r\n", RxData[i] );
  70.         }

  71.         value = memcmp( TxData, RxData, Size );

  72.         if( value == 0 )
  73.         {
  74.             printf( "Same\r\n" );
  75.         }
  76.         else
  77.         {
  78.             printf( "Different\r\n" );
  79.         }

  80.         while(1);
  81.     }
  82. }

main.c文件主要进行主机和从机下的数据发送和接收。并将接收数据与发送数据进行对比,当发送数据与接收数据相同,输出same,若不同,输出different。

4下载验证
将编译好的程序分别在主机模式和从机模式下下载到两个开发版,并将主机的引脚与从机的引脚一一对应进行连接,开发板上电后,串口打印如下:
主机打印:
图片1.png
从机打印:
图片2.png




  

50、SPI-全双工模式,硬件控制NSS.rar

477.45 KB, 下载次数: 18

gejigeji521 发表于 2021-2-22 12:02 | 显示全部楼层
SPI还有全双工,半双工模式之分吗,看看。
单片小菜 发表于 2021-2-23 15:25 | 显示全部楼层
SPI的全双工的和半双工是怎么界定的?

评论

SPI单工通信使用1条时钟线和一条数据线,具体区别可看相关手册  发表于 2021-2-23 16:02
自己造声卡 发表于 2021-2-23 16:30 | 显示全部楼层
感谢楼主的分享,我需要仔细的夯实一下基础知识了,好多东西已经忘记了。
elephant00 发表于 2021-3-16 14:39 | 显示全部楼层

感谢楼主的分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

133

主题

296

帖子

45

粉丝
快速回复 在线客服 返回列表 返回顶部

133

主题

296

帖子

45

粉丝
快速回复 在线客服 返回列表 返回顶部