使用纳芯微磁性传感器MT6521读取电机数据
该项目使用了磁性传感器MT6521以及其他硬件,实现了一个基于磁性传感器MT6521读取电机数据的设计,它的主要功能为:读取对应轴的磁数据;读取当前电机角度、记录电机旋转圈数和角度、归零对齐。
标签
开发板
纳芯微
MT6521传感器
李逸帆
更新2025-12-03
北京理工大学
67

1、项目功能介绍

该项目使用了磁性传感器MT6521以及其他硬件,实现了一个基于磁性传感器MT6521读取电机数据的设计,它的主要功能为:读取对应轴的磁数据;读取当前电机角度、记录电机旋转圈数和角度、归零对齐。

2、方案框图

MT6521:霍尔传感器,xy模式,采集磁铁角度,模拟信号输出。

按键:通过按键控制电机转动方向、回零、置零。

STM32F103C8T6:采集模拟信号,采集按键输入、控制电机转动以及OLED显示。

步进电机:单四拍转动

OLED:显示角度、转动方向、圈数。

3、电路介绍

3.1 单片机电路:

image.png

核心板上集成单片机工作所需的晶振、复位、电源电路,不需要外部电路进行驱动。

3.2 MT6521电路:

image.png

参考MT6521官方手册模拟方式输出电路进行设计,OUT1OUT2分别为两路模拟信号输出,本设计只使用一路信号。芯片工作电压5V,输出电压也是0~5V,单片机无法采集3.3V以上的信号,所以采用下图的分压电路,将5V电压降低至3.3V以内。

image.png

3.3 电机驱动电路

image.png

电机及电机驱动芯片使用5V供电,1B对应1C,其余同理,PB15输出高电平时,1C会输出一个更大电流的高电平,同理依次输入高电平信号,控制电机转动。通过控制1-4的输出电平顺序,可以控制电机的正反转。

3.4 按键电路

image.png

3.5 显示电路

OLED采用IIC通信,SCLSDA引脚为开漏输出,所以外接10K上拉电阻。

image.png

3.6 PCB板

系统PCB使用两层板进行设计,合理规划各个模块的摆放位置,其中电源线线宽较大,信号线线宽较小,铺地铜,各个滤波电容放置在电源引脚处,起到更好的滤波效果。

image.png

重点在于霍尔传感器与电机之间的相对位置摆放,结合MT6521的芯片手册可知,该传感器敏感元位于芯片正中间,故结合电机位置,绘制定位孔以及辅助线,确保磁铁中心尽可能对齐芯片中心敏感源,提高测量准确度。

4、软件介绍

4.1 主函数

主函数中循环读取按键状态、读取角度,根据按键检测实现电机转动控制、显示函数封装在角度读取函数中循环运行。

/* USER CODE BEGIN WHILE */
while(1)
{
/* USER CODE END WHILE */
Key_Scan();
ReadAngle();
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

4.2 按键扫描程序

uint8_t Key_GetNum(void);
void Key_Scan(void);
uint8_t KeyNum = 0;

uint8_t Key_GetNum(void)
{
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0)
{
HAL_Delay(20);
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == 0);
HAL_Delay(20);
KeyNum = 1;
}
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == 0)
{
HAL_Delay(20);
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == 0);
HAL_Delay(20);
KeyNum = 2;
}
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == 0)
{
HAL_Delay(20);
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == 0);
HAL_Delay(20);
KeyNum = 3;
}
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 0)
{
HAL_Delay(20);
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == 0);
HAL_Delay(20);
KeyNum = 4;
}

if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == 0)
{
HAL_Delay(20);
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == 0);
HAL_Delay(20);
KeyNum = 5;
}

return KeyNum;
}

void Key_Scan(void)
{
uint8_t key_push;
key_push=Key_GetNum();

if(key_push==1)
{
motor_cw();
OLED_ShowString(50,4,"CW ",16,0);

}

if(key_push==2)
{
motor_ccw();
OLED_ShowString(50,4,"CCW ",16,0);
}

if(key_push==3)
{
KeyNum=0;
OLED_ShowString(50,4,"STOP",16,0);
}

if(key_push==4)
{
Calibration();
OLED_ShowString(50,4,"STOP",16,0);
KeyNum=0;
}


if(key_push==5)
{
motor_zero();

}

}

此函数完成按键检测,根据检测IO状态判断按键哪个被按下,然后进入对应的状态,在key_scan函数中,判断key_push的值,执行顺时针、逆时针、停止、置零、回零操作。

4.3 角度检测程序

void ReadAngle(void)
{

static float last_real_angle = 0;

float adc_sum = 0;

for (int i = 0; i < SAMPLE_COUNT; i++) {
HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 1) == HAL_OK) {
adc_sum += HAL_ADC_GetValue(&hadc1);
}
HAL_ADC_Stop(&hadc1);
}
current_angle = adc_sum / SAMPLE_COUNT;
Angle_out = -(current_angle - 190) * 20.2;
refer_angle_out = Angle_out + refer_angle;

if (refer_angle_out > 65535) refer_angle_out -= 65535;
if (refer_angle_out < 0) refer_angle_out += 65535;

real_angle = refer_angle_out / 65535.0f * 360.0f;

float angle_diff = real_angle - last_real_angle;

if (angle_diff > 180.0f) {

angle_diff -= 360.0f;
} else if (angle_diff < -180.0f) {

angle_diff += 360.0f;
}

static float accumulated_angle = 0;
accumulated_angle += angle_diff;

if (accumulated_angle >= 360.0f) {
motor_loop++;
accumulated_angle -= 360.0f;
} else if (accumulated_angle <= -360.0f) {
motor_loop--;
accumulated_angle += 360.0f;
}

last_real_angle = real_angle;

OLED_ShowNum(55, 0, real_angle, 5, 16, 0);
OLED_ShowNum(45, 2, motor_loop, 5, 16, 0);
}

这段代码通过ADC采集电压值,进而转换为角度值。MT6521能够在0~360°范围内输出0~5V的电压(并非一一对应,只是范围相同),经过分压电路,检测0-3.3V电压,芯片输出以及ADC都有噪声,所以采用多次采样后计算平均值得到更稳定的角度值。

    Angle_out = -(current_angle - 190) * 20.2;
refer_angle_out = Angle_out + refer_angle;

if (refer_angle_out > 65535) refer_angle_out -= 65535;
if (refer_angle_out < 0) refer_angle_out += 65535;

real_angle = refer_angle_out / 65535.0f * 360.0f;

这段代码将采集到的原始角度按照实测的误差,先减190再乘20.2,转换为内部寄存器的值,MT6521的满量程为0~65535,转换为内部寄存器后,再均分为360°,即可得到实际角度值。其中refer_angle是清零时使用的角度偏差,目的是为了在清零按键按下时,角度值直接归0

		float angle_diff = real_angle - last_real_angle;

if (angle_diff > 180.0f) {

angle_diff -= 360.0f;
} else if (angle_diff < -180.0f) {

angle_diff += 360.0f;
}

static float accumulated_angle = 0;
accumulated_angle += angle_diff;

if (accumulated_angle >= 360.0f) {
motor_loop++;
accumulated_angle -= 360.0f;
} else if (accumulated_angle <= -360.0f) {
motor_loop--;
accumulated_angle += 360.0f;
}

last_real_angle = real_angle;

这段代码会实时记录当前角度以及第一次开始转动时的角度值,判断角度值累计变化量大于360°后,控制圈数加一,同时也考虑到了边界跨越,防止误判。

void Calibration(void)
{

refer_angle=-Angle_out+80;
;
motor_loop=0;

}

void motor_zero(void)
{
float target = 65535;
float error = target - refer_angle_out;
motor_loop=0;

if (error < 100.0f)
{
KeyNum = 0;
OLED_ShowString(50,4,"STOP",16,0);
refer_angle+=150;

return;
}

if (error > 32768)
{
motor_ccw();
}
else
{
motor_cw();
}

}

清零函数按下时,单片机直接记录当前角度值,并且将这个角度送到角度计算函数中,这样可以让采集到的角度值直接归0,角度值加上80是因为电机停转会产生一定的延迟,用于修正该输出。

归零函数也是通过计算当前角度与零点角度的偏差,根据偏差值的大小判断顺时针还是逆时针能够更快的回到零点。

5、实物展示

D6018437E18CD29665E8379A4A9D9B79.png

磁铁转动效果如下图:

C118EB22DDC537AEA92A71E15292A78A.jpg

磁铁在安装时需要将NS级平行于芯片放置,这样产生的磁感应线才会在MT6521芯片内部产生均匀变化的磁场,进而计算出磁铁的变化角度,当磁铁转动时,磁感应线在芯片内部的XY轴霍尔盘具有不同的磁场大小分量,芯片通过计算分量大小得到实际角度。

6、遇到的主要难题及解决方法

  1. 缺少电路搭建经验,通过b站学习逐步解决
  2. 缺少部分硬件与工具,通过求助同学和有相应经验的前辈解决

7、未来的计划

进一步研究MT6521传感器的特性,用以实现更多功能

软硬件
电路图
附件下载
Angle.zip
团队介绍
个人初次参加电子森林活动项目
团队成员
李逸帆
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号