关于stm32使用SPI协议代码段中发送数据后等待接收的几点体会
问题来源
之前初学stm32使用SPI协议时,出现过一下一段代码
u8 SPI_RW(u8 dat)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
//等待发送缓冲区为空,
SPI_I2S_SendData(SPI1, dat);
//发送数据
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
//等待接收缓冲区非空
return SPI_I2S_ReceiveData(SPI1);
// 接收数据
}
在之后的使用过程中,由上述代码段封装成的子函数,无论是通过SPI读数据以及写数据过程中,都被当作调用的最小单元被反复使用。由于初学,并没有发现这段代码有一些“违和”。
近期体会
最近在使用NRF24L01模块时,又重新碰到了这段代码。使用中总感觉有一点不对劲,主要有一下三点:
- 写数据为什么和读数据这么紧密的联系在一起,为什么不封装成两个函数。
- 通过这个函数来读数据,我还可以理解,无非向发送缓冲器中写一些无关紧要的数据,然后读出数据。但写数据呢?为什么还放一个while在哪里等,等完还读?这不浪费时间吗。
- 万一接收缓冲区里面没有数据,那不是一直在等吗?
最终体会
后来,经过查阅相关资料以及思考。得出一下几点解释。
-
首先,对于接收缓冲器,里面的数据不会因为你读了一遍了就会清除,它是有一个“排队挤压式”的存储流程。所以不会出现读不到数据一直在等的情况。
-
SPI协议是一个高速全双工的通信协议。发送数据以及接收数据是同时进行的。所以我们要极可能多的时机去读取数据(发送数据肯定由我们自己把握,接收就不一定了),防止一些数据丢失,
-
我们每次通过上文子函数读取接收缓冲区里面的数据并返回,但是不意味着我们就要使用它。
status = SPI_RW(XXX)
//我们要使用接收缓冲区里面的数据,就把它赋值给变量,一遍后续进行判断等等
SPI_RW(XXX)
//我们不使用这个数据,就可以不用管它