买到一个带编码器的电机,卖家留出来读取编码器数据的接口有SPI
具体的原理图如下:
P2标注的是SPI的接口,其中MISO和MOSI是硬件连接到一起的
使用ACM32G103的硬件SPI2去读取其角度数据
原理大概如下:
1、先发送读取数据的指令,然后再接收数据,一个半双工通信的过程
2、因为MOSI和MISO硬件上连接到了一起,根据TLE5102B的通信时序要求就要稍微修改一下MOSI引脚的状态,片选使用软件片选
3、SPI2的配置CPOL=0,CPHA=1
4、SPI2引脚:
PB9 CS AF3
PB8 SCK AF3
PB7 MOSI AF3
PB6 MISO AF3
其中CS的初始化要修改一下,要初始化为GPIO
接下来直接看代码
#define SPI_USE SPI2
void SPI_USE_Transfer_OneByte(uint8_t *sdata,uint16_t ssize)
{
/* Clear Batch Done Flag */
SET_BIT(SPI_USE->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(SPI_USE->STATUS, SPI_STATUS_BATCH_DONE);
/* Clear TX FIFO */
SET_BIT(SPI_USE->TX_CTL, SPI_TX_CTL_FIFO_RESET);
CLEAR_BIT(SPI_USE->TX_CTL, SPI_TX_CTL_FIFO_RESET);
/* Set Data Size */
SPI_USE->BATCH = ssize;
/* Tx Enable */
SPI_USE->TX_CTL |= SPI_TX_CTL_EN;
/* Transmit Start */
SPI_USE->CS |= SPI_CS_CS0;
while(ssize > 0)
{
while (SPI_USE->STATUS & SPI_STATUS_TX_FIFO_FULL)
{}
SPI_USE->DAT = *sdata;
sdata++;
ssize--;
}
while (!(SPI_USE->STATUS & SPI_STATUS_TX_BATCH_DONE))
{}
/* Clear Batch Done Flag */
SET_BIT(SPI_USE->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(SPI_USE->STATUS, SPI_STATUS_BATCH_DONE);
/* Tx Disable */
SPI_USE->TX_CTL &= (~SPI_TX_CTL_EN);
SPI_USE->CS &= (~SPI_CS_CS0);
}
void SPI_USE_Receive_OneByte(uint8_t *rdata,uint16_t rsize)
{
/* Clear Batch Done Flag */
SET_BIT(SPI_USE->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(SPI_USE->STATUS, SPI_STATUS_BATCH_DONE);
/* Set Data Size */
SPI_USE->BATCH = rsize;
/* Rx Enable */
SPI_USE->RX_CTL |= SPI_RX_CTL_EN;
/* Receive Start */
SPI_USE->CS |= SPI_CS_CS0;
while(rsize > 0)
{
/* Wait Rx FIFO Not Empty */
while (SPI_USE->STATUS & SPI_STATUS_RX_FIFO_EMPTY)
{}
*rdata = SPI_USE->DAT;
rsize--;
rdata++;
}
/* Wait Transmit Done */
while (!(SPI_USE->STATUS & SPI_STATUS_RX_BATCH_DONE));
/* Clear Batch Done Flag */
SET_BIT(SPI_USE->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(SPI_USE->STATUS, SPI_STATUS_BATCH_DONE);
/* Rx Disable */
SPI_USE->RX_CTL &= (~SPI_RX_CTL_EN);
/* Receive End */
SPI_USE->CS &= (~SPI_CS_CS0);
}
再来看读取角度的过程
// TxBuffer[0] = 0x80;
// TxBuffer[1] = 0x21;
GPIOB->BSC = GPIO_PIN_9 << 16U;
PB7_OUTPUT();
SPI_USE_Transfer_OneByte(TxBuffer,2);
PB7_INPUT();
SPI_USE_Receive_OneByte(RxBuffer,2);
GPIOB->BSC = GPIO_PIN_9;
Angle= (RxBuffer[0]<<8 | RxBuffer[1])&0x7FFF;
每次发送完读取数据的指令之后,因为MOSI和MISO硬件连接到一起,我们就要将MOSI引脚由复用为SPI设置为输入状态,下一次发指令的时候重新复用为SPI
其中将MOSI引脚设置成输入和复用的代码如下
void PB7_INPUT(void)
{
GPIOB->MD &= ~(3<<14);
}
void PB7_OUTPUT(void)
{
GPIOB->AF0 |= GPIO_FUNCTION_3 << 28;
GPIOB->DS0 |= GPIO_DRIVE_LEVEL3 <<28;
GPIOB->OTYP &= (~GPIO_PIN_7);
GPIOB->PUPD |= GPIO_PULLUP<<14;
GPIOB->MD |= GPIO_MODE_AF_PP<<14;
}
读取速度,TLE5012B推荐的SPI速率最大是8M,可以根据实际情况提高,也能读到数据