STM32 的SPI读写函数解析

本文详细解析了SPI通信中读写操作的实现机制,重点介绍了如何通过发送一个字节来同步接收一个字节的方法,解释了为何读写操作通常被组合在一起,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//SPIx 读写一个字节

//TxData:要写入的字节

//返回值:读取到的字节

u8 SPIx_ReadWriteByte(u8 TxData)

{                                                              

         while((SPI1->SR&(1<<1))==0);           

         SPI1->DR=TxData;            //发送一个byte          

         while((SPI1->SR&(1<<0))==0);                                                           

         returnSPI1->DR;          //返回收到的数据                                  

}

 

 

对于这样的读写函数曾有这样的疑惑,读就是读写就写为什么要放一起呢。这样是不是很麻烦,查询相关资料有如下解答。

 

转自:http://www.ec66.com/article/list.asp?indexid=4538

a)写一个字节:

​while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

//确保发生前Buffer为空,也就是说上一次已经发生完成

​SPI_I2S_SendData(SPI1, Data); 

//往寄存器中写入一个字节

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);

//等待接受到一个字节数据,

为什么要这么做?加这一句的原因是为了确保这个字节已经发送出去因为发生和接受是并行同步进行,那就是说你发生出去一个字节意味着你收到一个字节。所以这样判断完全没有问题,再说必要性,如果你不加这句你就会容易犯过早拉高CS信号的错误(相当于检测到收到数据,那么说明数据一定发完了),你想想如果在SPI_I2S_SendData(SPI1, Data)后面立即拉高CS是什么后果。SPI_I2S_ReceiveData(SPI1); //都会接收到的数据,看起来没什么必要,但以用stm32的经验推荐这样做,也许会有意想不到的收获。

SPI_Writebyteu8data

{

while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPI1, Data); 

​while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); 

​SPI_I2S_ReceiveData(SPI1);

 }

b)​读一个字节:读的时候要注意一个问题,因为从模式是没法提供时钟的,所以主模式下必须要在接收的同时提供时钟。办法就是发送一个字节来实现,因为还是上面说的,发送一个字节就意味着收到一个字节,代码和写完全一样,只要把读出来的字节保存即可。u8 SPI_Readbyteu8data{ while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);SPI_I2S_SendData(SPI1, Data); while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI1); }

这段代码应该是用于在某个 SPI Flash 存储器中入数据的代码。下面是对该代码的逐行解释: ```c while(1) { ``` 这是一个无限循环,表示程序会一直执行下去。 ```c WriteEnable(); ``` 这个函数用于向 SPI Flash 存储器中入一个命令,使其进入入状态。 ```c OutPin(CS,H); OutPin(CS,L); ``` 这两行代码用于控制 SPI Flash 存储器的片选信号,将其置为低电平,表示要开始对其进行读写操作。 ```c SPI_Write_Read_One(0x02); SPI_Write_Read_One(Curhwlb); SPI_Write_Read_One(Curlwhb); SPI_Write_Read_One(Curlwlb); ``` 这四行代码用于向 SPI Flash 存储器中入一组命令和地址信息,以指示要入的数据的位置。其中 0x02 表示入命令,Curhwlb、Curlwhb 和 Curlwlb 分别是要入的数据的地址信息。 ```c for(i=0; i<4; i++){ for(j=0; j<64; j++){ buf[j]=Store(); } SPI_Write_buf(buf, 64); } ``` 这个循环用于将要入的数据从某个缓冲区中取出来,并将其SPI Flash 存储器中。每次入 64 字节的数据。 ```c OutPin(CS,H); ``` 这行代码用于将 SPI Flash 存储器的片选信号置为高电平,表示本次读写操作已经结束。 ```c OutPin(CS,L); SPI_Write_One(0x05); ``` 这两行代码用于向 SPI Flash 存储器中入一个命令,以检查当前存储器是否空闲。0x05 表示此命令是取状态寄存器的命令。 ```c Chip_Data = SPI_Read_One(); for(n=0;n<4000;n++){ DelayUs(1); Chip_Data = SPI_Read_One(); if((Chip_Data&0x01)==0x00) break; if(n==3000) Fail(1,1,1,0); } ``` 这几行代码用于检查 SPI Flash 存储器是否已经完成了当前的操作。具体来说,它会不断取存储器的状态寄存器,直到发现存储器空闲为止。如果超过一定的时间(n==3000)还没有发现存储器空闲,就会执行一个 Fail 函数,表示出现了错误。 ```c OutPin(CS,H); ``` 这行代码用于将 SPI Flash 存储器的片选信号置为高电平,表示本次检查操作已经结束。 ```c CurHWLW+=256; DisScale(CurHWLW,(_ENDADDR0_+1)); if(CurHWLW==(_ENDADDR0_+1)) break; ``` 这几行代码用于更新要入的数据的地址信息,以便下一次入操作。如果已经入完所有的数据,则跳出循环,结束程序。 需要注意的是,由于这段代码没有给出一些关键函数(例如 WriteEnable、OutPin、SPI_Write_Read_One 等),因此无法准确地判断其功能和正确性。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值