基本知识
-
同步通信,异步通信
同步通信:使用相同的时钟,没有起始位,停止位,效率高,主机提供时钟,是阻塞通信的方式。
同步通信从机使用主机的时钟,因此从机的时钟设不设置都没有关系。
异步通信:不使用相同的时钟,发送方,发完一个字节数据,立马发送下一个字节。无阻塞通信方式。
uart是异步通信
spi,和iic是同步通信 -
主机和从机
spi总线上,只有一个主机。通过片选选中从机。
iic上通过仲裁,是多主机方式,总线上都可以成为主机,都可以主动收发数据。通过地址选中。
uart,没有这个概念。 -
全双工和半双工
spi,uart是全双工
iic是半双工,只有一根数据线
spi
- spi的发送缓冲区和接收缓冲区。
查看库函数会发现个,接收和发送数据都是调用,hspi->Instance->DR,读写都是这个寄存器。
实际上,接收和发送是两个寄存器,只是地址是相通的,在读写的时候硬件自己会做区分。
/* Check TXE flag */
if((hspi->TxXferCount > 0) && ((hspi->Instance->SR & SPI_FLAG_TXE) == SPI_FLAG_TXE))
{
hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr);
hspi->pTxBuffPtr += sizeof(uint16_t);
hspi->TxXferCount--;
/* Check RXNE flag */
if((hspi->RxXferCount > 0) && ((hspi->Instance->SR & SPI_FLAG_RXNE) == SPI_FLAG_RXNE))
{
*((uint16_t *)hspi->pRxBuffPtr) = hspi->Instance->DR;
hspi->pRxBuffPtr += sizeof(uint16_t);
hspi->RxXferCount--;
}
因为spi是全双工的,因此收发,需要在同一个函数里。
-
中断方式下主机读到的第一个字节为空
读到从机的数据,需要主机主动发送数据,当发送完成第一个数据时,从机进入中断,开始将第一个字节数据,放进DR.而在从机进入中断之前,主机已经收到了从机一个字节的数据。这个数据,其实不是从机需要发送的数据,而是默认的数据,0x00或0xFF。解决这种情况,需要在主函数里面,提前 将要发送的数据放到DR里面。 -
CPOL和CPHA
CPOL:时钟高电平有效,还是低电平有效。
CPHA:0代表第一个电平有效,1代表第二个电平有效。
stm32HAL库里面对应的是:
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
参考文档:https://blog.csdn.net/ce123/article/details/6923293 -
nss片选线如何使用
uint32_t NSS; /*!< Specifies whether the NSS signal is managed by
hardware (NSS pin) or by software using the SSI bit.
This parameter can be a value of @ref SPI_Slave_Select_management */
#define SPI_NSS_SOFT SPI_CR1_SSM
#define SPI_NSS_HARD_INPUT ((uint32_t)0x00000000)
#define SPI_NSS_HARD_OUTPUT ((uint32_t)0x00040000)
NSS可以选择是硬件模式还是软件模式:
通常从机,选择SPI_NSS_HARD_INPUT模式,这样只有在片选线拉低的情况下,才会响应sck的数据。
可以有效过滤因为,其他原因,比如主机复位,导致sck电平有变化,产生数据移位的错误。
主机也可以选择硬件模式,但是根据 网上的资料,主机发送完数据之后,并不会自动拉高电平。所以一般使用软件模式,然后配置io口,手动拉高,拉低片选线。
参考文档:https://blog.csdn.net/suohailongjob/article/details/49050741
can
标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID
CAN一个位只有3段:同步段(SYNC_SEG)、时间段1(BS1)和时间段2(BS2)