问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32 SPI获取MT6816磁编码器绝对角度

创作时间:
作者:
@小白创作中心

STM32 SPI获取MT6816磁编码器绝对角度

引用
CSDN
1.
https://blog.csdn.net/m0_64386340/article/details/139183344

本文将详细介绍如何使用STM32微控制器通过SPI接口读取MT6816磁编码器的绝对角度数据。文章将从硬件连接、软件编程到最终的角度数据显示,为读者提供一个完整的解决方案。

一、MT6816简介

MT6816是一款由MagnTek推出的基于AMR原理的磁编码器,其支持ABZ&UVW&PWM&SPI四种模式。可以输出分辨率为14位的绝对角度数据;支持最高转速25000RPM;工作温度范围为-40~125℃。常应用于直流无刷电机控制、伺服电机控制,闭环步进电机控制。

其引脚定义如下:

二、MT6816外围电路

1.模式选择

SPI(3线、4线)模式:

R2用0R电阻短路,或者HVPP引脚接到3.3V。

ABZ、UVW、和PWM模式:

R3用0R电阻短路,或者HVPP接地。

2.PCB布局及注意事项

注:MT6816芯片要位于步进电机的几何中心且芯片底部不能布线。

3.磁铁的选择及安装注意事项

使用镜像磁铁,用胶水粘在步进电机尾部的转动轴上,芯片距离磁铁建议1-3mm。

4.与STM32连接

MT6816CS接PA4; SCK接PA5; MISO接PA6; MOSI接PA7。

三、MT6816 4线SPI介绍

1.基本实现逻辑

基本逻辑是拉低片选,先输入0x83,写入03寄存器的地址和指令,读取03寄存器的数据,拉高片选,得到第一个数据,再次拉低片选,写入0x04寄存器的地址和指令,读取04寄存器的数据,拉高片选,重复得到05的,然后按照表格上的顺序进行运算,将03数据左移8位,加上04的数据,得到的新数据左移2位得到角度数值,除以16384,乘以角度360°得到角度值。

2.SPI底层代码编写

spi.c文件:

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:SPI写SS引脚电平,SS仍由软件模拟
  * 参    数:BitValue 协议层传入的当前需要写入SS的电平,范围0~1
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SS为低电平,当BitValue为1时,需要置SS为高电平
  */
void MySPI_W_SS(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);		//根据BitValue,设置SS引脚的电平
}

/**
  * 函    数:SPI初始化  CS PA4; SCK PA5; MISO PA6; MOSI PA7
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Init(void)
{
    /*开启时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);	//开启SPI1的时钟
    
    /*GPIO初始化*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA4引脚初始化为推挽输出
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA5和PA7引脚初始化为复用推挽输出
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA6引脚初始化为上拉输入
    
    /*SPI初始化*/
    SPI_InitTypeDef SPI_InitStructure;						//定义结构体变量
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;			//模式,选择为SPI主模式
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;	//方向,选择2线全双工
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//数据宽度,选择为8位
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;		//先行位,选择高位先行
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;	//波特率分频,选择128分频
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;				//SPI极性,选择高极性
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;			//SPI相位,选择第二个时钟边沿采样,极性和相位决定选择SPI模式3
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;				//NSS,选择由软件控制
    SPI_InitStructure.SPI_CRCPolynomial = 7;				//CRC多项式,暂时用不到,给默认值7
    SPI_Init(SPI1, &SPI_InitStructure);						//将结构体变量交给SPI_Init,配置SPI1
    
    /*SPI使能*/
    SPI_Cmd(SPI1, ENABLE);									//使能SPI1,开始运行
    
    /*设置默认电平*/
    MySPI_W_SS(1);											//SS默认高电平
}

/**
  * 函    数:SPI起始
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Start(void)
{
    MySPI_W_SS(0);				//拉低SS,开始时序
}

/**
  * 函    数:SPI终止
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Stop(void)
{
    MySPI_W_SS(1);				//拉高SS,终止时序
}

/**
  * 函    数:SPI交换传输一个字节,使用SPI模式3
  * 参    数:ByteSend 要发送的一个字节
  * 返 回 值:接收的一个字节
  */
uint8_t MySPI_SwapByte(uint16_t ByteSend)
{
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);	//等待发送数据寄存器空
    
    SPI_I2S_SendData(SPI1, ByteSend);								//写入数据到发送数据寄存器,开始产生时序
    
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);	//等待接收数据寄存器非空
    
    return SPI_I2S_ReceiveData(SPI1);								//读取接收到的数据并返回
}

3.MT6816读取角度代码:

#include "stm32f10x.h"                  // Device header
#include "MySPI.h"

void MT6816_Init(void)
{
    MySPI_Init();					
}

float MT6816_Get_AngleData(void)
{
    uint8_t Data1 = 0x00;
    uint8_t Data2 = 0x00;
    
    MySPI_Start();
  MySPI_SwapByte(0x83);            //向MT6816发送读取角度寄存器指令
    Data1 =MySPI_SwapByte(0xFF);    //将角度数据读回来
  MySPI_Stop();
            
  MySPI_Start();
  MySPI_SwapByte(0x04);
    Data2 =MySPI_SwapByte(0xFF);
  MySPI_Stop();
    
    float MyAngle = (((float)((Data1*256+Data2)/4)/16384)*360);    //将0X03和0X04数据进行拼接并将其右移两位,保留14位角度数据,根据公式将读取到的数据转换为角度
    return MyAngle;
}

4.将角度值显示到OLED屏幕

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MT6816.h"

float Angle;

int main(void)
{
    OLED_Init();						
    MT6816_Init();	
    OLED_ShowString(1,1,"Angle:");
    OLED_ShowChar(1,12,'.');
    while (1)
    {
        float Angle = MT6816_Get_AngleData();
        int FractionalPart = (int)((Angle - (int)Angle)* 1000);//角度小数部分计算,并将其化为整数
        
        //float LinearDisplacement = Angle / 360 * 4; 
        OLED_ShowNum(1, 7, Angle, 5);
        OLED_ShowNum(1, 13, FractionalPart, 3);
        //OLED_ShowNum(2, 1, LinearDisplacement, 3);
        
        
    }
}
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号