yuyy1989 发表于 2023-6-24 19:00

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

本帖最后由 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驱动电机的示例,后面会继续研究无刷电机的控制方法

jiangyimfs 发表于 2023-6-24 19:30

问一下楼主,问了什么型号的小电机,感觉跟我用的挺像的{:lol:}

yuyy1989 发表于 2023-6-24 19:39

jiangyimfs 发表于 2023-6-24 19:30
问一下楼主,问了什么型号的小电机,感觉跟我用的挺像的


jiangyimfs 发表于 2023-6-24 19:54

真的跟我用的电机一样的,这个 电机是2对极,电阻是7Ω,兄那有其他的参数吗?

yuyy1989 发表于 2023-6-24 20:00

jiangyimfs 发表于 2023-6-24 19:54
真的跟我用的电机一样的,这个 电机是2对极,电阻是7Ω,兄那有其他的参数吗? ...

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

八层楼 发表于 2023-7-6 17:02

这种电机专用的pwm模块和普通的pwm模块相比 有哪些差别呢

tpgf 发表于 2023-7-6 17:26

每个通道均控制一对输出,接着这些输出可控制某些片外操作,例如控制电机中的一组线圈

观海 发表于 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个捕获中断。

guanjiaer 发表于 2023-7-7 08:42

电机转起来之后总有一种有点偏心的样子

heimaojingzhang 发表于 2023-7-7 09:19

是不是基本上所有的mcpwm都具有三个通道啊

keaibukelian 发表于 2023-7-7 09:59

当电机的负载变大的时候 必然需要更大的扭矩 此时需要如何控制呢

yuyy1989 发表于 2023-7-7 15:41

keaibukelian 发表于 2023-7-7 09:59
当电机的负载变大的时候 必然需要更大的扭矩 此时需要如何控制呢

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

dreamwang123 发表于 2023-7-21 10:13

本帖最后由 dreamwang123 于 2023-7-21 10:29 编辑

很好

yuyy1989 发表于 2023-7-21 10:18

dreamwang123 发表于 2023-7-21 10:13
问下,这个底板VCC输入多少电压的,电机又是DC105V,这里不是很理解

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

dreamwang123 发表于 2023-7-21 10:30

yuyy1989 发表于 2023-7-21 10:18
底板输入电压范围20-60V,这个电机24V也能转

好的,谢谢

123wsy 发表于 2023-7-27 11:43

能拍一下你完整的运行图嘛,包括线是咋接的

yuyy1989 发表于 2023-7-27 22:47

123wsy 发表于 2023-7-27 11:43
能拍一下你完整的运行图嘛,包括线是咋接的


123wsy 发表于 2023-8-8 18:23

用LKS081控制一个12V电机,程序是凌欧提供的无感FOC例程,通电后,电机转动不到3秒就不转了,重新上电后重复这个情况,请问这是咋回事?

morrisk 发表于 2023-8-27 11:38

IO的切换速度尽量靠近手动控制IO的速度

leyangdai 发表于 2023-10-8 11:15

请问凌鸥创芯电机开发板LKS32MC071CBT8 的相关资料从哪可以获取到呢? 方便给我发一份吗?小白学习用。 谢谢。@yuyy1989
页: [1] 2
查看完整版本: 【凌鸥创芯电机开发板LKS32MC071CBT8评测报告】6.用MCPWM让电机转起来