话不多说,硬件连接图
单片机SPI的MOSI和MISO脚连一起,加4.7K上拉电阻。
软件使用SPI通信。
#define BMQ_LZ_D 30//编码器轮子直径30mm
//#define BMQ_pi 3.141592653 //π值
#define BMQ_motor_L (BMQ_LZ_D * M_PI) //轮子的周长
#define TLE_CSS_PIN GET_PIN(C, 6)
#define SPI_TX_OFF {GPIOB->CRH&=0x0FFFFFFF;GPIOB->CRH|=0x40000000;}//把PB15(MOSI)配置成开漏--输入模式
#define SPI_TX_ON {GPIOB->CRH&=0x0FFFFFFF;GPIOB->CRH|=0xB0000000;}//把PB15(MOSI)配置成推挽--输出模式(50MHz)
/* SPI command for TLE5012 */
#define READ_ANGLE_VALUE 0x8021
#define READ_SPEED_VALUE 0x8031
#define READ_CONT_VALUE 0x8041
rt_uint32_t bmq_licheng_value = 0;
rt_uint32_t eeprom_read_value = 0;
rt_uint32_t eeprom_write_value = 0;
rt_uint16_t eeprom_tle_angle = 0;
SPI_HandleTypeDef SPI2_Handler; //SPI2句柄
int TLE_spi_gpio_enable(void)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟
__HAL_RCC_SPI2_CLK_ENABLE(); //使能SPI2时钟
__HAL_RCC_GPIOC_CLK_ENABLE();
//PB13,14,15
GPIO_Initure.Pin=GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //快速
HAL_GPIO_Init(GPIOB,&GPIO_Initure);
GPIO_Initure.Pin = GPIO_PIN_6;
GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_Initure);
return 0;
}
rt_uint8_t SPI2_ReadWriteByte(rt_uint8_t TxData)
{
rt_uint8_t Rxdata;
HAL_SPI_TransmitReceive(&SPI2_Handler,&TxData,&Rxdata,1, 1000);
return Rxdata;
}
void TLE_SPI2_Init(void)
{
TLE_spi_gpio_enable();
SPI2_Handler.Instance = SPI2; //SPI2
SPI2_Handler.Init.Mode = SPI_MODE_MASTER; //设置SPI工作模式,设置为主模式
SPI2_Handler.Init.Direction = SPI_DIRECTION_2LINES; //设置SPI单向或者双向的数据模式:SPI设置为双线模式
SPI2_Handler.Init.DataSize = SPI_DATASIZE_8BIT; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI2_Handler.Init.CLKPolarity = SPI_POLARITY_LOW; //串行同步时钟的空闲状态为高电平
SPI2_Handler.Init.CLKPhase = SPI_PHASE_2EDGE; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI2_Handler.Init.NSS = SPI_NSS_SOFT; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
SPI2_Handler.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;//定义波特率预分频的值:波特率预分频值为256
SPI2_Handler.Init.FirstBit = SPI_FIRSTBIT_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI2_Handler.Init.TIMode = SPI_TIMODE_DISABLE; //关闭TI模式
SPI2_Handler.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
SPI2_Handler.Init.CRCPolynomial = 10; //CRC值计算的多项式
HAL_SPI_Init(&SPI2_Handler);//初始化
__HAL_SPI_ENABLE(&SPI2_Handler); //使能SPI2
SPI2_ReadWriteByte(0Xff); //启动传输
}
void SPI2_SetSpeed(rt_uint8_t SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//判断有效性
__HAL_SPI_DISABLE(&SPI2_Handler); //关闭SPI
SPI2_Handler.Instance->CR1&=0XFFC7; //位3-5清零,用来设置波特率
SPI2_Handler.Instance->CR1|=SPI_BaudRatePrescaler;//设置SPI速度
__HAL_SPI_ENABLE(&SPI2_Handler); //使能SPI
}
rt_uint8_t tle_tx_buf[10];
rt_uint8_t tle_rx_buf[10];
void SPI2_WriteByte(rt_uint16_t byte)
{
tle_tx_buf[0] = byte >> 8;
tle_tx_buf[1] = byte;
HAL_SPI_Transmit(&SPI2_Handler, tle_tx_buf, 2,100);
}
void SPI2_ReadByte(void)
{
HAL_SPI_Receive(&SPI2_Handler, tle_rx_buf, 2,100);
}
void SPI2_ReadBuf(void)
{
HAL_SPI_Receive(&SPI2_Handler, tle_rx_buf, 6,100);
}
void ReadValue(rt_uint16_t u16RegValue,rt_uint8_t read_cont)
{
rt_pin_write(TLE_CSS_PIN, PIN_LOW);
SPI2_WriteByte(u16RegValue);
SPI_TX_OFF;
if(read_cont == 1)
{
SPI2_ReadByte();
}
else if(read_cont == 2)
{
SPI2_ReadBuf();
}
rt_pin_write(TLE_CSS_PIN, PIN_HIGH);
SPI_TX_ON;
}
void WriteValue(rt_uint16_t addr,rt_uint16_t daat)
{
rt_pin_write(TLE_CSS_PIN, PIN_LOW);
SPI2_WriteByte(addr);
SPI2_WriteByte(daat);
SPI_TX_OFF;
SPI2_ReadByte();
rt_pin_write(TLE_CSS_PIN, PIN_HIGH);
SPI_TX_ON;
}
void tle_reset(void)
{
WriteValue(0x00f1,0x0000);//禁用启动BIST
rt_thread_mdelay(50);
WriteValue(0x0011,0x5aff);//激活HW复位
}
MSH_CMD_EXPORT(tle_reset, tle_reaet function);
//得到 0~359 度
rt_uint16_t ReadAngle(void)
{
rt_uint16_t rd = 0;
ReadValue(READ_ANGLE_VALUE,1);
rd = tle_rx_buf[0];
rd <<= 8;
rd |= tle_rx_buf[1];
rd &= 0x7FFF;
rd = (rd * 360) / 32768;
return rd;
}
//得到角速度
rt_uint16_t ReadSpeed(void)
{
rt_uint16_t rd = 0;
ReadValue(READ_SPEED_VALUE,1);
rd = tle_rx_buf[0];
rd <<= 8;
rd |= tle_rx_buf[1];
rd &= 0x7FFF;
return rd;
}
//得到角转数
rt_uint16_t ReadCont(void)
{
rt_uint16_t rd = 0;
ReadValue(READ_CONT_VALUE,1);
rd = tle_rx_buf[0];
rd <<= 8;
rd |= tle_rx_buf[1];
rd = rd & 0x01ff;
return rd;
}
rt_uint16_t tle_angle = 0;
rt_uint16_t tle_speed = 0;
rt_uint16_t tle_cont = 0;
void Read_tle_all(void)
{
rt_uint16_t rd = 0;
ReadValue(0x8023,2);
rd = tle_rx_buf[0];
rd <<= 8;
rd |= tle_rx_buf[1];
rd &= 0x7FFF;
rd = (rd * 360) / 32768;
tle_angle = rd;
rd = tle_rx_buf[2];
rd <<= 8;
rd |= tle_rx_buf[3];
rd &= 0x7FFF;
tle_speed = rd;
rd = tle_rx_buf[4];
rd <<= 8;
rd |= tle_rx_buf[5];
rd = rd & 0x01ff;
tle_cont = rd;
}
通过SPI读取角度,角速度、转数这些值网上有很多的例子,这里就不多说了,基本复制粘贴就可以了。
使用过程中发现有时候需要将转数寄存器的值清零,查了手册发现这个寄存器是只读寄存器,没法修改。
查了半天数据手册,没有发现可以设置这个寄存器的地方,那就只能复位了。
测试发现只需要将这个位置1就可以复位TLE5210了,然后转数寄存器会从零开始计数。
程序源码和数据手册下载地址