HAL STM32 SSI/SPI方式读取MT6701磁编码器获取角度例程

HAL STM32 SSI/SPI方式读取MT6701磁编码器获取角度例程


SSI方式完全可以使用3个IO配置为输入输出模式(两个配置为输出,一个配置为输入),通过SSI协议,读取电平状态,实现对数据解析。

cpp 复制代码
#define Loss_of_Track       4
#define Button_Detected     3
#define Field_Weak          2
#define Field_Strong        1
#define Normal              0


/*
 * SSI 方式读取信息
 * mode == 0 返回角度信息,0~360 浮点数
 * mode == 1 返回磁场信息
 */
double ReadDataSSI(uint8_t mode)
{
    uint8_t RawData[25] = {0};
    uint16_t angle = 0;
    double fangle = 0;

    HAL_GPIO_WritePin(SSI_CSN_GPIO_Port,SSI_CSN_Pin,GPIO_PIN_RESET);        //起始信号
    Delay_us(2);

    HAL_GPIO_WritePin(SSI_CLK_GPIO_Port,SSI_CLK_Pin,GPIO_PIN_RESET);        //跳过第一个时钟沿
    Delay_us(2);
    HAL_GPIO_WritePin(SSI_CLK_GPIO_Port,SSI_CLK_Pin,GPIO_PIN_SET);
    Delay_us(2);

    for(uint8_t i = 0; i < 25; i++)                                                                 //读取数据
    {
        HAL_GPIO_WritePin(SSI_CLK_GPIO_Port,SSI_CLK_Pin,GPIO_PIN_RESET);
        RawData[i] = HAL_GPIO_ReadPin(SSI_DI_GPIO_Port,SSI_DI_Pin);
        HAL_GPIO_WritePin(SSI_CLK_GPIO_Port,SSI_CLK_Pin,GPIO_PIN_SET);
        Delay_us(2);
    }
    HAL_GPIO_WritePin(SSI_CSN_GPIO_Port,SSI_CSN_Pin,GPIO_PIN_SET);          //结束信号

    for(uint8_t i = 0; i < 14; i++)
        angle += RawData[i] * (2 << (13 - i));
    fangle = (double)(angle * 180.0) / 16384.0;     //角度信息

    switch (mode)
    {
        case 0:
            return fangle;
        case 1:
        {
            if(RawData[14])
                return Loss_of_Track;
            else if(RawData[15])
                return Button_Detected;
            else if(RawData[16])
                return Field_Weak;
            else if(RawData[17])
                return Field_Strong;
            else
                return Normal;
        }
        default:
            return 0;
    }
}
  • 🌿引脚配置:

📚SSI测试工程

c 复制代码
链接:https://pan.baidu.com/s/1es233q_NBo_s_fLkgbmTjw?pwd=r90i 
提取码:r90i

⛳SPI方式

📗STM32 SPI参数配置:
  • 🌿STM32CubeMX中SPI基本配置信息:(其中Data Size,这里选择配置的是8位,配置16位也是可以的,不过软件编程上就与8位的编程代码就不同,不通用)。

  • SPI串行同步时钟可以设置为不同的极性(Clock Polarity ,CPOL)与相位(Clock Phase ,CPHA)。

  • 时钟的极性(CPOL)用来决定在总线空闲时,同步时钟(SCK)信号线上的电位是高电平还是低电平。

  • 当时钟极性为0时(CPOL=0),SCK信号线在空闲时为低电平;当时钟极性为1时(CPOL=1),SCK信号线在空闲时为高电平;

  • 时钟的相位(CPHA)用来决定何时进行信号采样。

  • 当时钟相位为1时(CPHA=1),在SCK信号线的第二个跳变沿进行采样;这里的跳变沿究竟是上升沿还是下降沿,取决于时钟的极性。当时钟极性(CPOL)为0时,取下降沿;当时钟极性(CPOL)为1时,取上升沿;如下图:

  • 🔖设置依据:根据手册SSI协议,可知:CLK空闲状态为low,决定CPOL配置为low,推荐CLK下降沿采集数据,那就配置CPHA为2,在SCK信号线的第二个跳变沿进行采样。


  • 🌾 补充:
    • 当时钟相位为0时(CPHA=0),在SCK信号线的第一个跳变沿进行采样。跳变沿同样与时钟极性有关:当时钟极性为0时,取上升沿;当时钟极性为1时,取下降沿;如下图:
  • 对应:

SPI数据读取和转换实现

c 复制代码
void MT6701_Read_RAW(uint8_t* pBuffer)   
{ 
	uint16_t i; 
	 MT6701_CSN_CLR;//MT6701_CSN=0  //片选 
	for (i = 0; i < 4; i++)
	{ 
		pBuffer[i]=SPIx_ReadWriteByte(0xFF);    //循环读入字节数据  
	}	
	 MT6701_CSN_SET;  //MT6701_CSN=1
} 

/*!
 *  @brief  Return position of encoder
 *  @return Angle value of encoder position
 */
float angleRead( void ){
	float angle_f = 0.0f;
	uint8_t data[3];
	uint16_t angle_u16;
	
	MT6701_Read_RAW(data);
		angle_u16  = (uint16_t)(data[1] >> 2);
		angle_u16 |= ((uint16_t)data[0] << 6);
		 angle_f =  (float)angle_u16 * (360.0f/16384.0f);
	return angle_f;
}
  • 🎉优化处理
c 复制代码
//angle_raw返回原始角度数据,angle转换后的角度值:0-360,field_status磁场强度;
void mt6701_read(uint16_t*angle_raw, float*angle, uint8_t*field_status)
{
    float angle_f = 0.0f;
    uint8_t status;
    uint8_t data[3];
    uint16_t angle_u16;

    MT6701_Read_RAW(data);
    angle_u16 = (uint16_t)(data[1] >> 2); //原始值
    angle_u16 |= ((uint16_t)data[0] << 6);
    status = (data[2] >> 6);
    status |= (data[1] & 0x03) << 2;
    if(angle_raw != NULL) {
        *angle_raw = angle_u16;
    }

    if(angle != NULL) {

        angle_f = (float)angle_u16 * (360.0f / 16384.0f);
        *angle = angle_f;
    }
    if(field_status != NULL) {
        *field_status = status & 0x03;
    }
}
  • 🔖测试效果:

📚SPI测试代码

c 复制代码
链接:https://pan.baidu.com/s/1X3vUEo5mW3vEGRbXftowxw?pwd=7o6g 
提取码:7o6g

📙读取24位数据并CRC校验功能测试

  • 📝代码实现部分:
c 复制代码
 unsigned int Angle = 0;
uint32_t AngleIn24bits = 0;
uint8_t Spi_TxData[4]={0x83,0xff,0xff,0xff};///03 04 05 寄存器存角度
uint8_t Spi_pRxData[4]={0};

uint32_t ReadAngle(void)
{
    //Read in Burst mode
	    
	    HAL_GPIO_WritePin(MT6701_CS_GPIO_Port, MT6701_CS_Pin, GPIO_PIN_RESET);///CSN LOW   
		HAL_SPI_TransmitReceive(&hspi1, &Spi_TxData[0], &Spi_pRxData[0],0x03,0xffff);
	    HAL_GPIO_WritePin(MT6701_CS_GPIO_Port, MT6701_CS_Pin, GPIO_PIN_SET);///CSN HIGH

	    AngleIn24bits= (Spi_pRxData[0]<<16)|(Spi_pRxData[1]<<8)|(Spi_pRxData[2]);
	 //   AngleIn14bits >>= 10;
	   	
        return (AngleIn24bits);	    
}
uint8_t crc6(uint8_t *data, uint8_t length)  
{  
	uint8_t i;  
	uint8_t crc = 0;    // Initial value  
	
	while(length--)  
	{  
		 crc ^= *data++; // crc ^= *data; data++;
		for (i=6; i>0; --i)  
        { 
            if (crc & 0x20)
                crc = (crc << 1) ^ 0x03;
            else
                crc = (crc << 1);
        }
	 }  
	return crc&0x3f;  
} 

int main(void)
{

  /* USER CODE BEGIN 1 */
	uint8_t s[3];
	uint8_t crcvalue = 0;
	uint32_t AngleInHex = 0;
					float angle=0.0f;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		 AngleInHex = ReadAngle();
			s[0]=AngleInHex>>18;
			s[1]=AngleInHex>>12;
			s[2]=AngleInHex>>6;
	        
			if(crc6(s, 3)==(AngleInHex&0x3f))
			{   
				printf("\r\nReadcrc=0x%x\r\n",AngleInHex&0x3F);
				
				printf("Cacucrc=0x%x\r\n",crc6(s, 3)&0x3F);
				printf("%.2f\r\n",(AngleInHex>>10)*360/16384.0);
				printf("%X\r\n",AngleInHex);
				 HAL_Delay(5);
				printf("\n-------------------\n");
				 HAL_Delay(5);
			}
			else
			{
				printf("\r\nReadcrc=0x%x\r\n",AngleInHex&0x3F);
				printf("Cacucrc=0x%x\r\n",crc6(s, 3)&0x3F);
			    printf("CRC check error!\r\n");
				printf("%.2f\r\n",(AngleInHex>>10)*360/16384.0);
				 HAL_Delay(5);
				printf("\n\r--------------------\n\r");
			}
		HAL_Delay(500);
  }
  /* USER CODE END 3 */
}
  • 📄打印测试


📚读取数据并带CRC校验测试工程

c 复制代码
链接:https://pan.baidu.com/s/1p-tUWT0P2aetlLwCr9X-IQ?pwd=1epn 
提取码:1epn

📘SPI +DMA读取数据并带CRC校验测试工程

  • 🥕基于读取数据并带CRC校验测试工程版本基础上调整而来的。
c 复制代码
链接:https://pan.baidu.com/s/1GCT23_lJC4ocbHautazoxg?pwd=9kvi 
提取码:9kvi
相关推荐
LateBloomer7773 分钟前
FreeRTOS——信号量
笔记·stm32·学习·freertos
wenchm39 分钟前
细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的另一种方法
stm32·单片机·嵌入式硬件
嵌新程5 小时前
day03(单片机高级)RTOS
stm32·单片机·嵌入式硬件·freertos·rtos·u575
Lin2012305 小时前
STM32 Keil5 attribute 关键字的用法
stm32·单片机·嵌入式硬件
电工小王(全国可飞)5 小时前
STM32 RAM在Memory Map中被分为3个区域
stm32·单片机·嵌入式硬件
maxiumII5 小时前
Diving into the STM32 HAL-----DAC笔记
笔记·stm32·嵌入式硬件
时光の尘9 小时前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
日晨难再12 小时前
嵌入式:STM32的启动(Startup)文件解析
stm32·单片机·嵌入式硬件
PegasusYu1 天前
STM32CUBEIDE FreeRTOS操作教程(九):eventgroup事件标志组
stm32·教程·rtos·stm32cubeide·free-rtos·eventgroup·时间标志组
文弱书生6561 天前
输出比较简介
stm32