查看: 1308|回复: 0
收起左侧

第五十章:SPI-全双工通信,软件控制NSS模式

[复制链接]

  离线 

  • TA的每日心情
    慵懒
    2021-7-23 17:16
  • 签到天数: 17 天

    [LV.4]

    发表于 2021-4-28 20:40:39 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 草帽王子 于 2021-9-10 17:40 编辑

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


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


    1、SPI简介及相关函数介绍

    关于SPI主从模式下的全双工发送和接收数据,其软件配置过程如下:
    1、设置SPI控制寄存器1(SPIx_CTLR1)位6 SPE位置1,启用SPI;
    2、在SPI数据寄存器(SPIx_DATAR)中写入第一个要发送的数据,此操作会清除SPI状态寄存器(SPI_SR)位1 TXE标志;
    3、当SPI状态寄存器(SPI_SR)位1 TXE标志为1(表示发送缓冲区为空),写入第二个要发送的数据;当SPI状态寄存器(SPI_SR)位0 RXNE标志为1(表示接收缓冲区非空),读SPI数据寄存器(SPIx_DATAR)中的数据并同时清除RXNE标志位。重复上述操作,发送后续数据并同时接收后续数据(n-1个);
    4、等待SPI状态寄存器(SPI_SR)位0 RXNE标志为1(表示接收缓冲区非空),接收最后一个数据;
    5、等待SPI状态寄存器(SPI_SR)位1 TXE标志位为1,在位7BSY标志位置0(SPI不在通讯)后关闭SPI模块。

    注:也可以在响应RXNE或TXE标志的上升沿产生的中断的处理程序中实现这个过程。

    关于CH32V103 SPI具体信息,可参考CH32V103应用手册。SPI标准库函数在第十五章节已介绍,在此不再赘述。


    2、硬件设计

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


    3、软件设计

    本章教程主要进行SPI主从模式下的全双工发送和接收数据,具体程序如下:

    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_5;
    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_6;
    24.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    25.     GPIO_Init( GPIOA, &GPIO_InitStructure );

    26.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    27.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    28.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    29.     GPIO_Init( GPIOA, &GPIO_InitStructure );

    30. #elif (SPI_MODE == SLAVE_MODE)
    31.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    32.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    33.     GPIO_Init( GPIOA, &GPIO_InitStructure );

    34.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    35.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    36.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    37.     GPIO_Init( GPIOA, &GPIO_InitStructure );

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

    41. #endif

    42.     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //全双工模式

    43. #if (SPI_MODE == HOST_MODE)
    44.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

    45. #elif (SPI_MODE == SLAVE_MODE)
    46.     SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;

    47. #endif

    48.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
    49.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    50.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    51.     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;  //软件控制NSS
    52.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
    53.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
    54.     SPI_InitStructure.SPI_CRCPolynomial = 7;
    55.     SPI_Init( SPI1, &SPI_InitStructure );

    56.     SPI_Cmd( SPI1, ENABLE );
    57. }

    复制代码


    spi.c文件主要包括1个函数:SPI_FullDuplex_Init函数。SPI_FullDuplex_Init函数主要进行SPI1全双工通信模式下的主机和从机配置。首先,由于采用全双工通信方式,且采用软件控制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. 双线全双工模式,Master/Slave 模式数据收发:
    14. Master:SPI1_SCK(PA5)、SPI1_MISO(PA6)、SPI1_MOSI(PA7)。
    15. Slave :SPI1_SCK(PA5)、SPI1_MISO(PA6)、SPI1_MOSI(PA7)。

    16. 本例程演示 Master 和 Slave 同时全双工收发。
    17. 注:两块板子分别下载 Master 和 Slave 程序,同时上电。
    18.        硬件连线:PA5 —— PA5
    19.             PA6 —— PA6
    20.             PA7 —— PA7

    21. */

    22. /*******************************************************************************
    23. * Function Name  : main
    24. * Description    : Main program.
    25. * Input          : None
    26. * Return         : None
    27. *******************************************************************************/
    28. int main(void)
    29. {
    30.     u8 i=0;
    31.     u8 j=0;
    32.     u8 value;

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

    36.     SPI_FullDuplex_Init();

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

    40. #endif

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

    44. #endif

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

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

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

    70.         //将发送数据与接收数据进行比较,若相同,返回0,不同,则返回1
    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、下载验证

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

    主机打印:
    CH32V CH573单片机芯片-第五十章:SPI-全双工通信,软件控制NSS模式risc-v单片机中文社区(1)

    从机打印:
    CH32V CH573单片机芯片-第五十章:SPI-全双工通信,软件控制NSS模式risc-v单片机中文社区(2)

    49、SPI-全双工模式,软件控制NSS.rar
    CH32V CH573单片机芯片-第五十章:SPI-全双工通信,软件控制NSS模式risc-v单片机中文社区(3) 49、SPI-全双工模式,软件控制NSS.rar (474.87 KB, 下载次数: 10)
    链接:https://pan.baidu.com/s/11zewNhVrvJKVuqqCQTm0QQ
    提取码:53d9
    复制这段内容后打开百度网盘手机App,操作更方便哦







    上一篇:第四十九章:SPI-单工通信(1条时钟线和1条单向数据线)
    下一篇:第五十一章:SPI-全双工通信,硬件控制NSS模式
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-4-19 01:51 , Processed in 0.902591 second(s), 48 queries .

    快速回复 返回顶部 返回列表