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);
}
}
热门推荐
人性的核心是什么
烂尾楼是银行和开发商造成的,干嘛要让购房者来承担后果?
右手无力是怎么回事?警惕这三种情况
什么茶降血脂降血压治心血管疾病
内地银联卡用户现可通过Apple Pay在钱包app中添加并充值香港八达通
小红书运营:新手做图文还是视频应该怎么选,看完这篇就懂了
项目经理该如何完成项目PPT
如何写软件测试改进建议
中国化学工程突破“卡脖子”技术:高端聚甲醛新材料实现自主可控
新生儿护理全攻略:从日常护理到正确抱姿
肢体接触看出两人关系
毕马威中国发布报告,深度解读国资国企迈向世界一流的发展路径
电影《奇迹男孩》体现了什么样的家庭教育观,引起观众那些深思?
葛根汤原方剂量及功效详解
大语言模型的LoRA研究综述:原理、应用与未来方向
七夕浪漫指南:传统习俗、爱情故事与节日庆典的完美融合
欧冠16强抽签:巴黎迎战利物浦,皇马马竞上演德比
长期耳鸣真的会影响听力吗?会不会聋?
正官日柱详解:八字命理中的正直与成就
这些年,为什么 130 万人离开了盐城
研究建议:少吃点,身体真会老得更慢
光环战斗进化周年版中文版:科幻射击游戏攻略指南
乙巳太岁 | 2025年哪些生肖犯太岁?应当如何化解?
C语言如何初始化一个三维数组
1820年的清朝算世界列强吗?欧洲人认为:英法俄普奥才是世界五强
狂犬病毒是否可以空气传播?
三明治的酱料有哪些 三明治用什么酱最好吃
DOTA 中单火猫英雄技能分析及装备推荐
《谈判专家》深度解析:这个细节设计有点微妙,很多人可能没发现
补贴翻倍!新一轮汽车以旧换新细则,带来哪些新变化?