打印
[LKS32 软件]

【凌鸥创芯电机开发板LKS32MC071CBT8评测报告】6.用MCPWM让电机转起来

[复制链接]
2422|35
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 yuyy1989 于 2023-6-24 19:01 编辑

#申请原创# 6.用MCPWM让电机转起来
之前用手动控制IO的方法成功让电机转了起来,不过LKS32MC071有电机控制专用的MCPWM模块,是一个精确控制电机驱动波形输出的模块。
首先对上一贴的控制序列做个处理,UP UN VP VN WP WN序列
1 1 0 0 0 1
0 1 1 1 0 0
0 0 0 1 1 1
停止时
0 1 0 1 0 1
转换为波形是这样的

从手册里看MCPWM的介绍,貌似找不到合适的波形输出,改一下这个序列,因为电机引脚有个下拉电阻

我想是不是不用的引脚直接拉低也行,所以变成
1 1 0 0 0 0
0 0 1 1 0 0
0 0 0 0 1 1
再转成波形

这次就很容易找到对应的了

中心对齐输出,但是CH<n>N要翻转一下
先用上一贴的手动控制IO的方法试了一下,这个序列是可以转起来的,接下来编写MCPWM的代码
为了保证能转起来,IO的切换速度尽量靠近手动控制IO的速度,手动控制IO时是每10ms转动三分之一,换成一个PWM周期是30ms,频率在30Hz左右,用12M的系统时钟可以正好得到这个频率,但是在实际使用时发现设置成12M时钟后MCU不工作了,尝试24M时钟可以正常工作,因此最终频率设置成了50Hz
工程需添加库文件lks32mc07x_mcpwm.c

代码示例
#include "lks32mc07x.h"
#include "yuyy_delay.h"

void led_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Pin =  LED_PINS;
    GPIO_Init(LED_GPIO, &GPIO_InitStruct);
    GPIO_ResetBits(LED_GPIO, LED1_PIN|LED2_PIN);
    GPIO_SetBits(LED_GPIO, LED3_PIN);
}

void key_init()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStruct.GPIO_Pin =  KEY_PINS;
    GPIO_Init(KEY_GPIO, &GPIO_InitStruct);
}

void uvw_testinit()
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;
    GPIO_Init(GPIO1, &GPIO_InitStruct);
    GPIO_PinAFConfig(GPIO1, GPIO_PinSource_4, AF3_MCPWM);
    GPIO_PinAFConfig(GPIO1, GPIO_PinSource_5, AF3_MCPWM);
    GPIO_PinAFConfig(GPIO1, GPIO_PinSource_6, AF3_MCPWM);
    GPIO_PinAFConfig(GPIO1, GPIO_PinSource_7, AF3_MCPWM);
    GPIO_PinAFConfig(GPIO1, GPIO_PinSource_8, AF3_MCPWM);
    GPIO_PinAFConfig(GPIO1, GPIO_PinSource_9, AF3_MCPWM);
}

#define MCU_MCLK                       (24000000LL)       /**<  PWM模块运行主频 */
#define PWM_MCLK                       ((u32)MCU_MCLK)    /**<  PWM模块运行主频 */
#define PWM_MCLK_DIV                   3
#if(PWM_MCLK_DIV == 0)
#define PWM_PRSC                        
#elif(PWM_MCLK_DIV == 1)
#define PWM_PRSC                       2
#elif(PWM_MCLK_DIV == 2)
#define PWM_PRSC                       4
#elif(PWM_MCLK_DIV == 3)
#define PWM_PRSC                       8            /**< *< *<  PWM模块运行预分频器 */
#endif
#define PWM_FREQ0                      ((u16)50)       /**< *<  MCPWM_CNT0PWM斩波频率 */

/**<  电机控制PWM 周期计数器值 */
#define MCPWM_PERIOD0                    ((u16) (PWM_MCLK / (u32)(2 * PWM_FREQ0 *(PWM_PRSC)))) //15位 最大32767
#define MCPWM_WIDTH  (MCPWM_PERIOD0*2/3)

#define DEADTIME_NS                    ((u16)1200)       /**<  死区时间 */
#define DEADTIME                       (u16)(((unsigned long long)PWM_MCLK * (unsigned long long)DEADTIME_NS)/1000000000uL)

void mcpwm_init()
{
    MCPWM_InitTypeDef MCPWM_InitStructure;
    MCPWM_StructInit(&MCPWM_InitStructure);

    MCPWM_InitStructure.MCLK_EN = ENABLE;              /* 模块时钟开启 */
    MCPWM_InitStructure.CLK_DIV = PWM_MCLK_DIV;                   /* MCPWM时钟分频设置 */

    MCPWM_InitStructure.IO_FLT_CLKDIV  = 12;  /* 急停事件(来自IO口信号)数字滤波器时间设置 */
    MCPWM_InitStructure.CMP_FLT_CLKDIV = 12;  /* 急停事件(来自比较器信号)数字滤波器时间设置 */

    MCPWM_InitStructure.AUEN = MCPWM0_ALL_AUPDAT; /*自动加载使能*/

    /* MCPWM0_CNT0 */

    MCPWM_InitStructure.BASE_CNT0_EN = ENABLE;                /* 主计数器开始计数使能开关 */
    MCPWM_InitStructure.TH0 = MCPWM_PERIOD0;                    /* 计数周期设置即MCPWM输出周期*/

    MCPWM_InitStructure.TH00 = (u16)(-MCPWM_PERIOD0+5);
    MCPWM_InitStructure.TH01 = (u16)(-MCPWM_PERIOD0+MCPWM_WIDTH-5);
    MCPWM_InitStructure.TH10 = (u16)(-MCPWM_PERIOD0+MCPWM_WIDTH+5);
    MCPWM_InitStructure.TH11 = (u16)(MCPWM_PERIOD0-MCPWM_WIDTH-5);
    MCPWM_InitStructure.TH20 = (u16)(MCPWM_PERIOD0-MCPWM_WIDTH+5);
    MCPWM_InitStructure.TH21 = (u16)(MCPWM_PERIOD0-5);

    MCPWM_InitStructure.MCPWM_WorkModeCH0 = MCPWM0_CENTRAL_PWM_MODE; /* MCPWM CH0工作模式:中心对齐PWM模式 */
    MCPWM_InitStructure.MCPWM_WorkModeCH1 = MCPWM0_CENTRAL_PWM_MODE; /* 通道工作模式设置,中心对齐或边沿对齐 */
    MCPWM_InitStructure.MCPWM_WorkModeCH2 = MCPWM0_CENTRAL_PWM_MODE;
    MCPWM_InitStructure.DeadTimeCH012N = DEADTIME;/* 死区时间设置 */
    MCPWM_InitStructure.DeadTimeCH012P = DEADTIME;
    MCPWM_InitStructure.CMP_CTRL_CNT0  = DISABLE ;/* CMP控制CNT0失能 */
    MCPWM_InitStructure.EVT_CNT0_EN    = DISABLE ;/* MCPWM_CNT1外部触发失能 */
    MCPWM_InitStructure.EVT0           = DISABLE ;

    MCPWM_InitStructure.TR0_UP_INTV     = DISABLE;
    MCPWM_InitStructure.TR0_T0_UpdateEN = ENABLE ;
    MCPWM_InitStructure.TR0_T1_UpdateEN = DISABLE ;
    MCPWM_InitStructure.TR0_AEC         = DISABLE;

    MCPWM_InitStructure.T0_Update0_INT_EN = DISABLE; /* T0更新事件 中断关闭 */
    MCPWM_InitStructure.T1_Update0_INT_EN = DISABLE ; /* T1更新事件 中断使能 */
    MCPWM_InitStructure.Update1_INT_EN = DISABLE;     /* CNT0 更新事件 中断使能  */

    MCPWM_InitStructure.CH0N_Polarity_INV = ENABLE;           /* CH0N通道输出极性设置 | 正常输出或取反输出*/
    MCPWM_InitStructure.CH0P_Polarity_INV = DISABLE;          /* CH0P通道输出极性设置 | 正常输出或取反输出 */
    MCPWM_InitStructure.CH1N_Polarity_INV = ENABLE;
    MCPWM_InitStructure.CH1P_Polarity_INV = DISABLE;
    MCPWM_InitStructure.CH2N_Polarity_INV = ENABLE;
    MCPWM_InitStructure.CH2P_Polarity_INV = DISABLE;

    MCPWM_InitStructure.Switch_CH0N_CH0P =  DISABLE;           /* 通道交换选择设置 | CH0P和CH0N是否选择信号交换 */
    MCPWM_InitStructure.Switch_CH1N_CH1P =  DISABLE;           /* 通道交换选择设置 */
    MCPWM_InitStructure.Switch_CH2N_CH2P =  DISABLE;           /* 通道交换选择设置 */

    /* 默认电平设置 默认电平输出不受MCPWM_IO01和MCPWM_IO23的 BIT0、BIT1、BIT8、BIT9、BIT6、BIT14通道交换和极性控制的影响,直接控制通道输出 */
    MCPWM_InitStructure.CH0P_default_output = MCPWM0_LOW_LEVEL;
    MCPWM_InitStructure.CH0N_default_output = MCPWM0_HIGH_LEVEL;
    MCPWM_InitStructure.CH1P_default_output = MCPWM0_LOW_LEVEL;      /* CH1P对应引脚在空闲状态输出低电平 */
    MCPWM_InitStructure.CH1N_default_output = MCPWM0_HIGH_LEVEL;     /* CH1N对应引脚在空闲状态输出高电平 */
    MCPWM_InitStructure.CH2P_default_output = MCPWM0_LOW_LEVEL;
    MCPWM_InitStructure.CH2N_default_output = MCPWM0_HIGH_LEVEL;

    MCPWM_InitStructure.CH0N_FAIL_EN = ENABLE ;
    MCPWM_InitStructure.CH0P_FAIL_EN = ENABLE ;
    MCPWM_InitStructure.CH1N_FAIL_EN = ENABLE ;
    MCPWM_InitStructure.CH1P_FAIL_EN = ENABLE ;
    MCPWM_InitStructure.CH2N_FAIL_EN = ENABLE ;
    MCPWM_InitStructure.CH2P_FAIL_EN = ENABLE ;

    MCPWM_InitStructure.FAIL0_INPUT_EN   = DISABLE ;//FAIL_0CAP
    MCPWM_InitStructure.FAIL0_INT_EN     = DISABLE;
    MCPWM_InitStructure.FAIL0_Signal_Sel = MCPWM0_FAIL_SEL_CMP ;//FAIL_0CAP
    MCPWM_InitStructure.FAIL0_Polarity   = MCPWM0_HIGH_LEVEL_ACTIVE ;

    MCPWM_InitStructure.FAIL1_INPUT_EN   = DISABLE ;//FAIL_0CAP
    MCPWM_InitStructure.FAIL1_INT_EN     = DISABLE;
    MCPWM_InitStructure.FAIL1_Signal_Sel = MCPWM0_FAIL_SEL_IO ;//FAIL_0CAP
    MCPWM_InitStructure.FAIL1_Polarity   = MCPWM0_HIGH_LEVEL_ACTIVE ;

    MCPWM_InitStructure.HALT_PRT0        = DISABLE ;
    MCPWM_InitStructure.FAIL_0CAP        = DISABLE ;
    MCPWM_Init(&MCPWM_InitStructure);
   
    NVIC_SetPriority(MCPWM0_IRQn, 1);
    NVIC_EnableIRQ(MCPWM0_IRQn);
}

void MCPWM0_IRQHandler(void)
{
        
}

void mcu_init(void)
{
    __disable_irq();         /* 关闭中断 中断总开关 */
    SYS_WR_PROTECT = 0x7a83; /*使能系统寄存器写操作*/
    FLASH_CFG |= 0x00080000; /* enable prefetch ,FLASH预取加速使能*/        
    IWDG_DISABLE();                                                /*关闭清零看门狗*/
    SYS_MclkChoice(SYS_MCLK_24M_RC); /*选择当前主时钟频率*/
    led_init();        
    key_init();
    uvw_testinit();
    mcpwm_init();
    yuyy_delay_us(100);          /* 延时等待硬件初始化稳定 */
    SYS_WR_PROTECT = 0x0;    /*关闭系统寄存器写操作*/
    __enable_irq();          /* 开启总中断 */
}

int main(void)
{
    uint8_t run = 0;
    uint8_t key_start_downcount = 0;
    uint8_t key_stop_downcount = 0;
    uint8_t runstep = 0;
    mcu_init();
    while (1)
    {
        if(Bit_RESET == GPIO_ReadInputDataBit(KEY_GPIO,KEY_START_PIN))
        {
            if(key_start_downcount < 0xFF)
                key_start_downcount++;
        }
        else
        {
            if(key_start_downcount > 3 && run == 0)
            {
                run = 1;
                runstep = 0;
                PWMOutputs(ENABLE);
            }
            key_start_downcount = 0;
        }
        
        if(Bit_RESET == GPIO_ReadInputDataBit(KEY_GPIO,KEY_STOP_PIN))
        {
            if(key_stop_downcount < 0xFF)
                key_stop_downcount++;
        }
        else
        {
            if(key_stop_downcount > 3 && run > 0)
            {
                run = 0;
                runstep = 0;
                PWMOutputs(DISABLE);
            }
            key_stop_downcount = 0;
        }
        
        if(runstep > 0)
            runstep--;
        else
        {
            runstep = 20;
            switch(run)
            {
                case 1:
                    GPIO_SetBits(LED_GPIO, LED1_PIN);
                    GPIO_ResetBits(LED_GPIO, LED2_PIN);
                    GPIO_SetBits(LED_GPIO, LED3_PIN);
                    run = 2;
                    break;
                case 2:
                    GPIO_ResetBits(LED_GPIO, LED1_PIN);
                    GPIO_SetBits(LED_GPIO, LED2_PIN);
                    GPIO_SetBits(LED_GPIO, LED3_PIN);
                    run = 3;
                    break;
                case 3:
                    GPIO_ResetBits(LED_GPIO, LED1_PIN);
                    GPIO_ResetBits(LED_GPIO, LED2_PIN);
                    GPIO_ResetBits(LED_GPIO, LED3_PIN);
                    run = 1;
                    break;
                default:
                    GPIO_ResetBits(LED_GPIO, LED1_PIN);
                    GPIO_ResetBits(LED_GPIO, LED2_PIN);
                    GPIO_SetBits(LED_GPIO, LED3_PIN);
                    run = 0;
                    break;
            }
        }
        yuyy_delay_ms(10);
    }
}
正式接电机使用前,如果有示波器最好用示波器看一下波形是否正常,以免烧坏电机
运行效果

这只是一个刚入门无刷电机的人做的一个简单的用MCPWM驱动电机的示例,后面会继续研究无刷电机的控制方法

使用特权

评论回复
评论
forgot 2023-6-26 10:08 回复TA
赞~!学习一下! 
沙发
jiangyimfs| | 2023-6-24 19:30 | 只看该作者
问一下楼主,问了什么型号的小电机,感觉跟我用的挺像的

使用特权

评论回复
板凳
yuyy1989|  楼主 | 2023-6-24 19:39 | 只看该作者
jiangyimfs 发表于 2023-6-24 19:30
问一下楼主,问了什么型号的小电机,感觉跟我用的挺像的


使用特权

评论回复
地板
jiangyimfs| | 2023-6-24 19:54 | 只看该作者
真的跟我用的电机一样的,这个 电机是2对极,电阻是7Ω,兄那有其他的参数吗?

使用特权

评论回复
5
yuyy1989|  楼主 | 2023-6-24 20:00 | 只看该作者
jiangyimfs 发表于 2023-6-24 19:54
真的跟我用的电机一样的,这个 电机是2对极,电阻是7Ω,兄那有其他的参数吗? ...

没有,在淘宝上看着便宜就买了,卖家那也没详细参数

使用特权

评论回复
6
八层楼| | 2023-7-6 17:02 | 只看该作者
这种电机专用的pwm模块和普通的pwm模块相比 有哪些差别呢

使用特权

评论回复
7
tpgf| | 2023-7-6 17:26 | 只看该作者
每个通道均控制一对输出,接着这些输出可控制某些片外操作,例如控制电机中的一组线圈

使用特权

评论回复
8
观海| | 2023-7-6 21:33 | 只看该作者

MCPWM每个通道包括:
1个32位定时器/计数器(TC);

1个32位界限寄存器(LIM);

1个32匹配寄存器(MAT);

1个10位死区时间寄存器(DT)和相应的10位死区时间计数器;

1个32位捕获寄存器;

2个极性可调整的输出(MCOA和MCOB);

1个周期中断、1个脉宽中断和1个捕获中断。


使用特权

评论回复
9
guanjiaer| | 2023-7-7 08:42 | 只看该作者
电机转起来之后总有一种有点偏心的样子

使用特权

评论回复
10
heimaojingzhang| | 2023-7-7 09:19 | 只看该作者
是不是基本上所有的mcpwm都具有三个通道啊

使用特权

评论回复
11
keaibukelian| | 2023-7-7 09:59 | 只看该作者
当电机的负载变大的时候 必然需要更大的扭矩 此时需要如何控制呢

使用特权

评论回复
12
yuyy1989|  楼主 | 2023-7-7 15:41 | 只看该作者
keaibukelian 发表于 2023-7-7 09:59
当电机的负载变大的时候 必然需要更大的扭矩 此时需要如何控制呢

本人电机小白,目前还不知道如何控制

使用特权

评论回复
13
dreamwang123| | 2023-7-21 10:13 | 只看该作者
本帖最后由 dreamwang123 于 2023-7-21 10:29 编辑

很好

使用特权

评论回复
14
yuyy1989|  楼主 | 2023-7-21 10:18 | 只看该作者
dreamwang123 发表于 2023-7-21 10:13
问下,这个底板VCC输入多少电压的,电机又是DC105V,这里不是很理解

底板输入电压范围20-60V,这个电机24V也能转

使用特权

评论回复
15
dreamwang123| | 2023-7-21 10:30 | 只看该作者
yuyy1989 发表于 2023-7-21 10:18
底板输入电压范围20-60V,这个电机24V也能转

好的,谢谢

使用特权

评论回复
16
123wsy| | 2023-7-27 11:43 | 只看该作者
能拍一下你完整的运行图嘛,包括线是咋接的

使用特权

评论回复
17
yuyy1989|  楼主 | 2023-7-27 22:47 | 只看该作者
123wsy 发表于 2023-7-27 11:43
能拍一下你完整的运行图嘛,包括线是咋接的


使用特权

评论回复
18
123wsy| | 2023-8-8 18:23 | 只看该作者
用LKS081控制一个12V电机,程序是凌欧提供的无感FOC例程,通电后,电机转动不到3秒就不转了,重新上电后重复这个情况,请问这是咋回事?

使用特权

评论回复
19
morrisk| | 2023-8-27 11:38 | 只看该作者
IO的切换速度尽量靠近手动控制IO的速度

使用特权

评论回复
20
leyangdai| | 2023-10-8 11:15 | 只看该作者
请问  凌鸥创芯电机开发板LKS32MC071CBT8 的相关资料从哪可以获取到呢? 方便给我发一份吗?小白学习用。 谢谢。  @yuyy1989

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

115

主题

602

帖子

5

粉丝