打印
[STM32F0]

STM32F051的SPI发送一个字节为啥这样写_高手解答一下谢谢

[复制链接]
9578|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
baita|  楼主 | 2015-4-16 08:06 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 baita 于 2015-4-16 08:07 编辑

在设置8位时STM32F051的SPI发送一个字节为啥这样写必须要强制转换成8位吗?
源码
void SPI_SendData8(SPI_TypeDef* SPIx, uint8_t Data)
{
  uint32_t spixbase = 0x00;
  /* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));
  spixbase = (uint32_t)SPIx;
  spixbase += 0x0C;
  
  *(__IO uint8_t *) spixbase = Data;
}
比如用SPI2
  spixbase = (uint32_t)SPI2;
  spixbase += 0x0C;  
  *(__IO uint8_t *) spixbase = Data;
而不是SPI2->DR= Data;一句完事,16位是这样的。
难道8位16位发送与这里也有关系?
沙发
aozima| | 2015-4-16 09:57 | 只看该作者
本帖最后由 aozima 于 2015-4-16 10:18 编辑

要看芯片的设计,有些芯片是不分字节定和半字写的,有的要区别。也可能是写驱动的人没有去看硬件文档。

使用特权

评论回复
板凳
diweo| | 2015-4-16 11:50 | 只看该作者
完全没必要。你设定好宽度后,硬件自动处理多余的位(写入无效,读出为0)。

使用特权

评论回复
地板
baita|  楼主 | 2015-4-16 20:48 | 只看该作者
spixbase = (uint32_t)SPI2;
  spixbase += 0x0C;  
  *(__IO uint8_t *) spixbase = Data;
我把上面的几句改成SPI2->DR= Data;根本不行
而16位模式用SPI2->DR= Data;这一句发送数据就没问题
STM32103系列就没这问题,算了不管他了知道STM32F051在8位模式下SPI发送一个字节
这样写就行了。

使用特权

评论回复
5
596142041| | 2015-4-16 22:47 | 只看该作者
你看一下数据寄存器的偏移地址呗,看是不是0x0c

使用特权

评论回复
6
airwill| | 2015-4-17 05:19 | 只看该作者
好奇怪呀, 我查了下库函数, 还真是是这样的.
/**
  * @brief  Transmits a Data through the SPIx/I2Sx peripheral.
  * @param  SPIx: where x can be 1 or 2 in SPI mode to select the SPI peripheral.
  * @param  Data: Data to be transmitted.
  * @retval None
  */
void SPI_SendData8(SPI_TypeDef* SPIx, uint8_t Data)
{
  uint32_t spixbase = 0x00;

  /* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));

  spixbase = (uint32_t)SPIx;
  spixbase += 0x0C;
  
  *(__IO uint8_t *) spixbase = Data;
}

/**
  * @brief  Transmits a Data through the SPIx/I2Sx peripheral.
  * @param  SPIx: where x can be 1 or 2 in SPI mode or 1 in I2S mode to select
  *         the SPI peripheral.
  * @param  Data: Data to be transmitted.
  * @retval None
  */
void SPI_I2S_SendData16(SPI_TypeDef* SPIx, uint16_t Data)
{
  /* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));
  
  SPIx->DR = (uint16_t)Data;
}

库函数里也有个说明:
    The read access of the SPI_DR register can be done using
         SPI_ReceiveData8() (when data size is equal or inferior than 8bits) and.
         SPI_I2S_ReceiveData16() (when data size is superior than 8bits)function
         and returns the Rx buffered value. Whereas a write access to the SPI_DR
         can be done using SPI_SendData8() (when data size is equal or inferior than 8bits)
         and SPI_I2S_SendData16() (when data size is superior than 8bits) function
         and stores the written data into Tx buffer.

看样子只能服从它的规范了.  估计是 SPI 模块里面的数据总线有了什么变化了吧
请路过的朋友也留意一下

使用特权

评论回复
7
diweo| | 2015-4-17 08:12 | 只看该作者
看来,话还是不能说的太死。。:L

使用特权

评论回复
8
香水城| | 2015-4-17 11:49 | 只看该作者
airwill 发表于 2015-4-17 05:19
好奇怪呀, 我查了下库函数, 还真是是这样的.
/**
  * @brief  Transmits a Data through the SPIx/I2Sx per ...

首先,膜拜版主的发帖时间。。。

然后,这个8位写操作是“特意为之”的,原因就在F0的SPI有FIFO,那么FIFO的门限设置是8位还是16位?如果是奇数个数据字节会怎样?请看手册相关描述。





使用特权

评论回复
9
baita|  楼主 | 2015-4-18 07:16 | 只看该作者
实际上看一下STM32F05xxx参考手册SPI里有一段是数据打包讲的就很明白,STM32F05x引入了FIFO缓冲因为SPIx->DR定义的是16位数据,当你位宽设置8位时SPI2->DR= Data;这句他会执行2个8位操作,先发送低8位再发送高8位所以当设置8位及低于8位时应把DR寄存器(实际上是FIFO)定义成8位访问模式。

使用特权

评论回复
评论
xia_318 2015-10-22 17:03 回复TA
说的好!顶一下! 
10
恩哥| | 2015-11-27 12:26 | 只看该作者
你看下波形就知道了,DR寄存器是16位的寄存器,你如果不强制转换成8位,波形图是先将你的8位数据发送出去,但到这还没有结束,发送完你的8位数据后时钟线SCLK仍然工作发送8个无效位
所以我的解决方法是参考ST库函数的方法,先找出DR寄存器的地址,然后将这地址强制转换成u8*,再赋值(发送),最后波形就正常了

使用特权

评论回复
11
desertsailor| | 2015-11-27 17:26 | 只看该作者
如果是按字节操作的,必须要这么做,否则发送的就不止8位数据了。

使用特权

评论回复
12
lai832| | 2016-4-10 13:36 | 只看该作者
本帖最后由 lai832 于 2016-4-10 13:38 编辑

谢谢LZ贴子的提醒,不再走LZ的路:
这样:
将:} SPI_TypeDef;这个结构定义里的

//  __IO uint16_t DR;       /*!< SPI data register,                                   Address offset: 0x0C */
改为下面这样
//832
  union
  {
    struct
    {
    __IO uint8_t  L;
    uint8_t       RESERVED;
    }             U8;
    __IO uint16_t U16;
  }               DR;

发送改为这样:
void SPI_SendData8(SPI_TypeDef* SPIx, uint8_t Data)
{
//  uint32_t spixbase = 0x00;
  /* Check the parameters */
//832  assert_param(IS_SPI_ALL_PERIPH(SPIx));
/*
  spixbase = (uint32_t)SPIx;
  spixbase += 0x0C;
  
  *(__IO uint8_t *) spixbase = Data;*/
  SPIx->DR.U8.L = Data;
}
接收
uint8_t SPI_ReceiveData8(SPI_TypeDef* SPIx)
{
/*  uint32_t spixbase = 0x00;
  
  spixbase = (uint32_t)SPIx;
  spixbase += 0x0C;
  
  return *(__IO uint8_t *) spixbase;*/
  return SPIx->DR.U8.L;
}
其实是一样的.....
解决

使用特权

评论回复
13
yu515301489| | 2017-7-20 18:21 | 只看该作者
学习了,直接将寄存器操作换用库函数就好了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

33

帖子

0

粉丝