[APM32E0] 极海APM32E030 Micro-EVB开发板测评+无刷电机6拍控制信号测评

[复制链接]
 楼主| wuyu40 发表于 2025-8-1 16:49 | 显示全部楼层 |阅读模式
#申请开发板#
 极海APM32E030R芯片是32 位 Arm®Cortex®-M0+内核,最高工作频率:72MHz,Flash 存储器:64KB,SRAM 存储器:8KB
开发方式如下:
1)连接 H2/H3 或 H4/H5 可使用板载 Geehy LINK 进行串口调试
2)断开 Geehy LINK 连接后,第三方调试工具可通过 JP1 连接仿真器进行 MCU 烧录调试
3)Type-C(数据通信)直接连接 PC 端进行 MCU 仿真调试
4)使用keil v 5.36编译环境
到官网找到如下文件:
28ec2f488546f6cdc0f6e9b9a0bf8ed6
使用的操作系统为win10(GEEHY-LINK(WinUSB)设备不支持在 Windows7 上免驱使用)假定已经安装keil (版本 V5.29 以上),安装Geehy.APM32E030_DFP.1.0.3也就是mcu支持包,阅读用户手册,按照指示连接硬件;该固件基于 CMSIS-DAP V1,会使用 USB 枚举成一个 HID 和 MSC 设备。
使用 USB 线成功连接电脑后,设备管理器上会出现:CMSIS DAP winUSB
1b5faead271e2b6f55214f625b2ae824
在 keil 软件上配置选择使用 SW 模式或者 JTAG 模式。点击“Options for Target” ,在打开的界面中选择“Debug”,然后再选择“CMSIS-DAP Debugger”,如图 :
b74413c1c300b1085441183fc47751d0
点击“Settings”按钮进入设置界面,选择 SWD 或者 JTAG 模式以及频率:
a5657154a59ebbc19c05fa9fc0021e39
无刷直流电机的换向控制原理
如下图示例极通电导通时, 电流由 A 极流向 C 极, 这样形成了定子合成磁场. 永磁体转子会根据定子合成磁场的方向进行旋转. 通过对三相交替通电 (A+ C-) , (A+ B-) , (C+ B-), (C+ A-) , (B+ A-) , (B+ C-) , 完成磁场旋转. 每一步只改变其中一极的导通状态, 共六步来完成定子合成磁场旋转一周, 即每步磁场旋转 60° —— 该方法被称为 “六步换向法”. 如下图所示六步换向法的基本原理:
7898e01866c7c9d0c8a11a3c1969aa15
为了实现定子磁场的旋转 (即六步换向), 需要交替有序地导通定子的三相电极. 而实现三相电极交替导通的驱动电路为三相全桥逆变电路, 控制上按照六步换向时序进行控制;
7224dffd5dd8db3e56df3c9975475a99
完成以上配置之后测试6开关驱动工程,工程使用了定时器模块原理如下:
bf231985a128bb8ec4b104cf03c6a5df
定时器可以看作三个模块组合,第一定时器基本功能,完成定时器周期性计数;第二定时器输出PWM功能,将计数值不断与比较寄存器做比较产生6根引脚的PWM输出信号控制无刷直流电机(或者其他类型交流电机)功率开关;第三定时器捕获功能,可以接HALL传感器等用来检测转子实时位置;在本工程中完成了6开关信号驱动,所以需要设置定时器1、2模块,代码如下:
    GPIO_Config_T GPIO_ConfigStruct;
    TMR_TimeBase_T baseConfig;
    TMR_OCConfig_T OCcongigStruct;
    TMR_BDTInit_T BDTConfig;
    //定义需要的结构体变量
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1);
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA | RCM_AHB_PERIPH_GPIOB);
      //打开外设时钟
    /* 设置定时器1通道1引脚TMR1_CH1 */
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_8, GPIO_AF_PIN2);
    /* TMR1_CH2 */
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_9, GPIO_AF_PIN2);
    /* TMR1_CH3 */
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_10, GPIO_AF_PIN2);
    /* 设置刹车信号引脚*/
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_6, GPIO_AF_PIN2);
    /* TMR1_CH1N */
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_PIN2);
    /* TMR1_CH2N */
    GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_0, GPIO_AF_PIN2);
    /* TMR1_CH3N */
    GPIO_ConfigPinAF(GPIOB, GPIO_PIN_SOURCE_1, GPIO_AF_PIN2);
    /* Config TMR1 GPIO for complementary output PWM */
    GPIO_ConfigStruct.pin     = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_6;
    GPIO_ConfigStruct.mode    = GPIO_MODE_AF;
    GPIO_ConfigStruct.outtype = GPIO_OUT_TYPE_PP;
    GPIO_ConfigStruct.speed   = GPIO_SPEED_50MHz;
    GPIO_Config(GPIOA, &GPIO_ConfigStruct);
    GPIO_ConfigStruct.pin = GPIO_PIN_0 | GPIO_PIN_1;
    GPIO_Config(GPIOB, &GPIO_ConfigStruct);
    /* 设置定时器1工作模式TMR1 */
    baseConfig.clockDivision     = TMR_CKD_DIV1;
    baseConfig.counterMode       = TMR_COUNTER_MODE_UP;
    baseConfig.div               = 0;
    baseConfig.period            = 2047;
    baseConfig.repetitionCounter = 0;
    TMR_ConfigTimeBase(TMR1, &baseConfig);
    /* 设置定时器输出通道工作模式*/
    OCcongigStruct.OC_Mode         = TMR_OC_MODE_TMRING;
    OCcongigStruct.Pulse           = 1023;
    OCcongigStruct.OC_Idlestate    = TMR_OCIDLESTATE_SET;
    OCcongigStruct.OC_OutputState  = TMR_OUTPUT_STATE_ENABLE;
    OCcongigStruct.OC_Polarity     = TMR_OC_POLARITY_HIGH;
    OCcongigStruct.OC_NIdlestate   = TMR_OCNIDLESTATE_SET;
    OCcongigStruct.OC_OutputNState = TMR_OUTPUT_NSTATE_ENABLE;
    OCcongigStruct.OC_NPolarity    = TMR_OC_NPOLARITY_HIGH;
    TMR_OC1Config(TMR1, &OCcongigStruct);
    OCcongigStruct.Pulse = 511;
    TMR_OC2Config(TMR1, &OCcongigStruct);
    OCcongigStruct.Pulse = 255;
    TMR_OC3Config(TMR1, &OCcongigStruct);
    /* 用在电机控制上下桥臂需要设置死区时间等 */
    BDTConfig.RMOS_State      = TMR_RMOS_STATE_ENABLE;
    BDTConfig.IMOS_State      = TMR_IMOS_STATE_ENABLE;
    BDTConfig.lockLevel       = TMR_LOCK_LEVEL_OFF;
    BDTConfig.deadTime        = 0x01;
    BDTConfig.breakState      = TMR_BREAK_STATE_DISABLE;
    BDTConfig.breakPolarity   = TMR_BREAK_POLARITY_HIGH;
    BDTConfig.automaticOutput = TMR_AUTOMATIC_OUTPUT_ENABLE;
    TMR_ConfigBDT(TMR1, &BDTConfig);
    /* Timer1 Commutation Interrupt */
    TMR_EnableInterrupt(TMR1, TMR_INT_CCU);
    NVIC_EnableIRQ(TMR1_BRK_UP_TRG_COM_IRQn);
    /* Enable Capture Compare Preload Control */
    TMR_EnableCCPreload(TMR1);
    TMR_EnablePWMOutputs(TMR1);
    TMR_Enable(TMR1);
    while (1)
    {
        /* 每隔1s产生com事件*/
        Delay_ms(100);
        TMR_GenerateEvent(TMR1, TMR_EVENT_CCU);
}
在com中断函数中进行6拍换相,根据下图所示的开关切换方式进行换相;
cfe7cd5440a8aea8e93f5d6bde041485
void TMR1_BRK_UP_TRG_COM_IRQHandler(void)
{
    /* The interrupt flag bit must be cleared first. */
    /* 清除TMR1 COM中断标志位*/
    TMR_ClearIntFlag(TMR1, TMR_INT_CCU);
    PWMStep++;
    switch (PWMStep)
    {
        case 1:
            /* configuration: Channel1 and Channel2 PWM1 Mode */
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_1, TMR_OC_MODE_PWM1);
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_2, TMR_OC_MODE_PWM1);
            /* configuration: Channel1 */
            TMR_EnableCCxChannel(TMR1, TMR_CHANNEL_1);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_1);
            /* configuration: Channel2 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_2);
            TMR_EnableCCxNChannel(TMR1, TMR_CHANNEL_2);
            /* configuration: Channel3 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_3);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_3);
            break;
        case 2:
            /* configuration: Channel2 and Channel3 PWM1 Mode */
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_2, TMR_OC_MODE_PWM1);
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_3, TMR_OC_MODE_PWM1);
            /* configuration: Channel1 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_1);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_1);
            /* configuration: Channel2 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_2);
            TMR_EnableCCxNChannel(TMR1, TMR_CHANNEL_2);
            /* configuration: Channel3 */
            TMR_EnableCCxChannel(TMR1, TMR_CHANNEL_3);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_3);
            break;
        case 3:
            /* configuration: Channel3 and Channel1 PWM1 Mode */
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_3, TMR_OC_MODE_PWM1);
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_1, TMR_OC_MODE_PWM1);
            /* configuration: Channel1 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_1);
            TMR_EnableCCxNChannel(TMR1, TMR_CHANNEL_1);
            /* configuration: Channel2 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_2);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_2);
            /* configuration: Channel3 */
            TMR_EnableCCxChannel(TMR1, TMR_CHANNEL_3);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_3);
            break;
        case 4:
            /* configuration: Channel1 and Channel2 PWM1 Mode */
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_1, TMR_OC_MODE_PWM1);
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_2, TMR_OC_MODE_PWM1);
            /* configuration: Channel1 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_1);
            TMR_EnableCCxNChannel(TMR1, TMR_CHANNEL_1);
            /* configuration: Channel2 */
            TMR_EnableCCxChannel(TMR1, TMR_CHANNEL_2);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_2);
            /* configuration: Channel3 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_3);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_3);
            break;
        case 5:
            /* configuration: Channel2 and Channel3 PWM1 Mode */
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_2, TMR_OC_MODE_PWM1);
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_3, TMR_OC_MODE_PWM1);
            /* configuration: Channel1 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_1);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_1);
            /* configuration: Channel2 */
            TMR_EnableCCxChannel(TMR1, TMR_CHANNEL_2);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_2);
            /* configuration: Channel3 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_3);
            TMR_EnableCCxNChannel(TMR1, TMR_CHANNEL_3);
            break;
        case 6:
            /* configuration: Channel3 and Channel1 PWM1 Mode */
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_3, TMR_OC_MODE_PWM1);
            TMR_SelectOCxMode(TMR1, TMR_CHANNEL_1, TMR_OC_MODE_PWM1);
            /* configuration: Channel1 */
            TMR_EnableCCxChannel(TMR1, TMR_CHANNEL_1);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_1);
            /* configuration: Channel2 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_2);
            TMR_DisableCCxNChannel(TMR1, TMR_CHANNEL_2);
            /* configuration: Channel3 */
            TMR_DisableCCxChannel(TMR1, TMR_CHANNEL_3);
            TMR_EnableCCxNChannel(TMR1, TMR_CHANNEL_3);
            PWMStep = 0;
            break;
        default:
            PWMStep = 0;
            break;
    }
}
开发板接到逻辑分析仪进行检测,接线如图:
568fd816813cc846af4ae6a76c6a13af
逻辑分析仪波形如下:
945cf3a66b8e689a5b22b6589bd47aa9
b9924e8f250515a11d6eddfd622372d2

迷雾隐者 发表于 2025-8-4 19:42 | 显示全部楼层
测评很详细,特别是无刷电机的6拍控制信号部分,学习了!
幻想收藏家 发表于 2025-8-6 21:21 | 显示全部楼层
测评很详细,APM32E030的性能看起来不错,特别是在无刷电机控制方面。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

64

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部