1289 lines
33 KiB
C
1289 lines
33 KiB
C
#include "as5047d.h"
|
||
#include <includes.h>
|
||
#include <stdint.h>
|
||
#include <stdio.h>
|
||
#include <stdbool.h>
|
||
|
||
#ifdef AS5047
|
||
|
||
static BSP_OS_SEM ptz_hori_get_angle_mutex;//共享资源锁
|
||
static BSP_OS_SEM ptz_vert_get_angle_mutex;
|
||
|
||
static void as5047d_delay_nop(int as5047d_delay_time);
|
||
static unsigned int as5047d_Parity_bit_even(unsigned int package);
|
||
/// AS5047D短延时函数
|
||
///
|
||
/// 用于AS5047D的SPI通信短延时
|
||
/// @param delay_time 短延时时间长短
|
||
/// @return 无
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-06创建
|
||
static void as5047d_delay_nop(int delay_time)
|
||
{
|
||
for(int i = 0; i < delay_time; i ++)
|
||
{
|
||
asm("nop");
|
||
asm("nop");
|
||
asm("nop");
|
||
asm("nop");
|
||
}
|
||
}
|
||
|
||
/// AS5047D初始化
|
||
///
|
||
/// 初始化AS5047D
|
||
/// @param 无
|
||
/// @return 无
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-06创建
|
||
/// LH修改于2022.0525
|
||
void as5047d_init()
|
||
{
|
||
//总线时钟使能
|
||
rcu_periph_clock_enable(RCU_GPIOA);
|
||
rcu_periph_clock_enable(RCU_GPIOC);
|
||
rcu_periph_clock_enable(RCU_GPIOD);
|
||
//水平PC10--CLK,PC12--MOSI
|
||
gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_10| GPIO_PIN_12);
|
||
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_10| GPIO_PIN_12);
|
||
//PA15--CS
|
||
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
|
||
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_15);
|
||
//PC11--MISO
|
||
gpio_mode_set(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_11);
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
AS5047D_HORI_CLK_LOW;
|
||
AS5047D_HORI_MOSI_LOW;
|
||
|
||
|
||
|
||
//垂直PD0--CS,PD1--CLK,PD3--MOSI
|
||
gpio_mode_set(GPIOD, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_0| GPIO_PIN_1| GPIO_PIN_3);
|
||
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_0| GPIO_PIN_1| GPIO_PIN_3);
|
||
//PD2--MISO
|
||
gpio_mode_set(GPIOD, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
AS5047D_VERT_CLK_LOW;
|
||
AS5047D_VERT_MOSI_LOW;
|
||
}
|
||
|
||
/// AS5047D数据包奇偶校验(偶校验)
|
||
///
|
||
/// 计算数据包的奇偶校验(偶校验)
|
||
/// @param package 需要计算的数据包
|
||
/// @return 返回奇偶校验后的数据包
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-06创建
|
||
static unsigned int as5047d_Parity_bit_even(unsigned int package)
|
||
{
|
||
unsigned int temp = 0;
|
||
char temp1 = 0;
|
||
///判断数据每一位是0还是1
|
||
for(char i = 0; i < 15; i++)
|
||
{
|
||
temp = package & (1 << i);
|
||
if(temp != 0)
|
||
{
|
||
///如果位数值为1则相加
|
||
temp1++;
|
||
}
|
||
temp = 0;
|
||
}
|
||
///temp1如果为偶数
|
||
if(temp1 % 2 == 0)
|
||
{
|
||
///将奇偶效验位置为0
|
||
package = package & 0X7FFF; //0111 1111 1111 1111
|
||
}
|
||
///temp1如果为奇数
|
||
else
|
||
{
|
||
///将奇偶效验位置为1
|
||
package = package | 0X8000;//1000 0000 0000 0000
|
||
}
|
||
return package;
|
||
}
|
||
|
||
|
||
|
||
/// 设定数据包read/write的类型
|
||
///
|
||
/// 设定数据包read/write的类型
|
||
/// @param package 需要设定的数据包
|
||
/// @return 设定后的数据包
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-07创建
|
||
unsigned int as5047d_command_type(unsigned int package, unsigned int type)
|
||
{
|
||
switch(type)
|
||
{
|
||
case AS5047D_WRITE_COMMAND:
|
||
case AS5047D_WRITE_DATA:
|
||
package = package & AS5047D_WRITE_COMMAND;
|
||
break;
|
||
|
||
case AS5047D_READ_COMMAND:
|
||
package = package | AS5047D_READ_COMMAND;
|
||
break;
|
||
|
||
default :
|
||
return 0;
|
||
}
|
||
return package;
|
||
}
|
||
|
||
/// 判断接收到的数据
|
||
///
|
||
/// 判断接收到的数据
|
||
/// @param package 待判断的数据
|
||
/// @param 无
|
||
/// @return 返回判断结果
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
As5047DJudgeReceivePackage as5047d_hori_judge_receive_package(unsigned int package)
|
||
{
|
||
unsigned int temp = 0;
|
||
As5047DJudgeReceivePackage temp1;
|
||
memset(&temp1,0,sizeof(temp1));
|
||
|
||
temp1.package = package;
|
||
temp1.Operation_Result = 1;
|
||
//首先判断数据包的偶校验码是否正确
|
||
//效验码错误
|
||
if(package != as5047d_Parity_bit_even(package))
|
||
{
|
||
temp1.parity_error_package = 1;
|
||
temp1.Operation_Result = 0;
|
||
}
|
||
//效验码正确
|
||
else
|
||
{
|
||
//判断返回数据包是否是回复的指令出错内容
|
||
temp = package & AS5047D_JUDGE_RECEIVE_DATA;
|
||
//回复指令出错内容
|
||
if(temp != 0)
|
||
{
|
||
// temp1.error_flag_command = 1;
|
||
// temp1.framing_error_command = package & 0X0001;
|
||
// temp1.command_invalid_command = package & (0X0001 << 1);
|
||
// temp1.parity_error_command = package & (0X0001 << 2);
|
||
as5047d_hori_cef_command();
|
||
|
||
}
|
||
}
|
||
return temp1;
|
||
}
|
||
|
||
|
||
As5047DJudgeReceivePackage as5047d_vert_judge_receive_package(unsigned int package)
|
||
{
|
||
unsigned int temp = 0;
|
||
As5047DJudgeReceivePackage temp1;
|
||
memset(&temp1,0,sizeof(temp1));
|
||
|
||
temp1.package = package;
|
||
temp1.Operation_Result = 1;
|
||
//首先判断数据包的偶校验码是否正确
|
||
//效验码错误
|
||
if(package != as5047d_Parity_bit_even(package))
|
||
{
|
||
temp1.parity_error_package = 1;
|
||
temp1.Operation_Result = 0;
|
||
}
|
||
//效验码正确
|
||
else
|
||
{
|
||
//判断返回数据包是否是回复的指令出错内容
|
||
temp = package & AS5047D_JUDGE_RECEIVE_DATA;
|
||
//回复指令出错内容
|
||
if(temp != 0)
|
||
{
|
||
// temp1.error_flag_command = 1;
|
||
// temp1.framing_error_command = package & 0X0001;
|
||
// temp1.command_invalid_command = package & (0X0001 << 1);
|
||
// temp1.parity_error_command = package & (0X0001 << 2);
|
||
as5047d_vert_cef_command();
|
||
|
||
}
|
||
}
|
||
return temp1;
|
||
}
|
||
|
||
/*********************************************************************/
|
||
|
||
|
||
|
||
|
||
/// 水平发送数据
|
||
///
|
||
/// 向as5047d发送数据
|
||
/// @param 无
|
||
/// @return 返回接收到的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
unsigned int as5047d_hori_send_package(unsigned int package)
|
||
{
|
||
unsigned int temp = 0;
|
||
unsigned int temp1 = 0;
|
||
unsigned int temp2 = 0;
|
||
AS5047D_HORI_CLK_LOW;
|
||
AS5047D_HORI_MOSI_LOW;
|
||
as5047d_delay_nop(2);
|
||
for(int i = 15; i >= 0; i--)
|
||
{
|
||
AS5047D_HORI_CLK_LOW;
|
||
as5047d_delay_nop(2);
|
||
temp = package & (1 << i);
|
||
if(temp != 0)
|
||
{
|
||
AS5047D_HORI_MOSI_HIGH;
|
||
}
|
||
else
|
||
{
|
||
AS5047D_HORI_MOSI_LOW;
|
||
}
|
||
as5047d_delay_nop(2);
|
||
AS5047D_HORI_CLK_HIGH;
|
||
as5047d_delay_nop(2);
|
||
|
||
temp1 = AS5047D_HORI_MISO_READ;
|
||
temp2 = temp2 | (temp1 << i);
|
||
|
||
temp1 = 0;
|
||
temp = 0;
|
||
}
|
||
AS5047D_HORI_CLK_LOW;
|
||
AS5047D_HORI_MOSI_LOW;
|
||
//返回的上一个指令回复的数据
|
||
return temp2;
|
||
}
|
||
|
||
/// 水平接收数据
|
||
///
|
||
/// 接收as5047d返回的数据
|
||
/// @param 无
|
||
/// @return 返回接收到的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-07创建
|
||
unsigned int as5047d_hori_receive_package()
|
||
{
|
||
unsigned int temp = 0;
|
||
unsigned int temp1 = 0;
|
||
AS5047D_HORI_CLK_LOW;
|
||
as5047d_delay_nop(2);
|
||
for(int j = 15; j >= 0; j--)
|
||
{
|
||
AS5047D_HORI_CLK_HIGH;
|
||
as5047d_delay_nop(2);
|
||
temp = AS5047D_HORI_MISO_READ;
|
||
temp1 = temp1 | (temp << j);
|
||
AS5047D_HORI_CLK_LOW;
|
||
as5047d_delay_nop(2);
|
||
temp = 0;
|
||
}
|
||
AS5047D_HORI_CLK_LOW;
|
||
return temp1;
|
||
}
|
||
|
||
|
||
/// 水平发送读指令
|
||
///
|
||
/// 发送读取as5047d数据指令
|
||
/// @param add 寄存器地址
|
||
/// @return 发送过程中接收的数据 111 1111 1111 1111
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-07创建
|
||
unsigned int as5047d_hori_read_command(unsigned int add)
|
||
{
|
||
unsigned int temp = 0;
|
||
add = as5047d_command_type(add,AS5047D_READ_COMMAND);
|
||
add = as5047d_Parity_bit_even(add);
|
||
//发送指令
|
||
temp = as5047d_hori_send_package(add);
|
||
//返回的上一个指令回复的数据
|
||
return temp;
|
||
}
|
||
|
||
|
||
/// 水平读取as5047d寄存器中的值
|
||
///
|
||
/// 读取as5047d寄存器中的值
|
||
/// @param add 寄存器地址
|
||
/// @return 返回读取到的寄存器中的值
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-07创建
|
||
unsigned int as5047d_hori_read_data(unsigned int add)
|
||
{
|
||
|
||
unsigned int temp = 0;
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_HORI_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
|
||
//发送读指令
|
||
as5047d_hori_read_command(add);
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_HORI_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
|
||
//读取上一条指令获得的数据
|
||
temp = as5047d_hori_nop_command();
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
return temp;
|
||
}
|
||
|
||
|
||
/// 水平发送写指令
|
||
///
|
||
/// 向as5047d发送写指令
|
||
/// @param add 寄存器地址
|
||
/// @return 发送过程中接收的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
unsigned int as5047d_hori_write_command(unsigned int add)
|
||
{
|
||
unsigned int temp = 0;
|
||
add = as5047d_command_type(add,AS5047D_WRITE_COMMAND);
|
||
add = as5047d_Parity_bit_even(add);
|
||
//发送指令
|
||
temp = as5047d_hori_send_package(add);
|
||
//返回的上一个指令回复的数据
|
||
return temp;
|
||
}
|
||
|
||
/// 水平发送NOP指令
|
||
///
|
||
/// 向as5047d发送NOP指令
|
||
/// @param 无
|
||
/// @return 发送过程中接收的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
unsigned int as5047d_hori_nop_command()
|
||
{
|
||
unsigned int temp = 0;
|
||
temp = as5047d_hori_send_package(AS5047D_NOP);
|
||
//返回的上一个指令回复的数据
|
||
return temp;
|
||
}
|
||
|
||
/// 水平清除错误标记指令
|
||
///
|
||
/// 向as5047d发送清除错误标记指令CLEAR ERROR FLAG command
|
||
/// @param 无
|
||
/// @return 1清除成功,0清除失败
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
unsigned int as5047d_hori_cef_command()
|
||
{
|
||
unsigned int temp = 0;
|
||
unsigned int temp1 = 0;
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_HORI_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
temp = as5047d_Parity_bit_even(AS5047D_CLEAR_ERROR_FLAG);
|
||
as5047d_hori_send_package(temp);
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_HORI_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
temp1 = as5047d_hori_nop_command();
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_HORI_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
temp1 = as5047d_hori_nop_command();
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
return temp1;
|
||
}
|
||
|
||
/// 水平发送写指令并读取返回的数据
|
||
///
|
||
/// 向as5047d发送写指令并读取返回的数据
|
||
/// @param add 寄存器地址
|
||
/// @param data 需要写入的数据
|
||
/// @return 发送过程中接收的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
As5047DJudgeReceivePackage as5047d_hori_write_data(unsigned int add,unsigned int data)
|
||
{
|
||
As5047DJudgeReceivePackage temp;
|
||
int i;
|
||
for(i = 0; i < AS5047D_WRITE_NUM; i++)
|
||
{
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
as5047d_delay_nop(20);
|
||
AS5047D_HORI_CSN_ENABLE;
|
||
as5047d_delay_nop(20);
|
||
|
||
//发送写入指令
|
||
as5047d_hori_write_command(add);
|
||
//从新写入新的数据,并返回寄存器中旧的数据
|
||
add = as5047d_command_type(data,AS5047D_WRITE_DATA);
|
||
add = as5047d_Parity_bit_even(data);
|
||
as5047d_hori_send_package(data);
|
||
//接收寄存器中的新数据0X3FFF 0011 1111 1111 1111
|
||
temp.package = as5047d_hori_nop_command();
|
||
temp = as5047d_hori_judge_receive_package(temp.package);
|
||
|
||
as5047d_delay_nop(2);
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
|
||
if(temp.Operation_Result != 1)
|
||
{
|
||
as5047d_hori_cef_command();
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
//判断写入的数据和最新返回的寄存器数据是否相同
|
||
if((data & 0X3FFF) == (temp.package & 0X3FFF))
|
||
{
|
||
temp.Operation_Result = 1;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
return temp;
|
||
}
|
||
|
||
/// 读取云台水平角度
|
||
///
|
||
/// 读取云台水平角度
|
||
/// @param 无
|
||
/// @param 无
|
||
/// @return 返回读取结果。-1读取失败,其他值读取成功
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-27创建
|
||
float as5047d_hori_get_angle()
|
||
{
|
||
BSP_OS_SemWait(&ptz_hori_get_angle_mutex, 0u);
|
||
float angle = 0;
|
||
unsigned int angle1 = 0;
|
||
unsigned int temp = 0;
|
||
As5047DJudgeReceivePackage temp1;
|
||
memset(&temp1, 0, sizeof(temp1));
|
||
//读取角度数据
|
||
temp = as5047d_hori_read_data(AS5047D_ANGLE);
|
||
//判断接收到的数据是否正常
|
||
temp1 = as5047d_hori_judge_receive_package(temp);
|
||
//数据正确
|
||
if(temp1.Operation_Result == 1)
|
||
{
|
||
angle = (temp & 0x3FFF) * 0.02197265625;//0.02197265625 = 360.0 / 16384.0
|
||
angle1 = (unsigned int)(angle * 1000.0);//只保留小数点后3位
|
||
angle = (float)(angle1 / 1000.0);
|
||
BSP_OS_SemPost(&ptz_hori_get_angle_mutex);
|
||
return angle;
|
||
}
|
||
BSP_OS_SemPost(&ptz_hori_get_angle_mutex);
|
||
return -1;
|
||
}
|
||
|
||
|
||
/************************************************************************/
|
||
|
||
|
||
|
||
/// 垂直发送数据
|
||
///
|
||
/// 向as5047d发送数据
|
||
/// @param 无
|
||
/// @return 返回接收到的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
unsigned int as5047d_vert_send_package(unsigned int package)
|
||
{
|
||
unsigned int temp = 0;
|
||
unsigned int temp1 = 0;
|
||
unsigned int temp2 = 0;
|
||
AS5047D_VERT_CLK_LOW;
|
||
AS5047D_VERT_MOSI_LOW;
|
||
as5047d_delay_nop(2);
|
||
for(int i = 15; i >= 0; i--)
|
||
{
|
||
AS5047D_VERT_CLK_LOW;
|
||
as5047d_delay_nop(2);
|
||
temp = package & (1 << i);
|
||
if(temp != 0)
|
||
{
|
||
AS5047D_VERT_MOSI_HIGH;
|
||
}
|
||
else
|
||
{
|
||
AS5047D_VERT_MOSI_LOW;
|
||
}
|
||
as5047d_delay_nop(2);
|
||
AS5047D_VERT_CLK_HIGH;
|
||
as5047d_delay_nop(2);
|
||
|
||
temp1 = AS5047D_VERT_MISO_READ;
|
||
temp2 = temp2 | (temp1 << i);
|
||
|
||
temp1 = 0;
|
||
temp = 0;
|
||
}
|
||
AS5047D_VERT_CLK_LOW;
|
||
AS5047D_VERT_MOSI_LOW;
|
||
//返回的上一个指令回复的数据
|
||
return temp2;
|
||
}
|
||
|
||
/// 垂直接收数据
|
||
///
|
||
/// 接收as5047d返回的数据
|
||
/// @param 无
|
||
/// @return 返回接收到的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-07创建
|
||
unsigned int as5047d_vert_receive_package()
|
||
{
|
||
unsigned int temp = 0;
|
||
unsigned int temp1 = 0;
|
||
AS5047D_VERT_CLK_LOW;
|
||
as5047d_delay_nop(2);
|
||
for(int j = 15; j >= 0; j--)
|
||
{
|
||
AS5047D_VERT_CLK_HIGH;
|
||
as5047d_delay_nop(2);
|
||
temp = AS5047D_VERT_MISO_READ;
|
||
temp1 = temp1 | (temp << j);
|
||
AS5047D_VERT_CLK_LOW;
|
||
as5047d_delay_nop(2);
|
||
temp = 0;
|
||
}
|
||
AS5047D_VERT_CLK_LOW;
|
||
return temp1;
|
||
}
|
||
|
||
|
||
/// 垂直发送读指令
|
||
///
|
||
/// 发送读取as5047d数据指令
|
||
/// @param add 寄存器地址
|
||
/// @return 发送过程中接收的数据 111 1111 1111 1111
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-07创建
|
||
unsigned int as5047d_vert_read_command(unsigned int add)
|
||
{
|
||
unsigned int temp = 0;
|
||
add = as5047d_command_type(add,AS5047D_READ_COMMAND);
|
||
add = as5047d_Parity_bit_even(add);
|
||
//发送指令
|
||
temp = as5047d_vert_send_package(add);
|
||
//返回的上一个指令回复的数据
|
||
return temp;
|
||
}
|
||
|
||
|
||
/// 垂直读取as5047d寄存器中的值
|
||
///
|
||
/// 读取as5047d寄存器中的值
|
||
/// @param add 寄存器地址
|
||
/// @return 返回读取到的寄存器中的值
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-07创建
|
||
unsigned int as5047d_vert_read_data(unsigned int add)
|
||
{
|
||
|
||
unsigned int temp = 0;
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_VERT_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
|
||
//发送读指令
|
||
as5047d_vert_read_command(add);
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_VERT_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
|
||
//读取上一条指令获得的数据
|
||
temp = as5047d_vert_nop_command();
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
return temp;
|
||
}
|
||
|
||
/// 垂直发送写指令
|
||
///
|
||
/// 向as5047d发送写指令
|
||
/// @param add 寄存器地址
|
||
/// @return 发送过程中接收的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
unsigned int as5047d_vert_write_command(unsigned int add)
|
||
{
|
||
unsigned int temp = 0;
|
||
add = as5047d_command_type(add,AS5047D_WRITE_COMMAND);
|
||
add = as5047d_Parity_bit_even(add);
|
||
//发送指令
|
||
temp = as5047d_vert_send_package(add);
|
||
//返回的上一个指令回复的数据
|
||
return temp;
|
||
}
|
||
|
||
/// 垂直发送NOP指令
|
||
///
|
||
/// 向as5047d发送NOP指令
|
||
/// @param 无
|
||
/// @return 发送过程中接收的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
unsigned int as5047d_vert_nop_command()
|
||
{
|
||
unsigned int temp = 0;
|
||
temp = as5047d_vert_send_package(AS5047D_NOP);
|
||
//返回的上一个指令回复的数据
|
||
return temp;
|
||
}
|
||
|
||
/// 垂直清除错误标记指令
|
||
///
|
||
/// 向as5047d发送清除错误标记指令CLEAR ERROR FLAG command
|
||
/// @param 无
|
||
/// @return 1清除成功,0清除失败
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
unsigned int as5047d_vert_cef_command()
|
||
{
|
||
unsigned int temp = 0;
|
||
unsigned int temp1 = 0;
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_VERT_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
temp = as5047d_Parity_bit_even(AS5047D_CLEAR_ERROR_FLAG);
|
||
as5047d_vert_send_package(temp);
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_VERT_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
temp1 = as5047d_vert_nop_command();
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_VERT_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
temp1 = as5047d_vert_nop_command();
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
return temp1;
|
||
}
|
||
|
||
/// 垂直发送写指令并读取返回的数据
|
||
///
|
||
/// 向as5047d发送写指令并读取返回的数据
|
||
/// @param add 寄存器地址
|
||
/// @param data 需要写入的数据
|
||
/// @return 发送过程中接收的数据
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-08创建
|
||
As5047DJudgeReceivePackage as5047d_vert_write_data(unsigned int add,unsigned int data)
|
||
{
|
||
As5047DJudgeReceivePackage temp;
|
||
int i;
|
||
for(i = 0; i < AS5047D_WRITE_NUM; i++)
|
||
{
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
as5047d_delay_nop(20);
|
||
AS5047D_VERT_CSN_ENABLE;
|
||
as5047d_delay_nop(20);
|
||
|
||
//发送写入指令
|
||
as5047d_vert_write_command(add);
|
||
//从新写入新的数据,并返回寄存器中旧的数据
|
||
add = as5047d_command_type(data,AS5047D_WRITE_DATA);
|
||
add = as5047d_Parity_bit_even(data);
|
||
as5047d_vert_send_package(data);
|
||
//接收寄存器中的新数据0X3FFF 0011 1111 1111 1111
|
||
temp.package = as5047d_vert_nop_command();
|
||
temp = as5047d_vert_judge_receive_package(temp.package);
|
||
|
||
as5047d_delay_nop(2);
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
|
||
if(temp.Operation_Result != 1)
|
||
{
|
||
as5047d_vert_cef_command();
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
//判断写入的数据和最新返回的寄存器数据是否相同
|
||
if((data & 0X3FFF) == (temp.package & 0X3FFF))
|
||
{
|
||
temp.Operation_Result = 1;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
return temp;
|
||
}
|
||
|
||
/// 读取云台垂直角度
|
||
///
|
||
/// 读取云台垂直角度
|
||
/// @param 无
|
||
/// @param 无
|
||
/// @return 返回读取结果。-1读取失败,其他值读取成功
|
||
/// @par 修改日志
|
||
/// 杨鹏程于2017-09-27创建
|
||
float as5047d_vert_get_angle()
|
||
{
|
||
BSP_OS_SemWait(&ptz_vert_get_angle_mutex, 0u);
|
||
float angle = 0;
|
||
unsigned int angle1 = 0;
|
||
unsigned int temp = 0;
|
||
As5047DJudgeReceivePackage temp1;
|
||
memset(&temp1, 0, sizeof(temp1));
|
||
//读取角度数据
|
||
temp = as5047d_vert_read_data(AS5047D_ANGLE);
|
||
//判断接收到的数据是否正常
|
||
temp1 = as5047d_vert_judge_receive_package(temp);
|
||
//数据正确
|
||
if(temp1.Operation_Result == 1)
|
||
{
|
||
angle = (temp & 0x3FFF) * 0.02197265625;//0.02197265625 = 360.0 / 16384.0
|
||
angle1 = (unsigned int)(angle * 1000.0);//只保留小数点后3位
|
||
angle = (float)(angle1 / 1000.0);
|
||
BSP_OS_SemPost(&ptz_vert_get_angle_mutex);
|
||
return angle;
|
||
}
|
||
BSP_OS_SemPost(&ptz_vert_get_angle_mutex);
|
||
return -1;
|
||
}
|
||
|
||
|
||
|
||
/********************************************************************************/
|
||
/********************************************************************************/
|
||
/********************************************************************************/
|
||
//直接通过时钟读取角度
|
||
unsigned int as5047d_hori_clk_read_angle()
|
||
{
|
||
unsigned int temp1 = 0;
|
||
unsigned int temp2 = 0;
|
||
AS5047D_HORI_CLK_LOW;
|
||
AS5047D_HORI_MOSI_HIGH;
|
||
as5047d_delay_nop(2);
|
||
for(int i = 15; i >= 0; i--)
|
||
{
|
||
AS5047D_HORI_CLK_LOW;
|
||
as5047d_delay_nop(2);
|
||
AS5047D_HORI_CLK_HIGH;
|
||
as5047d_delay_nop(2);
|
||
|
||
temp1 = AS5047D_HORI_MISO_READ;
|
||
temp2 = temp2 | (temp1 << i);
|
||
|
||
temp1 = 0;
|
||
}
|
||
AS5047D_HORI_CLK_LOW;
|
||
return temp2;
|
||
}
|
||
|
||
//修改读取角度的方式,提升角度读取速度
|
||
unsigned int as5047d_hori_read_data_a()
|
||
{
|
||
|
||
unsigned int temp = 0;
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_HORI_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
|
||
//发送读指令
|
||
temp = as5047d_hori_clk_read_angle();
|
||
|
||
AS5047D_HORI_CSN_DISABLE;
|
||
return temp;
|
||
}
|
||
|
||
//新的判断方式
|
||
As5047DJudgeReceivePackage as5047d_hori_judge_receive_package_a(unsigned int package)
|
||
{
|
||
As5047DJudgeReceivePackage temp1;
|
||
memset(&temp1,0,sizeof(temp1));
|
||
|
||
temp1.package = package;
|
||
temp1.Operation_Result = 1;
|
||
//首先判断数据包的偶校验码是否正确
|
||
//效验码错误
|
||
if(package != as5047d_Parity_bit_even(package))
|
||
{
|
||
temp1.parity_error_package = 1;
|
||
temp1.Operation_Result = 0;
|
||
}
|
||
return temp1;
|
||
}
|
||
|
||
|
||
|
||
//新的读取角度方式
|
||
float as5047d_hori_get_angle_a()
|
||
{
|
||
BSP_OS_SemWait(&ptz_hori_get_angle_mutex, 0u);
|
||
float angle = 0;
|
||
unsigned int angle1 = 0;
|
||
unsigned int temp = 0;
|
||
As5047DJudgeReceivePackage temp1;
|
||
memset(&temp1, 0, sizeof(temp1));
|
||
//读取角度数据
|
||
temp = as5047d_hori_read_data_a();
|
||
//判断接收到的数据是否正常
|
||
temp1 = as5047d_hori_judge_receive_package_a(temp);
|
||
//数据正确
|
||
if(temp1.Operation_Result == 1)
|
||
{
|
||
angle = (temp & 0x3FFF) * 0.02197265625;//0.02197265625 = 360.0 / 16384.0
|
||
angle1 = (unsigned int)(angle * 1000.0);//只保留小数点后3位
|
||
angle = (float)(angle1 / 1000.0);
|
||
BSP_OS_SemPost(&ptz_hori_get_angle_mutex);
|
||
return angle;
|
||
}
|
||
BSP_OS_SemPost(&ptz_hori_get_angle_mutex);
|
||
return -1;
|
||
}
|
||
|
||
/********************************************************************************/
|
||
/********************************************************************************/
|
||
/********************************************************************************/
|
||
|
||
//直接通过时钟读取角度
|
||
unsigned int as5047d_vert_clk_read_angle()
|
||
{
|
||
unsigned int temp1 = 0;
|
||
unsigned int temp2 = 0;
|
||
AS5047D_VERT_CLK_LOW;
|
||
AS5047D_VERT_MOSI_HIGH;
|
||
as5047d_delay_nop(2);
|
||
for(int i = 15; i >= 0; i--)
|
||
{
|
||
AS5047D_VERT_CLK_LOW;
|
||
as5047d_delay_nop(2);
|
||
AS5047D_VERT_CLK_HIGH;
|
||
as5047d_delay_nop(2);
|
||
|
||
temp1 = AS5047D_VERT_MISO_READ;
|
||
temp2 = temp2 | (temp1 << i);
|
||
|
||
temp1 = 0;
|
||
}
|
||
AS5047D_VERT_CLK_LOW;
|
||
return temp2;
|
||
}
|
||
|
||
//修改读取角度的方式,提升角度读取速度
|
||
unsigned int as5047d_vert_read_data_a()
|
||
{
|
||
|
||
unsigned int temp = 0;
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
as5047d_delay_nop(4);
|
||
AS5047D_VERT_CSN_ENABLE;
|
||
as5047d_delay_nop(4);
|
||
|
||
//发送读指令
|
||
temp = as5047d_vert_clk_read_angle();
|
||
|
||
AS5047D_VERT_CSN_DISABLE;
|
||
return temp;
|
||
}
|
||
|
||
//新的判断方式
|
||
As5047DJudgeReceivePackage as5047d_vert_judge_receive_package_a(unsigned int package)
|
||
{
|
||
As5047DJudgeReceivePackage temp1;
|
||
memset(&temp1,0,sizeof(temp1));
|
||
|
||
temp1.package = package;
|
||
temp1.Operation_Result = 1;
|
||
//首先判断数据包的偶校验码是否正确
|
||
//效验码错误
|
||
if(package != as5047d_Parity_bit_even(package))
|
||
{
|
||
temp1.parity_error_package = 1;
|
||
temp1.Operation_Result = 0;
|
||
}
|
||
return temp1;
|
||
}
|
||
|
||
|
||
|
||
//新的读取角度方式
|
||
float as5047d_vert_get_angle_a()
|
||
{
|
||
BSP_OS_SemWait(&ptz_vert_get_angle_mutex, 0u);
|
||
float angle = 0;
|
||
unsigned int angle1 = 0;
|
||
unsigned int temp = 0;
|
||
As5047DJudgeReceivePackage temp1;
|
||
memset(&temp1, 0, sizeof(temp1));
|
||
//读取角度数据
|
||
temp = as5047d_vert_read_data_a();
|
||
//判断接收到的数据是否正常
|
||
temp1 = as5047d_vert_judge_receive_package_a(temp);
|
||
//数据正确
|
||
if(temp1.Operation_Result == 1)
|
||
{
|
||
angle = (temp & 0x3FFF) * 0.02197265625;//0.02197265625 = 360.0 / 16384.0
|
||
angle1 = (unsigned int)(angle * 1000.0);//只保留小数点后3位
|
||
angle = (float)(angle1 / 1000.0);
|
||
BSP_OS_SemPost(&ptz_vert_get_angle_mutex);
|
||
return angle;
|
||
}
|
||
BSP_OS_SemPost(&ptz_vert_get_angle_mutex);
|
||
return -1;
|
||
}
|
||
|
||
#endif
|
||
/********************************************************************************/
|
||
/********************************************************************************/
|
||
/********************************************************************************/
|
||
|
||
#ifdef TMR3109
|
||
|
||
//TMR3109 操作码定义
|
||
#define TMR3109_OPCODE_WRITE_EEPROM 0x01 //001 写EEPROM
|
||
#define TMR3109_OPCODE_WRITE_REGISTER 0x05 //101 写寄存器
|
||
#define TMR3109_OPCODE_READ_REGISTER 0x06 //110 读寄存器
|
||
#define TMR3109_OPCODE_CHANGE_MODE 0x07 //111 模式切换
|
||
#define TMR3109_OPCODE_READ_ANGLE 0x03 //011 读角度
|
||
|
||
//TMR3109设备结构体
|
||
typedef struct{
|
||
uint8_t device_id; //设备地址
|
||
uint32_t spi_periph; //SPI外设地址
|
||
uint32_t cs_pin; //片选引脚
|
||
uint32_t cs_gpio_periph; //片选引脚外设地址
|
||
}TMR3109_Device;
|
||
|
||
//角度数据结构体
|
||
typedef struct{
|
||
uint32_t angle_raw; //23位原始角度值
|
||
float angle_degree; //角度值,单位:度
|
||
uint8_t crc; //CRC校验码
|
||
uint8_t error; //错误码
|
||
bool is_valid; //是否有效
|
||
}TMR3109_AngleData;
|
||
|
||
//TMR3109设备定义
|
||
TMR3109_Device tmr3109_dev1 = {
|
||
.device_id = 1,
|
||
.spi_periph = SPI2,
|
||
.cs_pin = GPIO_PIN_15,
|
||
.cs_gpio_periph = GPIOA,
|
||
};
|
||
|
||
TMR3109_Device tmr3109_dev2 = {
|
||
.device_id = 2,
|
||
.spi_periph = SPI4,
|
||
.cs_pin = GPIO_PIN_11,
|
||
.cs_gpio_periph = GPIOE,
|
||
};
|
||
|
||
TMR3109_AngleData hori_angle_data = {0};
|
||
TMR3109_AngleData vert_angle_data = {0};
|
||
|
||
//暂定微秒级延迟函数(基于SysTick)(后期删除,所有延迟函数更换为统一的函数)
|
||
void delay_us(uint32_t us)
|
||
{
|
||
uint32_t start, now, delta, reload, us_tick;
|
||
start = SysTick->VAL;
|
||
reload = SysTick->LOAD;
|
||
us_tick = SystemCoreClock / 1000000UL;
|
||
|
||
do {
|
||
now = SysTick->VAL;
|
||
delta = start > now? start - now : reload + start - now;
|
||
} while (delta < us_tick * us);
|
||
}
|
||
|
||
//TMR3109初始化
|
||
void TMR3109_Init(void)
|
||
{
|
||
//初始化SPI2(U33编码器)
|
||
rcu_periph_clock_enable(RCU_GPIOA);
|
||
rcu_periph_clock_enable(RCU_GPIOC);
|
||
rcu_periph_clock_enable(RCU_SPI2);
|
||
|
||
//配置SPI2引脚
|
||
gpio_af_set(GPIOC, GPIO_AF_6, GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12); //PC10,11,12复用为SPI2
|
||
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12);
|
||
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | /*GPIO_PIN_11 | */GPIO_PIN_12); //注意一下MISO是输入模式,这里可能会有问题
|
||
|
||
//配置CS引脚
|
||
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
|
||
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
|
||
gpio_bit_set(GPIOA, GPIO_PIN_15); //默认CS引脚高电平
|
||
|
||
//配置SPI2参数(不超过8MHz,暂定5MHz左右)
|
||
spi_parameter_struct spi_init_struct;
|
||
spi_struct_para_init(&spi_init_struct);
|
||
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
|
||
spi_init_struct.device_mode = SPI_MASTER;
|
||
spi_init_struct.frame_size = SPI_FRAMESIZE_16BIT; //16位帧长
|
||
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE; //时钟极性为低,相位为第二边缘(下降沿)
|
||
spi_init_struct.nss = SPI_NSS_SOFT; //软件控制
|
||
spi_init_struct.prescale = SPI_PSC_16; //时钟预分频系数为16(5MHz左右)
|
||
spi_init_struct.endian = SPI_ENDIAN_MSB; //高位先出
|
||
spi_init(SPI2, &spi_init_struct);
|
||
spi_enable(SPI2);
|
||
|
||
//初始化SPI4(U32编码器)
|
||
rcu_periph_clock_enable(RCU_GPIOE);
|
||
rcu_periph_clock_enable(RCU_SPI4);
|
||
|
||
//配置SPI4引脚
|
||
gpio_af_set(GPIOE, GPIO_AF_6, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14); //PE12,13,14复用为SPI4
|
||
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14);
|
||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14); //注意一下MISO是输入模式,这里可能会有问题
|
||
|
||
//配置CS引脚
|
||
gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_11);
|
||
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
|
||
gpio_bit_set(GPIOE, GPIO_PIN_11); //默认CS引脚高电平
|
||
|
||
//配置SPI4参数(不超过8MHz,暂定5MHz左右)
|
||
spi_parameter_struct spi_init_struct2;
|
||
spi_struct_para_init(&spi_init_struct2);
|
||
spi_init_struct2.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
|
||
spi_init_struct2.device_mode = SPI_MASTER;
|
||
spi_init_struct2.frame_size = SPI_FRAMESIZE_16BIT; //16位帧长
|
||
spi_init_struct2.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE; //时钟极性为低,相位为第二边缘(下降沿)
|
||
spi_init_struct2.nss = SPI_NSS_SOFT; //软件控制
|
||
spi_init_struct2.prescale = SPI_PSC_16; //时钟预分频系数为16(5MHz左右)
|
||
spi_init_struct2.endian = SPI_ENDIAN_MSB; //高位先出
|
||
spi_init(SPI4, &spi_init_struct2);
|
||
spi_enable(SPI4);
|
||
|
||
//初始化后延迟
|
||
}
|
||
|
||
void as5047d_init()
|
||
{
|
||
TMR3109_Init();
|
||
}
|
||
|
||
|
||
// SPI发送接收32位数据(GD32的SPI只支持8位或16位传输,所以需要分两次发送)
|
||
static uint32_t spi_transfer_32bit(uint32_t spi_periph, uint32_t data)
|
||
{
|
||
uint16_t temp_high, temp_low;
|
||
uint32_t received_data = 0;
|
||
uint32_t start_tick;
|
||
const uint32_t timeout_ticks = 10; // 10ms超时
|
||
|
||
// 提取要发送的32位数据的高16位和低16位
|
||
temp_high = (uint16_t)(data >> 16); // 高16位
|
||
temp_low = (uint16_t)(data & 0xFFFF); // 低16位
|
||
|
||
// 1. 先发送高16位,并读取高16位响应
|
||
start_tick = OSTimeGet();
|
||
while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE));
|
||
{
|
||
//超时判断
|
||
if (OSTimeGet() - start_tick > timeout_ticks) {
|
||
// 根据SPI外设判断使用哪个片选引脚
|
||
if (spi_periph == SPI2) {
|
||
gpio_bit_set(GPIOA, GPIO_PIN_15); // tmr3109_dev1 CS拉高
|
||
} else if (spi_periph == SPI4) {
|
||
gpio_bit_set(GPIOE, GPIO_PIN_11); // tmr3109_dev2 CS拉高
|
||
}
|
||
return 0xFFFFFFFF;
|
||
}
|
||
}
|
||
spi_i2s_data_transmit(spi_periph, temp_high);
|
||
|
||
start_tick = OSTimeGet();
|
||
while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE));
|
||
{
|
||
if (OSTimeGet() - start_tick > timeout_ticks) {
|
||
if (spi_periph == SPI2) {
|
||
gpio_bit_set(GPIOA, GPIO_PIN_15);
|
||
} else if (spi_periph == SPI4) {
|
||
gpio_bit_set(GPIOE, GPIO_PIN_11);
|
||
}
|
||
return 0xFFFFFFFF;
|
||
}
|
||
}
|
||
received_data = (uint32_t)spi_i2s_data_receive(spi_periph) << 16; // 存储到高16位
|
||
|
||
// 2. 紧接着发送低16位,并读取低16位响应
|
||
start_tick = OSTimeGet();
|
||
while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE));
|
||
{
|
||
if (OSTimeGet() - start_tick > timeout_ticks) {
|
||
if (spi_periph == SPI2) {
|
||
gpio_bit_set(GPIOA, GPIO_PIN_15);
|
||
} else if (spi_periph == SPI4) {
|
||
gpio_bit_set(GPIOE, GPIO_PIN_11);
|
||
}
|
||
return 0xFFFFFFFF;
|
||
}
|
||
}
|
||
spi_i2s_data_transmit(spi_periph, temp_low);
|
||
|
||
start_tick = OSTimeGet();
|
||
while(RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE));
|
||
{
|
||
if (OSTimeGet() - start_tick > timeout_ticks) {
|
||
if (spi_periph == SPI2) {
|
||
gpio_bit_set(GPIOA, GPIO_PIN_15);
|
||
} else if (spi_periph == SPI4) {
|
||
gpio_bit_set(GPIOE, GPIO_PIN_11);
|
||
}
|
||
return 0xFFFFFFFF;
|
||
}
|
||
}
|
||
received_data |= spi_i2s_data_receive(spi_periph); // 存储到低16位
|
||
|
||
return received_data;
|
||
}
|
||
|
||
//设置CS引脚
|
||
static void set_cs(TMR3109_Device* dev, bool state)
|
||
{
|
||
if(state)
|
||
{
|
||
gpio_bit_set(dev->cs_gpio_periph, dev->cs_pin);
|
||
}
|
||
else
|
||
{
|
||
gpio_bit_reset(dev->cs_gpio_periph, dev->cs_pin);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 计算TMR3109角度数据的CRC4校验码
|
||
* @param angle_data 23位角度数据
|
||
* @return 4位CRC校验码
|
||
*/
|
||
uint8_t TMR3109_CalculateCRC(uint32_t angle_data_23bit)
|
||
{
|
||
// 多项式: x^4 + x^3 + x^2 + 1 = 0b1101 = 0x0D
|
||
const uint8_t polynomial = 0x0D;
|
||
|
||
// 初始值: 0b0011 = 0x3
|
||
uint8_t crc = 0x3;
|
||
|
||
// 构建24位数据: 1位0 + 23位角度值
|
||
uint32_t data = angle_data_23bit; // 低23位是角度值
|
||
// 最高位已经是0(因为angle_data_23bit只有23位)
|
||
|
||
// 处理24位数据(从最高位开始)
|
||
for (int i = 23; i >= 0; i--) {
|
||
// 检查CRC最高位
|
||
uint8_t crc_msb = (crc >> 3) & 0x1;
|
||
|
||
// 获取当前数据位
|
||
uint8_t data_bit = (data >> i) & 0x1;
|
||
|
||
// CRC左移1位,最低位补0
|
||
crc = (crc << 1) & 0x0F;
|
||
|
||
// 如果CRC最高位与数据位异或结果为1,则与多项式异或
|
||
if (crc_msb ^ data_bit) {
|
||
crc ^= polynomial;
|
||
}
|
||
}
|
||
|
||
return crc & 0x0F; // 确保返回4位
|
||
}
|
||
|
||
/**
|
||
* @brief 验证TMR3109角度数据的CRC
|
||
* @param angle_data_23bit 23位角度数据
|
||
* @param received_crc 接收到的4位CRC
|
||
* @return true表示CRC校验通过
|
||
*/
|
||
bool TMR3109_CheckCRC(uint32_t angle_data_23bit, uint8_t received_crc)
|
||
{
|
||
uint8_t calculated_crc = TMR3109_CalculateCRC(angle_data_23bit);
|
||
return (calculated_crc == received_crc);
|
||
}
|
||
|
||
//读角度
|
||
bool TMR3109_ReadAngle(TMR3109_Device* dev, TMR3109_AngleData* angle_data)
|
||
{
|
||
if(dev == NULL || angle_data == NULL) return false;
|
||
|
||
//读角度命令: 操作码(3bit)+地址(8bit)+空闲(5bit)+数据(16bit)
|
||
uint32_t tx_data = (TMR3109_OPCODE_READ_ANGLE << 29)| (0X00 << 21) | (0X00 << 16) | (0X00 << 0) ;
|
||
|
||
set_cs(dev, false); //使能CS
|
||
delay_us(20); //SPI启动时间 优化点
|
||
|
||
//发送32位数据并接收响应
|
||
uint32_t rx_data = spi_transfer_32bit(dev->spi_periph, tx_data);
|
||
|
||
set_cs(dev, true); //拉高片选
|
||
|
||
//解析响应数据
|
||
//d27~d5: 23位角度数据,d4~d1: CRC校验码,d0: error位
|
||
angle_data->angle_raw = (rx_data >> 5) & 0X7FFFFF; //取23位角度数据
|
||
angle_data->crc = (rx_data >> 1) & 0X0F; //取4位CRC校验码
|
||
angle_data->error = rx_data & 0X01; //取1位error位
|
||
|
||
//计算角度值((∑_{i=0}^{23} Angle<i> * 2^i) / 8388608 * 360)
|
||
angle_data->angle_degree = (angle_data->angle_raw * 360.0f) / 8388608.0f;
|
||
|
||
//数据有效性校验(加入CRC校验)
|
||
bool crc_valid = TMR3109_CheckCRC(angle_data->angle_raw, angle_data->crc);
|
||
// angle_data->is_valid = 0/*(angle_data->error == 0)*/; //注意这里的error位有问题,手册没找到error位的具体定义
|
||
angle_data->is_valid = crc_valid;
|
||
|
||
//CRC错误记录逻辑,后期添加
|
||
// if(!crc_valid) {
|
||
// //CRC校验失败,记录错误信息
|
||
// //...
|
||
// }
|
||
|
||
return angle_data->is_valid;
|
||
}
|
||
|
||
float as5047d_hori_get_angle_a()
|
||
{
|
||
if (TMR3109_ReadAngle(&tmr3109_dev1, &hori_angle_data)) {
|
||
return hori_angle_data.angle_degree;
|
||
}
|
||
return 0.0f;
|
||
}
|
||
|
||
float as5047d_vert_get_angle_a()
|
||
{
|
||
if (TMR3109_ReadAngle(&tmr3109_dev2, &vert_angle_data)) {
|
||
return vert_angle_data.angle_degree;
|
||
}
|
||
return 0.0f;
|
||
}
|
||
|
||
#endif
|