OpenEdv-开源电子网

 找回密码
 立即注册

扫一扫,访问微社区

正点原子全套STM32开发资料,上千讲STM32视频教程,RT1052教程免费下载啦...

查看: 676|回复: 20

有关STM32通过硬件SPI实现16为数据传输的问题

[复制链接]

  离线 

5

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
167
金钱
167
注册时间
2017-10-15
在线时间
17 小时
发表于 2018-5-17 09:48:30 | 显示全部楼层 |阅读模式
1金钱
请教大家一个问题,如何实现SPI的16位数据输出,我看封装的函数中他们的移位寄存器是8位的,而16位的如何传输,求解答
回复

使用道具 举报

  离线 

20

主题

1667

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
3306
金钱
3306
注册时间
2014-8-26
在线时间
815 小时
发表于 2018-5-17 09:48:31 | 显示全部楼层
16位哦
1111111.JPG
回复

使用道具 举报

  离线 

0

主题

3

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2018-5-17
在线时间
2 小时
发表于 2018-5-17 14:27:37 | 显示全部楼层
是 16bit
回复

使用道具 举报

  离线 

5

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
167
金钱
167
注册时间
2017-10-15
在线时间
17 小时
 楼主| 发表于 2018-5-17 16:36:12 | 显示全部楼层

HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout);为什么发送和接收都是u8?
回复

使用道具 举报

  离线 

5

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
167
金钱
167
注册时间
2017-10-15
在线时间
17 小时
 楼主| 发表于 2018-5-17 16:36:49 | 显示全部楼层
正点原子公众号

HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)为什么发送和接收都是u8,不是8位吗?
回复

使用道具 举报

  离线 

16

主题

345

帖子

0

精华

高级会员

Rank: 4

积分
750
金钱
750
注册时间
2017-5-21
在线时间
331 小时
发表于 2018-5-17 17:32:37 来自手机 | 显示全部楼层
*pTxData是一个指针,这个指针是8位的而不是说数据是8位的
回复

使用道具 举报

  离线 

5

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
167
金钱
167
注册时间
2017-10-15
在线时间
17 小时
 楼主| 发表于 2018-5-17 21:05:36 | 显示全部楼层
l6931639 发表于 2018-5-17 17:32
*pTxData是一个指针,这个指针是8位的而不是说数据是8位的

u8 SPI2_WriteByte(u8 TxData)
{
        u8 Rxdata;
        HAL_SPI_TransmitReceive(&SPI2_Handler,&TxData,&Rxdata,8, 1000);      
        return Rxdata;                                    
}
但是入口的变量是8位的呀,怎么实现16位的?
回复

使用道具 举报

  离线 

4

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2018-4-4
在线时间
10 小时
发表于 2018-5-18 10:10:45 | 显示全部楼层
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)指针为8位,你定义uint16_t的数据仍然是可以用的,举个例子
我定义16位的数据:
                uint16_t        DeTxBuffer[1] ;
                uint16_t        DeRxBuffer[1] ;
收发时使用数据转换即可:
HAL_SPI_TransmitReceive(&hspi1,(uint8_t *)DeTxBuffer,(uint8_t *)DeRxBuffer,1,1000);
回复

使用道具 举报

  离线 

2

主题

60

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
209
金钱
209
注册时间
2018-1-31
在线时间
33 小时
发表于 2018-5-18 10:17:38 | 显示全部楼层
l6931639 发表于 2018-5-17 17:32
*pTxData是一个指针,这个指针是8位的而不是说数据是8位的

指针是8位的?还是说指针指向的数据是8位的?
回复

使用道具 举报

  离线 

2

主题

60

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
209
金钱
209
注册时间
2018-1-31
在线时间
33 小时
发表于 2018-5-18 10:18:49 | 显示全部楼层
xiaoff 发表于 2018-5-18 10:10
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxDat ...

函数内部转换了吗?不转换的话16位数据是不是只有低8位发送出去?或者是说u16是分两次发送出去?
回复

使用道具 举报

  离线 

2

主题

60

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
209
金钱
209
注册时间
2018-1-31
在线时间
33 小时
发表于 2018-5-18 10:21:41 | 显示全部楼层
楼主,2楼说的对,SPI设置可以选择8位或者16位。
那为什么封装的函数都是8位的?因为大部分情况都是8位的。16位的很少用吧?
如果你有特殊需求,那就自己改一个函数,发16位的。
要不就把16位拆成两个8bit的,分两次发送。
回复

使用道具 举报

  离线 

5

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
167
金钱
167
注册时间
2017-10-15
在线时间
17 小时
 楼主| 发表于 2018-5-18 16:49:56 | 显示全部楼层
屋脊雀 发表于 2018-5-18 10:21
楼主,2楼说的对,SPI设置可以选择8位或者16位。
那为什么封装的函数都是8位的?因为大部分情况都是8位的 ...

谢谢你的解答,分两次发送中间会不会有间断啊?
回复

使用道具 举报

  离线 

4

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2018-4-4
在线时间
10 小时
发表于 2018-5-30 15:18:33 | 显示全部楼层
屋脊雀 发表于 2018-5-18 10:18
函数内部转换了吗?不转换的话16位数据是不是只有低8位发送出去?或者是说u16是分两次发送出去?

  你对这个函数理解的不太对。uint16_t        DeTxBuffer[1] 是指DeTxBuffer所存储的数据是16bit,而非DeTxBuffer的地址是16bit,在单片机中一般使用8bit 的地址。
  所以函数所需要的是地址,而不是数据;即使你的数据不是8位的也不是16位的,只要地址传递正确,依然可以收发数据。
  另外,收发数据理应根据数据的大小来发送数据,最好不要将16位的拆分成8位的数据。
回复

使用道具 举报

  离线 

5

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
167
金钱
167
注册时间
2017-10-15
在线时间
17 小时
 楼主| 发表于 2018-5-31 10:06:10 | 显示全部楼层
xiaoff 发表于 2018-5-30 15:18
你对这个函数理解的不太对。uint16_t        DeTxBuffer[1] 是指DeTxBuffer所存储的数据是16bit,而非D ...

谢谢您的解答,你的意思是只要指针的地址位(8位)正确,具体里面装多大的数据(16 or8位)无所谓,对吧?
回复

使用道具 举报

  离线 

2

主题

60

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
209
金钱
209
注册时间
2018-1-31
在线时间
33 小时
发表于 2018-6-1 12:11:58 | 显示全部楼层
xiaoff 发表于 2018-5-30 15:18
你对这个函数理解的不太对。uint16_t        DeTxBuffer[1] 是指DeTxBuffer所存储的数据是16bit,而非D ...

1 我认为我没有理解错。
uint16_t        DeTxBuffer[1] 是指DeTxBuffer所存储的数据是16bit,而非DeTxBuffer的地址是16bit------------------是的
在单片机中一般使用8bit 的地址。----------你确定是8bit地址?寻址范围0-256?

2 是的,函数需要的是地址,但是,函数也是通过地址获取数据吧?

还是回到你举的例子:
你定义:
uint16_t        DeTxBuffer[1] ;
                uint16_t        DeRxBuffer[1] ;
楼主说要发送16位数据,那么是不是就将数据赋值给TX?
假如数据是0X4455,赋值给DeTxBuffer[0].

调用发送函数:
HAL_SPI_TransmitReceive(&hspi1,(uint8_t *)DeTxBuffer,(uint8_t *)DeRxBuffer,1,1000);

你觉得这个函数会进行什么操作?
1  将0x4455发送出去?
2  将0x44发送出去?
3  将0x55发送出去?

你说“依然可以发送数据出去”?是指上面的哪种?

这个函数定入口是U8,你让他发送1个数据,意思就是发送一个u8,你觉得会将u16发送出去?请问怎么做的?
回复

使用道具 举报

  离线 

2

主题

60

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
209
金钱
209
注册时间
2018-1-31
在线时间
33 小时
发表于 2018-6-1 12:13:49 | 显示全部楼层
简单的旅行 发表于 2018-5-31 10:06
谢谢您的解答,你的意思是只要指针的地址位(8位)正确,具体里面装多大的数据(16 or8位)无所谓,对吧 ...

装什么数据确实无所谓,程序又不知道你要做什么,
但是发送什么数据出去,你有所谓吧?
我要发U16,程序给你发个U8出去,不能无所谓。
回复

使用道具 举报

  离线 

6

主题

113

帖子

0

精华

高级会员

Rank: 4

积分
635
金钱
635
注册时间
2015-11-26
在线时间
126 小时
发表于 2018-6-1 14:44:12 | 显示全部楼层
屋脊雀 发表于 2018-5-18 10:17
指针是8位的?还是说指针指向的数据是8位的?

指针指向的数据是8位的
回复

使用道具 举报

  离线 

4

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2018-4-4
在线时间
10 小时
发表于 2018-6-4 10:53:35 | 显示全部楼层
本帖最后由 xiaoff 于 2018-6-4 13:34 编辑
屋脊雀 发表于 2018-6-1 12:11
1 我认为我没有理解错。
uint16_t        DeTxBuffer[1] 是指DeTxBuffer所存储的数据是16bit,而非DeTxB ...

您好,我在描述的时候的确是有问题的,我自己都没在意。但是这种做法的确是正确的。

假如数据是0x4455,那么收到的就应该是0x4455。

请注意函数库这一段的描述

  /* Set the function for IT treatment */
  if(hspi->Init.DataSize > SPI_DATASIZE_8BIT )
  {
    hspi->RxISR     = SPI_2linesRxISR_16BIT;
    hspi->TxISR     = SPI_2linesTxISR_16BIT;
  }
  else
  {
    hspi->RxISR     = SPI_2linesRxISR_8BIT;
    hspi->TxISR     = SPI_2linesTxISR_8BIT;
  }

也就是说,函数会根据你的数据大小选择如何接受和发送。假如进入16bit数据的收发,会进入下面这个函数:
static void SPI_2linesRxISR_16BIT(struct __SPI_HandleTypeDef *hspi)
{
  /* Receive data in 16 Bit mode */
  *((uint16_t*)hspi->pRxBuffPtr) = hspi->Instance->DR;
  hspi->pRxBuffPtr += sizeof(uint16_t);
  hspi->RxXferCount--;

  if(hspi->RxXferCount == 0U)
  {
#if (USE_SPI_CRC != 0U)
    if(hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
    {
      hspi->RxISR =  SPI_2linesRxISR_16BITCRC;
      return;
    }
#endif /* USE_SPI_CRC */

    /* Disable RXNE interrupt */
    __HAL_SPI_DISABLE_IT(hspi, SPI_IT_RXNE);

    if(hspi->TxXferCount == 0U)
    {
      SPI_CloseRxTx_ISR(hspi);
    }
  }
}
这个函数在数据收发完毕之后会关闭RX和TX(TX的原理与RX相似)。
这样的话就可以根据你定义数据大小来收发函数,也就是说,SPI是可以实现16位数的收发的,这也就是为什么可以直接接收到0x4455的原因。
回复

使用道具 举报

  离线 

4

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
53
金钱
53
注册时间
2018-4-4
在线时间
10 小时
发表于 2018-6-4 13:51:55 | 显示全部楼层
屋脊雀 发表于 2018-6-1 12:11
1 我认为我没有理解错。
uint16_t        DeTxBuffer[1] 是指DeTxBuffer所存储的数据是16bit,而非DeTxB ...

如果你的DataSize = SPI_DATASIZE_16BIT;而你的数据是8bit,那么16个数据传输的时钟仅仅有8个有效,其余的会用0进行补齐。
如果你的DataSize = SPI_DATASIZE_8BIT;而你的数据是16bit,依然可以发送,但是时钟因为被设定成8个,所有你只能分两次发送结束。除非溢出时间被你设置的太短,传输被中断。具体可以查看函数库中
      static void SPI_2linesRxISR_8BIT(struct __SPI_HandleTypeDef *hspi)
对此有所描述。
回复

使用道具 举报

  离线 

7

主题

60

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
251
金钱
251
注册时间
2018-4-25
在线时间
50 小时
发表于 2018-6-4 17:32:49 | 显示全部楼层
初始化的时候配置成16位的不就OK咯
回复

使用道具 举报

  离线 

5

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
167
金钱
167
注册时间
2017-10-15
在线时间
17 小时
 楼主| 发表于 2018-6-7 08:33:40 | 显示全部楼层
xiaoff 发表于 2018-6-4 13:51
如果你的DataSize = SPI_DATASIZE_16BIT;而你的数据是8bit,那么16个数据传输的时钟仅仅有8个有效,其余 ...

晓得了,谢谢!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则




QQ|联系我们|手机版|官方淘宝店|微信公众平台|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2018-8-15 01:40

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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