你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F407用PWM的问题??谢谢

[复制链接]
Seny Lee 提问时间:2016-6-21 17:21 /
      最近在做一个项目,需要用到STM32F407的定时器产生一个频率可调的PWM驱动电机,思路是这样的??

     需要放出的PWM放在两个数组里面,cycles表示需要放脉冲的时间(按照定时器单位周期为单位),steps表示在指定的cycles时间内需要放出的脉冲的数量。表示如下:
  1. int16_t steps[10] = {5,-5,6,-7,8,-9,0,3};
  2. uint32_t cycles[10] = {354672,145256,33423,45612,180356,20444,5647343};
复制代码

     最后用STM32F407的PF9(TIM14)作为PWM输出引脚,PC2作为方向引脚,

       思路大概是:我首先开启定时器(定时10ms),在第一次中断中记录该次pwm脉冲的宽度,并把值转化为PSC和ARR的值,采用自动重装模式,也就是在本次中断里面计算出下一个脉冲的宽度,最后选择在中断时自动PSC和ARR的值,进行放脉冲(第一个10ms中断目的就是重装第一个pwm脉冲的宽度,在 10ms之后放出)。
      最后发现实际放出的脉冲数组的每段少放一个脉冲,比如数组的第一列,在354672个周期内放出5个脉冲,实际只放出了4个脉冲,少了一个,数组的每列都少放了一个脉冲,不知道什么情况,我猜测是不是寄存器重装(PSC和ARR的值)装载出了问题?这一块由于不是很熟悉,调试了一个上午,现象依旧,大家帮忙看一下代码?非常感谢!

      初始化函数:
  1. void Motor_Init_T1(void)
  2. {
  3. //定义IO口初始化变量
  4. GPIO_InitTypeDef GPIO_InitStructure;

  5. //定义定时器初始化变量
  6. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  7. TIM_OCInitTypeDef TIM_OCInitStructure;
  8. NVIC_InitTypeDef        NVIC_InitStructure;


  9. //定时器时钟初始化
  10. RCC_APB1PeriphClockCmd(MOTOR1_TIMER_CLOCK, ENABLE);

  11. //IO口时钟初始化
  12. RCC_AHB1PeriphClockCmd(MOTOR1_PU_CLOCK | MOTOR1_DR_CLOCK, ENABLE);


  13. //MOTOR_DR1 IO口初始化
  14. GPIO_InitStructure.GPIO_Pin = MOTOR1_DR_PIN;        
  15. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;        
  16. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;        
  17. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        
  18. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  19. GPIO_Init(MOTOR1_DR_BASE, &GPIO_InitStructure);
  20. //初始化方向引脚电平
  21. MOTOR_DR_OUTBIT = 1;

  22. //初始化MOTOR_PU IO口
  23. GPIO_InitStructure.GPIO_Pin = MOTOR1_PU_PIN ;
  24. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  25. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  26. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  27. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
  28. GPIO_Init(MOTOR1_PU_BASE, &GPIO_InitStructure);

  29. //设置定时器PWM输出到MOTOR_PU1引脚上
  30. GPIO_PinAFConfig(MOTOR1_PU_BASE, MOTOR1_PU_PINSOURCE, GPIO_AF_TIM14);

  31. //定时器中断初始化
  32. NVIC_InitStructure.NVIC_IRQChannel = TIM8_TRG_COM_TIM14_IRQn;
  33. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  34. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  35. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  36. NVIC_Init(&NVIC_InitStructure);

  37. //定时器初始化
  38. TIM_DeInit(TIM14);
  39. TIM_TimeBaseStructure.TIM_Period = 999;
  40. TIM_TimeBaseStructure.TIM_Prescaler = 839;
  41. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  42. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  43. TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);

  44. TIM_OCStructInit(&TIM_OCInitStructure);
  45. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  46. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  47. TIM_OCInitStructure.TIM_Pulse = 0xffff;
  48. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  49. TIM_OC1Init(TIM14, &TIM_OCInitStructure);
  50. TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);

  51. TIM_ClearFlag(TIM14, TIM_FLAG_Update);
  52. TIM_ITConfig(TIM14, TIM_IT_Update, ENABLE);

  53. TIM_ARRPreloadConfig(TIM14, ENABLE);
  54. TIM_Cmd(TIM14, DISABLE);

  55. }
复制代码


     定时器溢出中断处理函数:
  1. uint16_t        serial = 0;
  2. uint16_t        serialOld = 0;
  3. int16_t        dir = 1;
  4. uint16_t count = 0;
  5. uint16_t        period = 1000, prescaler = 840;
  6. uint16_t        pulse = 0xffff;


  7. uint16_t error = 0; //误差累计值,计算脉冲的时间产生的误差,叠加到下一个脉冲中去)
  8. uint32_t times = 0;


  9. uint16_t        serialNums = 1;//要放出脉冲的数组的个数(小于数据的长度即可)
  10. uint16_t        stepNums = 0;



  11. void Motor_ISR_T1( const int16_t * pSteps, const uint32_t        * pCycles)
  12. {
  13. uint32_t        timerPwm = 0;

  14. if(serial <= serialNums)
  15. {
  16. TIM_SetCompare1(TIM14,pulse);        
  17. }
  18. if(count == 0)
  19. {
  20. if(serial < serialNums)
  21. {
  22. if(pSteps[serial] > 0)
  23. {
  24. MOTOR_DR_OUTBIT = 1;        //正方向
  25. count = pSteps[serial];
  26. }
  27. else if(pSteps[serial] < 0)
  28. {
  29. MOTOR_DR_OUTBIT = 0;        //反方向
  30. count = -pSteps[serial];
  31. }
  32. else if (pSteps[serial] == 0)
  33. {
  34. count = 5;
  35. }
  36. times = pCycles[serial] + error;

  37. serial++;
  38. serialOld = serial - 1;
  39. }
  40. else if(serial == serialNums)
  41. {
  42. serial++;
  43. }
  44. else if(serial > serialNums)        //脉冲已经全部放完
  45. {
  46. Motor_Stop_T1();
  47. }
  48. }

  49. if(count > 0)        //有脉冲需要放
  50. {        
  51. timerPwm = times/count;

  52. prescaler = (timerPwm >> 16) + 1;

  53. period = timerPwm/prescaler;

  54. error = timerPwm - period * prescaler;

  55. times = times - timerPwm + error;

  56. TIM_PrescalerConfig(TIM14, prescaler - 1, TIM_PSCReloadMode_Update);
  57. TIM_SetAutoreload(TIM14, period - 1);

  58. if(pSteps[serialOld] == 0)
  59. {
  60. pulse = 0xffff;
  61. }
  62. else
  63. {
  64. pulse = period - (4000/prescaler + 1);
  65. }
  66. count--;
  67. }
  68. }
复制代码


               这里serialNums 为1表示只放出数组的第一列的数据,5个脉冲,实际只放出了4个,如果取2,表示只放出2列总计10个脉冲,前面5个正转,后面5个反转,但是实际只放出了4+4 = 8个脉冲,就是数据每一列都会少放一个脉冲!!!
收藏 评论2 发布时间:2016-6-21 17:21

举报

2个回答
xmshao 回答时间:2016-6-22 17:14:54
会不会跟CCR/ARR预装载配置有关?

请检查确认下。

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 2 很给力!

查看全部评分

Seny Lee 回答时间:2016-6-26 14:32:21
非常感谢,已经发现是CCR的预装载出现问题,谢谢!!!!

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 2

查看全部评分

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版