一、TLE5012介绍
TLE5012是采用巨磁阻原理的15位绝对磁编码器,支持SSC、PWM、IIF、HSM、SPC通信接口,其中SSC是兼容传统SPI的3线接口,通讯频率可达8M。安装方式如下:
二、SSC通信
1、硬件电路连接
SSC包含3根数据线:DATA、SCK、CSQ。如果单片机的MOSI接口配置为推挽输出,就采用下面的电路:
如果单片机的MOSI接口配置为开漏输出,就采用下面的电路:
2、SSC读写数据帧的组成
如上图,数据帧由3部分组成:COMMAND、Data、SAFETY-WORD。
1)、COMMAND
COMMAND是每帧数据的开头。TLE5012B寄存器中的位有3种操作标志:r、w、u。r代表该位可以读,w代表该位可以写,u代表该位带有update buffer功能。
当你要在同一个时间读多个寄存器的值,因为通讯过程也有时间,这就会导致读取到的多个寄存器实际上并不是同一个时间的。update buffer功能就应运而生。你只需要在开始读寄存器前发送一个Update-Signal(把CSQ拉低tCSupdate时间),TLE5012E就会把具有update buffer功能的寄存器的值更新到update buffer中,然后你把COMMAND中的UPD设置为1,就会去读相应寄存器的update buffer值。无论你等多久去读,update buffer中的值都是你发送Update-Signal时的值,直到你再次发送Update-Signal,update buffer中的值才会更新。
2)、Data
读数据或写数据操作的数据内容。
3)、SAFETY-WORD
当发生错误,SAFETY-WORD中对应的位会拉低,直到通过SSC接口读取了STAT(地址0)寄存器,读完后,SAFETY-WORD中对应的位会自动拉高。
3、读写示例
三、程序
程序中需要注意的是,因为MOSI和MISO共用一根线,因此当主机通过DATA线传完数据后,要把DATA线配置为输入模式,释放DATA线的控制权,让从机可以控制DATA线。否则,主机对于DATA线一直是推挽输出模式,从机是改变不了DATA线的电平的。
#define READ_STATUS 0x8001 //8000
#define READ_ANGLE_VALUE 0x8021 //8020
#define READ_SPEED_VALUE 0x8031 //8030
#define SPI_TX_OFF {GPIOA->CRL&=0x0FFFFFFF;GPIOA->CRL|=0x40000000;}//把PA7(MOSI)配置成开漏--输入模式
#define SPI_TX_ON {GPIOA->CRL&=0x0FFFFFFF;GPIOA->CRL|=0xB0000000;}//把PA7(MOSI)配置成推挽--输出模式(50MHz)
void SPI1_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1,ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PA5--CLK--复用推挽
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA6--MISO--输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//PA7--MOSI--推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //PA8--CS--推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIO_CS_Pin_Type, &GPIO_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//SPI1--双线全双工!!
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
u16 SPI1_ReadWriteByte(u16 TxData)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) { //检查指定的SPI标志位设置与否:发送缓存空标志位
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据
retry=0;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET) { //检查指定的SPI标志位设置与否:接受缓存非空标志位
retry++;
if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据
}
uint16_t ReadValue(uint16_t u16RegValue)
{
uint16_t u16Data;
SPI_CS_ENABLE;
SPI1_ReadWriteByte(u16RegValue);
SPI_TX_OFF;
u16Data = ( SPI1_ReadWriteByte(0xffff) & 0x7FFF ) << 1;//0x12/0xff*100k
SPI_CS_DISABLE;
SPI_TX_ON;
return(u16Data);
}
//得到 0~359 度
uint16_t ReadAngle(void)
{
return ( ReadValue(READ_ANGLE_VALUE) * 360 / 0x10000 );
}