OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4868|回复: 9

新手求助,PWM驱动舵机问题,急急急!!!

[复制链接]

4

主题

10

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2018-2-7
在线时间
6 小时
发表于 2019-2-26 10:46:09 | 显示全部楼层 |阅读模式
24金钱
本帖最后由 水墓年华 于 2019-2-26 11:17 编辑

大家好:
我是一个嵌入式初学者,现在要做一个小项目,需要用到PWM驱动的舵机,但是调试了好久也摸不清原理,代码也是网上找的,有些地方还不太理解,现在电机就是不停的正转大概30度,再转回来30度,这样一直循环,请各位帮忙解答一下
1.在定时器初始化函数中,设置时钟分频系数应该是htim2.Init.Prescaler = 168-1;将时钟频率分为更小的频率,如我的板子STM32F427是设置168M的时钟频率,设置psc=168分频,168/168=1得到1M时钟频率,但是我这样配置的话电机就不转了,我试了试最起码要在差不多400才能正常转起来,而且这个时候转的角度很小,大概在1200的时候能达到最大,大概是45度左右,是我理解的不对吗?
2.htim2.Init.Period = 200-1;这个是设定自动重装载值吗,周期是怎么算的?
3.我要如何更改代码才能实现精准的控制,比如现在怎么让舵机只朝一个方向转动
下面贴一下我的代码:
主函数

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM2_Init();

    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3);
    int n = 50;
    int dir = 0;

    while(1)
    {
        HAL_Delay(20);
        if(dir)n++;                                        //dir==1 n 递增
        else n--;                                          //dir==0 n 递减
        if(n>300)dir=0;                                    //n 到达 300 后,方向为递减
        if(n==50)dir=1;                                     //n 递减到 0 后,方向改为递增
        USER_PWM_SetDutyRatio(&htim2,TIM_CHANNEL_3,n);     //修改比较值,修改占空比
    }

定时器初始化

static void MX_TIM2_Init(void)
{

  TIM_MasterConfigTypeDef sMasterConfig;
  TIM_OC_InitTypeDef sConfigOC;

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 1200-1;                                   //该分频将时钟频率分为更小的频率,如STM32F429是设置168M的时钟频率,设置psc=168分频,得到1M时钟频率
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;                    //设置计数方式为向上计数逐一增加从0到19999,此时得到的是20ms就重装初值的定时器
  htim2.Init.Period = 200-1;                                      //自动重装载值,在设置arr=20000重装初值,由公式1M/20000=50Hz,即周期T=20ms
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

  HAL_TIM_MspPostInit(&htim2);
}

调整PWM占空比,value为占空比 value=50 即占空比为50%
void USER_PWM_SetDutyRatio(TIM_HandleTypeDef *htim,uint32_t Channel,uint8_t value)
{
    TIM_OC_InitTypeDef sConfigOC;
   
    uint32_t period=htim->Init.Period+1;
    uint32_t pluse=(value * period)/100;
   
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = pluse;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    HAL_TIM_PWM_ConfigChannel(htim, &sConfigOC, Channel);
    HAL_TIM_PWM_Start(htim, Channel);   
}


最佳答案

查看完整内容[请看2#楼]

你这问题有点大啊,第一,你贴的这个代码本来是用PWM来驱动led灯的,n值的改变是改CCRx值(比较值)的,是用来改led亮的明暗度的,你这个直接这么用会产生你的第一个问题,PWM驱动电机是将输出的PWM波接PU口,方向另有DIR口控制;第二, htim2.Init.Period是自动重载值,频率是 htim2.Init.Prescaler和htim2.Init.Period共同决定的,比如某定时器所在的时钟是168M,Prescaler为168,Period为500,那么PWM频率就是(168M/168)/500= ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

12

主题

108

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1825
金钱
1825
注册时间
2017-9-7
在线时间
501 小时
发表于 2019-2-26 10:46:10 | 显示全部楼层
你这问题有点大啊,第一,你贴的这个代码本来是用PWM来驱动led灯的,n值的改变是改CCRx值(比较值)的,是用来改led亮的明暗度的,你这个直接这么用会产生你的第一个问题,PWM驱动电机是将输出的PWM波接PU口,方向另有DIR口控制;第二, htim2.Init.Period是自动重载值,频率是 htim2.Init.Prescaler和htim2.Init.Period共同决定的,比如某定时器所在的时钟是168M,Prescaler为168,Period为500,那么PWM频率就是(168M/168)/500=2KHz;第三个问题就大了去了,精确控制的相关因素很多,实现固定方向转很简单,正确配置确定PWM输出频率,然后接PU口就可以了,要控制方向的话再加个IO驱动拉低拉高就可以了,先不要去改比较值,后续的速度啊,转多少圈啊什么的就得去摸了
回复

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2019-2-26 12:37:41 | 显示全部楼层
舵机只朝一个方向转动,用一个if(n>0)判断语句,n++阔以试下
还是要多改改看看
业精于勤荒于嬉;行成于思毁于随!
回复

使用道具 举报

4

主题

10

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2018-2-7
在线时间
6 小时
 楼主| 发表于 2019-2-26 16:43:50 | 显示全部楼层
1208 发表于 2019-2-26 12:37
舵机只朝一个方向转动,用一个if(n>0)判断语句,n++阔以试下
还是要多改改看看

这样还是不行,参数我也改了好多次了
回复

使用道具 举报

4

主题

10

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2018-2-7
在线时间
6 小时
 楼主| 发表于 2019-2-26 17:12:14 | 显示全部楼层
亦辰 发表于 2019-2-26 10:46
你这问题有点大啊,第一,你贴的这个代码本来是用PWM来驱动led灯的,n值的改变是改CCRx值(比较值)的,是 ...

谢谢,听你这么一说恍然大悟,一下子懂了点,麻烦再问下有你有没有相关的驱动电机的代码,有的话让我参考一下可以吗,还有就是我这个是舵机只有电源正负极,白色的信号线这三根线,那就是说这个白色信号线接PWM波输出,没有DIR口的概念对吗,这个要怎么控制呢,能详细说说吗
回复

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4306
金钱
4306
注册时间
2018-6-30
在线时间
808 小时
发表于 2019-2-26 18:52:20 | 显示全部楼层
水墓年华 发表于 2019-2-26 16:43
这样还是不行,参数我也改了好多次了

电机控制这一块还没开始弄过,你试下二楼大佬的建议,看看如何,网上也有相关的资料可以找下CSDN
业精于勤荒于嬉;行成于思毁于随!
回复

使用道具 举报

12

主题

108

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1825
金钱
1825
注册时间
2017-9-7
在线时间
501 小时
发表于 2019-2-27 09:18:55 | 显示全部楼层
本帖最后由 亦辰 于 2019-2-27 14:30 编辑
水墓年华 发表于 2019-2-26 17:12
谢谢,听你这么一说恍然大悟,一下子懂了点,麻烦再问下有你有没有相关的驱动电机的代码,有的话让我 ...

额。。有点尴尬,我把舵机理解成伺服电机了,我查了下资料,舵机的基准信号的周期为20ms,也就是50Hz,所以先配置周期,就是配置htim2.Init.Prescaler和htim2.Init.Period两个值,根据50Hz可以去匹配,这里我配出的是htim2.Init.Prescaler=672-1,htim2.Init.Period=5000-1,然后舵机是根据占空比来转角度的,占空比由比较值确定,典型值是1ms-2ms,基准位置1.5ms,所以根据这个来配置比较值,根据典型值,占空比应该在5%-10%浮动,基准位置为7.5%,看了你下面的代码,是用pluse来设置的,可能有点不一样,为了方便USER_PWM_SetDutyRatio()函数中pluse=(value * period)/1000改成这样,value的值是在50-100之间的,就是说主函数里面n的值是在50-100之间改变,判断以100为上界,50为下界,只要一个方向的话,应该是50-75,或者75-100,改下相应的上下界就行C:\Users\Administrator\Desktop\Snipaste_2019-02-27_09-12-27.png
Snipaste_2019-02-27_09-12-27.png
回复

使用道具 举报

4

主题

10

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2018-2-7
在线时间
6 小时
 楼主| 发表于 2019-2-27 10:16:45 | 显示全部楼层
本帖最后由 水墓年华 于 2019-2-27 10:18 编辑
亦辰 发表于 2019-2-27 09:18
额。。有点尴尬,我把舵机理解成伺服电机了,我查了下资料,舵机的基准信号的周期为20ms,也就是500Hz, ...

C:\Users\hao\Desktop\TIM截图20190227095301哦哦好,那这些参数配置和我的时钟配置无关吗,这个是我的时钟配置图,我想问下我如何确定TIM2现在用的是APB1还是APB2呢?还有你说的Prescaler和Period这两个值是根据什么去配的可以说明一下吗。你说的比较值又该如何理解呢
TIM截图20190227095301.png
回复

使用道具 举报

12

主题

108

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1825
金钱
1825
注册时间
2017-9-7
在线时间
501 小时
发表于 2019-2-27 11:01:46 | 显示全部楼层
本帖最后由 亦辰 于 2019-2-27 14:30 编辑
水墓年华 发表于 2019-2-27 10:16
哦哦好,那这些参数配置和我的时钟配置无关吗,这个是我的时钟配置图,我想问下我如何确定TIM2现在用的是 ...

你提供的代码说明你的时钟是在APB2的啊,怎么看的要去看stm32的参考手册,哪个外设在哪个总线上都有说明;Prescaler和Period根据你需求的周期来配,已经说明过了的,比如是需要20ms的周期,那频率就是50Hz,根据外设所在的时钟总线频率,若为168M,Prescaler就是对168M进行分频,Period是对分频后的时钟进行分段,所谓自动重载值是计数到这个值后归零重新计数(向上计数方式),比较值你在看下图理解吧,CCR就是比较值
Snipaste_2019-02-27_11-00-51.png
Snipaste_2019-02-27_11-00-01.png
回复

使用道具 举报

4

主题

10

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2018-2-7
在线时间
6 小时
 楼主| 发表于 2019-2-27 13:21:12 | 显示全部楼层
亦辰 发表于 2019-2-27 11:01
你提供的代码说明你的时钟是在APB2的啊,怎么看的要去看stm32的参考手册,哪个外设在哪个总线上都有说明 ...

好的明白了,谢谢呀,我再去看看
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-9 22:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表