瑞萨单片机william hill官网
直播中

HonestQiao

8年用户 519经验值
擅长:嵌入式技术
私信 关注
[经验]

【瑞萨RA4系列开发板体验】基于PWM控制的无极调速电机控制

之前分享过GPT定时器的基础使用,把GPT作为基础的定时器来使用的。

在RA系列板子上,GPT更重要的作用之一,是进行PWM输出,不然对不起他的全名:General PWM Timer。

要使用PWM输出功能,借助FSP工具,可以很方便的进行配置,然后在代码中进行对应的调用处理。

正好,我手头有一个MX1508的直流电机控制模块,以及一个带风扇的小直流电机,刚好可以用上。

MX1508一般是这样的:
image.png
可以同时控制两路直流电机,例如在小车上使用。
通常按照如下方式使用:
image.png

不过,我手头的这个,只能控制一个电机:
image.png

通过MX1508控制电机,需要两个信号接口,一个是PWM控制转速,一个是DIR控制方向。

通过查看RA4M2的硬件手册和原理图,最终进行如下的设计:

  1. PWM控制使用GPT1,因为其两个PWM输出IO口,分别为P405、P406,而P405刚好接到了板子上的LED3,可以用其亮度,表示当前PWM的占空比情况,而P406则输出控制电机
  2. 使用LED2来表示电机运转的方向,其对应的控制引脚为P404,同时用于控制电机运转的方向
  3. 使用板载SW1按键,其对应的因较为P005,用来控制是否保持电机当前的转速;同时,使用LED1的亮灭表示是否保持。

对应的手册信息如下:
image.png

image.png

image.png

做好了设计规划,就先用FSP进行设置。
首先,P405默认设置为普通IO控制LED3,如果要使用PWM进行控制,则需要取消原有的设置,也就是禁用P405默认的配置:
image.png

然后,配置GPT1:
image.png
当选择GPIOCA and GPIOCB的时候,会自动设置GPIOC1A、GPIOC1B为P405、P406。如果用GPIOCA or GPIOCB,则只能二选一启用一个。

其次,进行gpt1 stack的设置:
先添加一个gpt:
image.png

在设置对应的配置,按照如下步骤设置或者检查对应的值是否正确:
image.png

各个部分的说明如下:

  • Common:主要是启用输出功能
  • General:主要是设置变量名、通道、模式、周期、周期单位,这些会生成到代码文件中,作为配置调用
  • Output:设置启用两个输出IO端口
  • Pins:检查是否为对应的引脚设置即可

做好了设置,生成代码,就可以在进行实际的代码编写了。
其他部分的代码FSP都生成好了,我们只需要编写关键调用即可:

void hal_entry(void)
{
    /* TODO: add your own code here */
    int32_t pwm_counter = 0;    // PWM次数计数
    uint32_t key_counter = 0;   // 按键次数计数
    bool status = false;        // 按键状态
    bool direction = true;      // 运转方向
    bsp_io_level_t Pin_P005;    // 定义按键1
    fsp_err_t err = FSP_SUCCESS;// 定义调用返回结果

    err = R_IOPORT_Open(&g_ioport_ctrl, &g_bsp_pin_cfg); // 初始化引脚
    assert(FSP_SUCCESS == err);                          // 判断是否初始化成功

    err = R_GPT_Open(&g_timer_gpt1_ctrl, &g_timer_gpt1_cfg); // 初始化GPT1
	assert(FSP_SUCCESS == err);                          // 判断是否初始化成功

    (void) R_GPT_Start(&g_timer_gpt1_ctrl);             //  启用GPT1

    err = R_GPT_PeriodSet(&g_timer_gpt1_ctrl, 10000);   // 设置运行频率为10KHz
    assert(FSP_SUCCESS == err);

    while (1) 
	{
        R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, &Pin_P005); // 读取按键1的结果
        if (Pin_P005 == BSP_IO_LEVEL_LOW && !status)
        { // 判断按键有没有按下
            status = true;  // 设置按下状态
            key_counter++;  // 按键次数+1
        }
        else if (Pin_P005 == BSP_IO_LEVEL_HIGH && status)
        { // 判断按键有没有松开
            status = false; // 设置松开状态
        }

        if(key_counter%2==0) {
            // 偶数次按下,则保持运转状态
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_HIGH); // 点亮LED

            // 设置占空比
            err = R_GPT_DutyCycleSet(&g_timer_gpt1_ctrl, pwm_counter, GPT_IO_PIN_GTIOCA_AND_GTIOCB);
            assert(FSP_SUCCESS == err);

            // 延时
            R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);
        } else {
            // 奇数次按下,则正常运转
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_15, BSP_IO_LEVEL_LOW); // 关闭LED

            // 根据运转方向,设置是加速还是减速,实际运转,将类似呼吸灯,逐渐加速直到最大值,再逐渐减速直到最小值,如此反复
            if(direction) {
                pwm_counter += 100;
            } else {
                pwm_counter -= 100;            
            }
            if (pwm_counter > 10000) {
                // 超过最大值,则保持最大值,但方向转向
                pwm_counter = 10000;
                direction = !direction;

                // 设置占空比
                err = R_GPT_DutyCycleSet(&g_timer_gpt1_ctrl, 0, GPT_IO_PIN_GTIOCA_AND_GTIOCB);
                assert(FSP_SUCCESS == err);
            }
            else if (pwm_counter < 0) {
                //  达到最小值,则保持最小值,但方向转向
                pwm_counter = 0;
                direction = !direction;

                // 设置占空比
                err = R_GPT_DutyCycleSet(&g_timer_gpt1_ctrl, 0, GPT_IO_PIN_GTIOCA_AND_GTIOCB);
                assert(FSP_SUCCESS == err);
            }
            else {
                // 设置占空比
                err = R_GPT_DutyCycleSet(&g_timer_gpt1_ctrl, pwm_counter, GPT_IO_PIN_GTIOCA_AND_GTIOCB);
                assert(FSP_SUCCESS == err);
            }

            // 设置运转方向及指示灯
            if(direction) {
                R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_HIGH);
            } else {
                R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW);
            }

            // 延时
            R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);
        }
	}

#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

上述代码的逻辑非常清晰,注解也很详细,就不一一说明了,几个重点说一下:

  1. 按键采用了根据按下计数次数,来进行是否保持的设定;如果按下偶数次,则保持;如果按下奇数次,则不保持。这样做的目的,是为了防止按下的时候,如果一直检测到按下,则会不断地触发。也可以用按下来进行保持,松开则不包吃,但是这样并不方便。
  2. 占空比根据direction,来自动进行增加或者减小,在0~10000之间往复
  3. 实际运转的时候,如果处于非保持状态,则自动加速到最大速度,然后反向运转,自动减速到最小速度,如此往复;在次之间任意时刻按下按键,则会保持当前的转速运转;再按一次,则恢复往复运转状态。

在编译烧录上诉代码之前,把MX1508和电机节后,然后接到开发板上。
通过开发板的手册,可以得知,开发板上有两个PMOD接口,P406在PMOD1上,可以用该PMOD接口,直接驱动DC电机,非常方便:
image.png

具体的接线如下:
image.png

image.png

为了方便检查,点击电机按照预期的方向运转,我在点击前面挂了一张纸巾,这样就可以根据纸巾飘动方向,来判断运转是否正常了。

实际运转的效果如下:
image.png

image.png

具体控制效果,可以查看文章后面的视频。

通过视频可以看到,使用按键1,可以很方便的进行速度的保持,不管是在高速状态,还是在低速状态。
而在非保持状态下,电机按照预期的,先加速,再转向减速,纸巾的飘动方向和幅度也随之变化。
另外,当占空比过低的时候,电机会不启动。

【瑞萨RA4系列开发板体验】基于PWM控制的无极调速电机控制演示

更多回帖

发帖
×
20
完善资料,
赚取积分