查看: 571|回复: 1

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

[复制链接]

116

主题

133

帖子

3768

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3768
发表于 2023-2-8 09:50:39 | 显示全部楼层 |阅读模式
【瑞萨RA4系列开发板体验】基于PWM控制的无极调速电机控制
作者:HonestQiao

之前分享过GPT定时器的基础使用,把GPT作为基础的定时器来使用的。
在RA系列板子上,GPT更重要的作用之一,是进行PWM输出,不然对不起他的全名:General PWM Timer。
要使用PWM输出功能,借助FSP工具,可以很方便的进行配置,然后在代码中进行对应的调用处理。
正好,我手头有一个MX1508的直流电机控制模块,以及一个带风扇的小直流电机,刚好可以用上。
MX1508一般是这样的:
可以同时控制两路直流电机,例如在小车上使用。
通常按照如下方式使用:
不过,我手头的这个,只能控制一个电机:
通过MX1508控制电机,需要两个信号接口,一个是PWM控制转速,一个是DIR控制方向。
通过查看RA4M2的硬件手册和原理图,最终进行如下的设计:
  • PWM控制使用GPT1,因为其两个PWM输出IO口,分别为P405、P406,而P405刚好接到了板子上的LED3,可以用其亮度,表示当前PWM的占空比情况,而P406则输出控制电机
  • 使用LED2来表示电机运转的方向,其对应的控制引脚为P404,同时用于控制电机运转的方向
  • 使用板载SW1按键,其对应的因较为P005,用来控制是否保持电机当前的转速;同时,使用LED1的亮灭表示是否保持。
对应的手册信息如下:
做好了设计规划,就先用FSP进行设置。
首先,P405默认设置为普通IO控制LED3,如果要使用PWM进行控制,则需要取消原有的设置,也就是禁用P405默认的配置:
然后,配置GPT1:
当选择GPIOCA and GPIOCB的时候,会自动设置GPIOC1A、GPIOC1B为P405、P406。如果用GPIOCA or GPIOCB,则只能二选一启用一个。
其次,进行gpt1 stack的设置:
先添加一个gpt:
在设置对应的配置,按照如下步骤设置或者检查对应的值是否正确:
各个部分的说明如下:
  • Common:主要是启用输出功能
  • General:主要是设置变量名、通道、模式、周期、周期单位,这些会生成到代码文件中,作为配置调用
  • Output:设置启用两个输出IO端口
  • Pins:检查是否为对应的引脚设置即可
做好了设置,生成代码,就可以在进行实际的代码编写了。
其他部分的代码FSP都生成好了,我们只需要编写关键调用即可:
  1. void hal_entry(void)
  2. {
  3.     /* TODO: add your own code here */
  4.     int32_t pwm_counter = 0;    // PWM次数计数
  5.     uint32_t key_counter = 0;   // 按键次数计数
  6.     bool status = false;        // 按键状态
  7.     bool direction = true;      // 运转方向
  8.     bsp_io_level_t Pin_P005;    // 定义按键1
  9.     fsp_err_t err = FSP_SUCCESS;// 定义调用返回结果

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

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

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

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

  17.     while (1)
  18.         {
  19.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, &Pin_P005); // 读取按键1的结果
  20.         if (Pin_P005 == BSP_IO_LEVEL_LOW && !status)
  21.         { // 判断按键有没有按下
  22.             status = true;  // 设置按下状态
  23.             key_counter++;  // 按键次数+1
  24.         }
  25.         else if (Pin_P005 == BSP_IO_LEVEL_HIGH && status)
  26.         { // 判断按键有没有松开
  27.             status = false; // 设置松开状态
  28.         }

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

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

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

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

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

  58.                 // 设置占空比
  59.                 err = R_GPT_DutyCycleSet(&g_timer_gpt1_ctrl, 0, GPT_IO_PIN_GTIOCA_AND_GTIOCB);
  60.                 assert(FSP_SUCCESS == err);
  61.             }
  62.             else {
  63.                 // 设置占空比
  64.                 err = R_GPT_DutyCycleSet(&g_timer_gpt1_ctrl, pwm_counter, GPT_IO_PIN_GTIOCA_AND_GTIOCB);
  65.                 assert(FSP_SUCCESS == err);
  66.             }

  67.             // 设置运转方向及指示灯
  68.             if(direction) {
  69.                 R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_HIGH);
  70.             } else {
  71.                 R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_04, BSP_IO_LEVEL_LOW);
  72.             }

  73.             // 延时
  74.             R_BSP_SoftwareDelay (100, BSP_DELAY_UNITS_MILLISECONDS);
  75.         }
  76.         }

  77. #if BSP_TZ_SECURE_BUILD
  78.     /* Enter non-secure code */
  79.     R_BSP_NonSecureEnter();
  80. #endif
  81. }
复制代码
上述代码的逻辑非常清晰,注解也很详细,就不一一说明了,几个重点说一下:
  • 按键采用了根据按下计数次数,来进行是否保持的设定;如果按下偶数次,则保持;如果按下奇数次,则不保持。这样做的目的,是为了防止按下的时候,如果一直检测到按下,则会不断地触发。也可以用按下来进行保持,松开则不包吃,但是这样并不方便。
  • 占空比根据direction,来自动进行增加或者减小,在0~10000之间往复
  • 实际运转的时候,如果处于非保持状态,则自动加速到最大速度,然后反向运转,自动减速到最小速度,如此往复;在次之间任意时刻按下按键,则会保持当前的转速运转;再按一次,则恢复往复运转状态。
在编译烧录上诉代码之前,把MX1508和电机节后,然后接到开发板上。
通过开发板的手册,可以得知,开发板上有两个PMOD接口,P406在PMOD1上,可以用该PMOD接口,直接驱动DC电机,非常方便:
具体的接线如下:
为了方便检查,点击电机按照预期的方向运转,我在点击前面挂了一张纸巾,这样就可以根据纸巾飘动方向,来判断运转是否正常了。
实际运转的效果如下:
具体控制效果,可以查看文章后面的视频。
通过视频可以看到,使用按键1,可以很方便的进行速度的保持,不管是在高速状态,还是在低速状态。
而在非保持状态下,电机按照预期的,先加速,再转向减速,纸巾的飘动方向和幅度也随之变化。
另外,当占空比过低的时候,电机会不启动。


回复

使用道具 举报

3

主题

195

帖子

1191

积分

金牌会员

Rank: 6Rank: 6

积分
1191
发表于 2023-3-14 10:56:37 | 显示全部楼层

不错,学习一下
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

用户排行榜

RA助手

主题: 116帖子:133精华:0

RA_Lance

主题: 92帖子:132精华:9

lugl

主题: 38帖子:126精华:0

xujiwei263

主题: 16帖子:73精华:0

books咦

主题: 11帖子:11精华:2

Juggernaut

主题: 9帖子:95精华:0
快速回复 返回顶部 返回列表