打印
[应用相关]

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

[复制链接]
1062|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-5-30 10:53 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一、MT6816简介
MT6816是一款由MagnTek推出的基于AMR原理的磁编码器,其支持ABZ&UVW&PWM&SPI四种模式。可以输出分辨率为14位的绝对角度数据;支持最高转速25000RPM;工作温度范围为-40~125℃。常应用于直流无刷电机控制、伺服电机控制,闭环步进电机控制。

其引脚定义如下:



二、MT6816外围电路
1、MT6816模块原理图



2.模式选择
SPI(3线、4线)模式:
R2用0R电阻短路,或者HVPP引脚接到3.3V。

ABZ、UVW、和PWM模式:
R3用0R电阻短路,或者HVPP接地。

3.PCB布局即注意事项



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

4、磁铁的选择及安装注意事项:
使用镜像磁铁,用胶水粘在步进电机尾部的转动轴上,芯片距离磁铁建议1-3mm。



5、与STM32连接
MT6816CS接PA4; SCK接PA5; MISO接PA6; MOSI接PA7。

三、MT6816 4线SPI介绍
1、MT6816SPI时序



2.4线SPI协议



3、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);
               
               
        }
}

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/m0_64386340/article/details/139183344

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1923

主题

15596

帖子

11

粉丝