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

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值