WeDesign7基于MT6521的电机角度监测与控制项目报告
一、所选任务介绍
基础任务:
完成MT6521传感器PCB设计
实现电机角度读取、圈数统计、归零对齐
额外任务:
开发闭环控制算法,实现:
指定速度/圈数/终止角度的旋转控制
精准返回原点的双向运动控制
二、项目描述
1. 整体介绍:
系统功能:
实时监测直流无刷电机旋转角度(0-360°)
自动统计旋转圈数(±1000圈)
支持机械零点校准(归零对齐)
双向精确运动控制(误差<±0.5°)
2. 硬件配置清单:
模块 型号/规格 功能说明
传感器 MT6521霍尔角度编码器 3D磁场检测,SPI/ADC输出
微控制器 NS800RT5039 数据处理与运动控制
评估板 NSSinePad-NS800RT5039 快速原型开发(替代自定义PCB)
驱动电路DRV8313直流无刷电机驱动芯片
方案设计
1. 系统框图:
这个系统主要用纳芯微NS800RT5039评估板来控制,它通过板上的12位ADC模块来读取MT6521霍尔角度传感器输出的模拟电压信号(0-5V对应0-360°的旋转角度)。评估板直接给MT6521供电,不需要额外设计电源模块。控制器通过三路PWM信号来驱动无刷电机驱动器,实现电机的精确角度控制;同时,实时角度数据通过USART串口(波特率115200)上传到电脑(比如12指神探屏幕或串口助手),方便动态监控和调试。系统通过闭环控制逻辑(ADC采集→角度计算→PID调整→PWM输出)来实现电机位置的高精度控制,整体设计既简化了硬件又保证了功能完整,符合WeDesign7活动的低成本、高效开发目标。

2. 设计思路
基础任务实现:
利用MT6521的ADC接口获取12位绝对角度值
通过软件算法(SimpleFOC)计算旋转方向与圈数
移植ThreadX从操作系统,实现1ms的算法执行周期
额外任务实现:
开发SimpleFOC算法调节PWM占空比,以实现电机的角度环控制
三、硬件实现
1. PCB设计说明
核心电路:
根据数据手册的参考电路设计。
MT6521引脚连接:
ADC -> PA9
VDD → 5V稳压输出
GND →数字地

磁编码器PCB

驱动电路PCB
四、软件开发
1. 流程图

调试工具链
开发环境:Keil5 +板载DAPLink调试器
编程方法:SWD接口在线编程
2. 关键代码示例
ADC初始化,使用PA9作为模拟输入引脚,基准源设置到2.5V,软件触发单词采样。
/**
* @brief ADCA Configurations
*/
void BSP_ADC_Init(void)
{
/* ADC Initialization: Write ADC configurations and power up the ADC.
Set the analog voltage reference selection and ADC module's offset trims.
This function sets the analog voltage reference to internal
(with the reference voltage of 1.65V or 2.5V) or external for ADC. */
ADC_setVREF(myADC0_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_2_5V);
/* Configures the analog-to-digital converter module prescaler. */
ADC_setPrescaler(myADC0_BASE, ADC_CLK_DIV_4);
/* Sets the timing of the end-of-conversion pulse */
ADC_setInterruptPulsePosMode(myADC0_BASE, ADC_PULSE_END_OF_CONV);
/* Powers up the analog-to-digital converter core. */
ADC_enableConverter(myADC0_BASE);
/* Delay for 1ms to allow ADC time to power up */
Delay_us(1000);
/* SOC Configuration: Setup ADC EPWM channel and trigger settings */
/* Disables SOC burst mode. */
ADC_disableBurstMode(myADC0_BASE);
/* Sets the priority mode of the SOCs. */
ADC_setSOCPriority(myADC0_BASE, ADC_PRI_ALL_ROUND_ROBIN);
/* Start of Conversion 0 Configuration */
/* Configures a start-of-conversion (SOC) in the ADC and its interrupt SOC trigger.
SOC number : 0
Trigger : ADC_TRIGGER_SW_ONLY
Channel : ADC_CH_ADCIN0
Sample Window : 8 SYSCLK cycles
Interrupt Trigger : ADC_INT_SOC_TRIGGER_NONE */
ADC_setupSOC(myADC0_BASE, ADC_SOC_NUMBER9, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN9, myADC_SAMPLE_WINDOW);
ADC_setInterruptSOCTrigger(myADC0_BASE, ADC_SOC_NUMBER9, ADC_INT_SOC_TRIGGER_NONE);
/* ADC Interrupt 1 Configuration
Source : ADC_SOC_NUMBER1
Interrupt Source : enabled
Continuous Mode : disabled */
ADC_setInterruptSource(myADC0_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER1);
ADC_clearInterruptStatus(myADC0_BASE, ADC_INT_NUMBER1);
ADC_disableContinuousMode(myADC0_BASE, ADC_INT_NUMBER1);
ADC_enableInterrupt(myADC0_BASE, ADC_INT_NUMBER1);
/* Convert, wait for completion, and store results */
ADC_forceMultipleSOC(myADC0_BASE, (ADC_FORCE_SOC9));
}
ePWM 初始化,使用PWM1模块的A、B、D 三个通道输出PWM。重装在值设置为5100。使用GPIO30、31、40。
/**
* @brief EPWM Configurations
*/
void EPWM_init(void)
{
// 设置EPWM时钟预分频器,选择主时钟和高速时钟的分频系数
EPWM_setClockPrescaler(myEPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
// 设置时间基准的周期为5200,表示计数器每5200个时钟周期溢出
EPWM_setTimeBasePeriod(myEPWM1_BASE, 5200);
// 设置时间基准计数器的初始值为0
EPWM_setTimeBaseCounter(myEPWM1_BASE, 0);
// 设置时间基准计数器的计数模式为上升下降模式(Up-Down),即计数器到达最大值后反向计数
EPWM_setTimeBaseCounterMode(myEPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);
// 禁用相位移加载功能
EPWM_disablePhaseShiftLoad(myEPWM1_BASE);
// 设置相位移为0,表示没有相位偏移
EPWM_setPhaseShift(myEPWM1_BASE, 0);
// 设置比较器A的比较值为100,表示在计数器值为100时触发相关事件
EPWM_setCounterCompareValue(myEPWM1_BASE, EPWM_COUNTER_COMPARE_A, 0);
// 设置比较器A的加载模式为在计数器归零时加载(此时值为100)
EPWM_setCounterCompareShadowLoadMode(myEPWM1_BASE, EPWM_COUNTER_COMPARE_A, EPWM_COMP_LOAD_ON_CNTR_ZERO);
// 设置比较器B的比较值为5100,表示在计数器值为5100时触发相关事件
EPWM_setCounterCompareValue(myEPWM1_BASE, EPWM_COUNTER_COMPARE_B, 0);
// 设置比较器B的加载模式为在计数器归零时加载(此时值为5100)
EPWM_setCounterCompareShadowLoadMode(myEPWM1_BASE, EPWM_COUNTER_COMPARE_B, EPWM_COMP_LOAD_ON_CNTR_ZERO);
// 设置比较器D的比较值为5100,表示在计数器值为5100时触发相关事件
EPWM_setCounterCompareValue(myEPWM1_BASE, EPWM_COUNTER_COMPARE_D, 0);
// 设置比较器D的加载模式为在计数器归零时加载(此时值为5100)
EPWM_setCounterCompareShadowLoadMode(myEPWM1_BASE, EPWM_COUNTER_COMPARE_D, EPWM_COMP_LOAD_ON_CNTR_ZERO);
// 设置EPWM输出A的动作定性:在计数器归零时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
// 设置EPWM输出A的动作定性:在计数器周期结束时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
// 设置EPWM输出A的动作定性:在计数器上升到比较器A的值时输出高电平
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 设置EPWM输出A的动作定性:在计数器下降到比较器A的值时输出低电平
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
// 设置EPWM输出A的动作定性:在计数器上升到比较器B的值时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
// 设置EPWM输出A的动作定性:在计数器下降到比较器B的值时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
// 设置EPWM输出B的动作定性:在计数器归零时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
// 设置EPWM输出B的动作定性:在计数器周期结束时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
// 设置EPWM输出B的动作定性:在计数器上升到比较器A的值时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 设置EPWM输出B的动作定性:在计数器下降到比较器A的值时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);
// 设置EPWM输出B的动作定性:在计数器上升到比较器B的值时输出高电平
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB);
// 设置EPWM输出B的动作定性:在计数器下降到比较器B的值时输出低电平
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_B, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB);
// 设置EPWM输出D的动作定性:在计数器归零时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_D, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
// 设置EPWM输出D的动作定性:在计数器周期结束时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_D, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
// 设置EPWM输出D的动作定性:在计数器上升到比较器C的值时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_D, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPC);
// 设置EPWM输出D的动作定性:在计数器下降到比较器A的值时不改变输出
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_D, EPWM_AQ_OUTPUT_NO_CHANGE, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPC);
// 设置EPWM输出D的动作定性:在计数器上升到比较器D的值时输出高电平
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_D, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPD);
// 设置EPWM输出D的动作定性:在计数器下降到比较器D的值时输出低电平
EPWM_setActionQualifierAction(myEPWM1_BASE, EPWM_AQ_OUTPUT_D, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPD);
// 设置上升沿延迟计数加载模式,计数器归零时加载
EPWM_setRisingEdgeDelayCountShadowLoadMode(myEPWM1_BASE, EPWM_RED_LOAD_ON_CNTR_ZERO);
// 禁用上升沿延迟计数加载模式
EPWM_disableRisingEdgeDelayCountShadowLoadMode(myEPWM1_BASE);
// 设置下降沿延迟计数加载模式,计数器归零时加载
EPWM_setFallingEdgeDelayCountShadowLoadMode(myEPWM1_BASE, EPWM_FED_LOAD_ON_CNTR_ZERO);
// 禁用下降沿延迟计数加载模式
EPWM_disableFallingEdgeDelayCountShadowLoadMode(myEPWM1_BASE);
// 以下代码被注释掉,表示目前未启用中断配置
// EPWM_enableInterrupt(myEPWM1_BASE);
// EPWM_setInterruptSource(myEPWM1_BASE, EPWM_INT_TBCTR_ZERO);
// EPWM_setInterruptEventCount(myEPWM1_BASE, 3);
主函数
做完外设及FOC算法初始化之后,程序由ThreadX接管。
/**
* @brief Main function
* @return int Force return 0
*/
int main(void)
{
/* Initialize device clock and peripherals */
Device_init();
/* Disable peripheral register locks */
Device_unlockPeriphReg();
/* Board Initialization
Setup LED pins, Key pins and Serial Communication Interface pins
*/
Board_init();
// AS5600_Init();
BSP_ADC_Init();
EasyFOC_Init();
M1_Enable();
target = 50.0f;
systick_CountMode();
tx_kernel_enter();
/* Loop indefinitely */
while (1)
{
}
}
主要任务
由ThreadX创建这个1ms的任务,用于执行角度读取,FOC计算以及PWM输出。
void my_thread2_entry(ULONG thread_input)
{
shaft_velocity_sp=400;//在这里设置
while(1)
{
GPIO_togglePin(BOARD_LED5_PIN);
// 循环执行FOC控制算法
move(target);
loopFOC();
tx_thread_sleep(1);
}
}
心得体会和收获总结:
技术层面:
掌握了MT6521的SPI通信协议和角度解析方法
验证了PID控制算法在电机定位中的实际效果
学习了使用评估板NSSinePad快速实现复杂功能
工程实践:
验证低通滤波器滤波对传感器噪声的抑制效果
1.改进建议:
硬件优化:
建议增加温度补偿电路,提升长期稳定性
可扩展CAN总线接口实现远程控制
软件优化:
增加S曲线加减速算法,减少机械冲击
开发图形化配置界面,简化参数设置