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
相关推荐
scan11 小时前
单片机串口接收状态机STM32
stm32·单片机·串口·51·串口接收
Mortal_hhh3 小时前
VScode的C/C++点击转到定义,不是跳转定义而是跳转声明怎么办?(内附详细做法)
ide·vscode·stm32·编辑器
Mr.谢尔比4 小时前
电赛入门之软件stm32keil+cubemx
stm32·单片机·嵌入式硬件·mcu·信息与通信·信号处理
LightningJie4 小时前
STM32中ARR(自动重装寄存器)为什么要减1
stm32·单片机·嵌入式硬件
鹿屿二向箔5 小时前
STM32外设之SPI的介绍
stm32
西瓜籽@5 小时前
STM32——毕设基于单片机的多功能节能窗控制系统
stm32·单片机·课程设计
极客小张8 小时前
基于STM32的智能充电桩:集成RTOS、MQTT与SQLite的先进管理系统设计思路
stm32·单片机·嵌入式硬件·mqtt·sqlite·毕业设计·智能充电桩
m0_7393128711 小时前
【STM32】项目实战——OV7725/OV2604摄像头颜色识别检测(开源)
stm32·单片机·嵌入式硬件
嵌入式小章11 小时前
基于STM32的实时时钟(RTC)教学
stm32·嵌入式硬件·实时音视频
徐嵌13 小时前
STM32项目---水质水位检测
stm32·单片机·嵌入式硬件