【转】GD32105R例程---SPI收发函数测试

[复制链接]
 楼主| 发表于 2015-8-30 09:14 | 显示全部楼层 |阅读模式
    SPI,是一种高速的,全双工,同步的通信总线,接口简单,利于硬件设计与实现。采用主从模式架构,支持多从设备应用。时钟速度快,目前应用中的数据速率可达几Mbps,且没有系统开销。相对抗干扰能力强,传输稳定,正是出于这种简单易用的特性,GD32 105R_STAR芯片也集成了这种通信协议。

1、SPI在一般应用中有4根信号线:

    MOSI:主器件数据输出,从器件数据输入。

    MISO:主器件数据输入,从器件数据输出。

    SCK: 时钟信号,由主设备控制发出。

    /SS: 从设备选择信号,由主设备控制。 根据此信号可以决定能连接到总线上从设备的数量。

    2、根据时钟极性(CPOL)及相位(CPHA)不同可以组合成4种工作模式:

    SPI0:CPOL=0,CPHA=0

    SPI1:CPOL=0,CPHA=1

    SPI2:CPOL=1,CPHA=0

    SPI3:CPOL=1,CPHA=1

 楼主| 发表于 2015-8-30 09:15 | 显示全部楼层
    根据不同外设模块的需求,来对GD32 105R_STAR的SPI外设进行不同的匹配设置,楼主根据PT6315的外设需求,进行如下初始化配置:
  1. view plaincopy to clipboardprint?
  2. /*
  3. ****************************************************************************
  4. *函数名称:void  Pt_SPIInit(void)
  5. *函数功能:PT6315 SPI 总线初始化
  6. *日期:2015 4 6
  7. *版本:V1.0
  8. *作者:yrj
  9. *SPI_FirstBit_MSB;//高位在前 PT6315手册对应改为低位在前。
  10. ****************************************************************************
  11. */  
  12. // PB12/SPI2NSS  PB13/SPI2CLK  PB14/SPI2MISO PTOUT  PB15/SPI2MOSI PTIN  
  13. void Pt_SPIInit(void)  
  14. {   
  15.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);  
  16.   GPIO_InitTypeDef GPIO_InitStructure;  
  17.   //PB14 (MISO)浮空输入  
  18.   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14;  
  19.   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;  
  20.   GPIO_Init(GPIOB,&GPIO_InitStructure);  
  21.   //PB15 MOSI PB13 SCK 复用推挽输出(外设总线用)  
  22.   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_15;  
  23.   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;  
  24.   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;  
  25.   GPIO_Init(GPIOB,&GPIO_InitStructure);  
  26.   //PB12 NSS,PB11 WP写保护普通推挽输出  本实验用软件控制NSS(主从设备的选择控制端)  
  27.   GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;  
  28.   GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;  
  29.   GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;  
  30.   GPIO_Init(GPIOB,&GPIO_InitStructure);  
  31.   Pt_Disable(); //PB12/NSS  失能  
  32.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);  
  33. view plaincopy to clipboardprint?
  34.   SPI_InitTypeDef SPI_InitStructure;  
  35.   SPI_I2S_DeInit(SPI2);  
  36.   SPI_Cmd(SPI2,DISABLE);//在改变CPOL/CPHA位之前必须清除SPE位将SPI禁止  
  37.   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//全双工  
  38.   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主模式  
  39.   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位帧结构  
  40.   SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//时钟悬空低  
  41.   SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//数据捕获与第1个时钟沿  
  42.   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//软件控制NSS信号  
  43.   SPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_8;//比特率预分频值为8。最大18MHz  
  44.   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB; /*SPI_FirstBit_MSB; //高位在前 7 7 与PT6315手册对应改为低位在前。*/   
  45.   SPI_InitStructure.SPI_CRCPolynomial = 7;//定义用于CRC值计算的多项式 7  
  46.   SPI_Init(SPI2, &SPI_InitStructure);  
  47.   SPI_Cmd(SPI2,ENABLE);   
  48. }  
  49. view plaincopy to clipboardprint?
  50.         <p>  
  51.                 此外由于SPI是一种全双工的同步通信总线,所以在进行数据通信中收发是同步进行的,为了在实际的函数调用中简单明了,针对GD32 105R_STAR SPI数据的收发,楼主在此分别设计了两个函数来进行数据的发送和接收。  
  52.         </p>  
  53.   
  54.         <p>  
  55.             SPI发送函数:  
  56.         </p>  
  57.   
  58. <pre class="c" name="code">/*
  59. ****************************************************************************
  60. *函数名称:uint8 Send_Byte(void)
  61. *函数功能:通过硬件SPI发送一个字节
  62. *日期:2015 4 6
  63. *版本:V1.0
  64. *作者:yrj
  65. ****************************************************************************
  66. */  
  67. uint32 CsyCnt;  
  68. void SendPt_Byte(uint8 data)   
  69. {  
  70.   SPI_I2S_SendData(SPI2, data);//发送数据  
  71.   CsyCnt = 0;  
  72.   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET) //等待数据发送完毕  
  73.   {  
  74.    CsyCnt++;  
  75.    if(CsyCnt>10000)   break ;  
  76.   }  
  77.   SPI_I2S_ClearFlag(SPI2,SPI_I2S_FLAG_TXE);  //清除发送完成   
  78.   //////////// 测试是否正常写入  
  79.   if( CsyCnt >10000)  // 有故障  
  80.   {  
  81.     /*重新初始化*/  
  82.     Pt_SPIInit();  
  83.     /*重新发送数据*/  
  84.     SPI_I2S_SendData(SPI2, data);/*发送数据*/  
  85.     while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET); /*等待数据发送完毕*/  
  86.   }  
  87.   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==RESET); /*等待数据发接收完毕*/  
  88.     SPI_I2S_ReceiveData(SPI2);  /*接收返回的数据,在此无实意*/         
  89. }  
  90. </pre>  
  91. <pre class="c" name="code">SPI接收函数:  
  92. </pre>  
  93. <pre class="c" name="code"><pre class="c" name="code">/*
  94. ****************************************************************************
  95. *函数名称:uint8 Get_Byte(void)
  96. *函数功能:通过硬件SPI接口接收一个字节到处理器   
  97. *日期:2015 4 6
  98. *版本:V1.0
  99. *作者:yrj
  100. ****************************************************************************
  101. */  
  102. uint8 GetPt_Byte(void)  
  103. {   
  104.   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE)==RESET); /*等待数据发送完毕*/  
  105.   SPI_I2S_SendData(SPI2, 0);/*发送该数据易产生时钟,数据本身无意义。*/  
  106.    
  107.   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==RESET);/*等待接收完成*/  
  108.   return SPI_I2S_ReceiveData(SPI2);/*返回最近接收到的数据*/   
  109. }</pre>  
  110.         <p>  
  111.             <br>  
  112.         </p>  
  113. </pre>  
发表于 2015-8-30 23:03 | 显示全部楼层
不错,纯硬件的SPI例程,不是模拟SPI的,很有用,收藏了!
发表于 2015-8-31 11:20 | 显示全部楼层
主持下,软件模拟SPI用过,速度有点慢
发表于 2015-8-31 21:53 | 显示全部楼层
不错,收藏了。等有空了烧进去看看
 楼主| 发表于 2017-11-25 09:47 | 显示全部楼层
蜕变吧 发表于 2015-8-31 11:20
主持下,软件模拟SPI用过,速度有点慢

一般场合,不是通讯场合,模拟也够用了。
发表于 2017-11-27 23:27 | 显示全部楼层
SPI,是一种高速的,全双工,同步的通信总线,接口简单,利于硬件设计与实现。
发表于 2017-11-27 23:41 | 显示全部楼层
作为SPI总线的设计的,注意两边的通讯速率保持一致的
发表于 2017-11-29 10:21 | 显示全部楼层
硬件SPI可以更省资源
发表于 2017-11-29 10:28 | 显示全部楼层
好东西,谢谢分享
发表于 2017-11-30 16:05 | 显示全部楼层
想问下楼主,从机发送无关数据启动时钟后,从机会进入中断吗
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

133

帖子

0

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