OpenEdv-开源电子网

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

包含高级定时器的多路多通道PWM输出的探索与疑问

[复制链接]

17

主题

97

帖子

0

精华

高级会员

Rank: 4

积分
822
金钱
822
注册时间
2020-7-21
在线时间
85 小时
发表于 2020-8-12 16:57:26 | 显示全部楼层 |阅读模式
1金钱
板子:STM32F103RCT6               
目的:在TIM3的通道3和4、TIM5的通道1和2、高级定时器TIM8的通道1234输出PWM波
要用到的引脚:经alldatasheet查询,
  1. /************************************************************************************
  2.   电机编号                     PWM
  3. -------------------------------------------------------------------------------------               
  4.                  1               |       PB0-TIM3CH3                                      PB1-TIM3CH4       |
  5.                  |                                                                               |
  6.                  2               |       PA0-TIM5CH1                                      PA1-TIM5CH2       |
  7.                  |                                                                               |
  8.                  3               |       PC6-TIM8CH1                                      PC7-TIM8CH2       |
  9.                  |                                                                               |
  10.                  4               |       PC8-TIM8CH3                                      PC9-TIM8CH4       |
  11. -------------------------------------------------------------------------------------


  12. ************************************************************************************/
复制代码


具体过程:
      首先放一个能成功同时在TIM3的两个通道的代码
  1. void TIM3_PWM_Init(u16 arr, u16 psc)           //PWM 用TIM3CH3、TIM3CH4
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  5.         TIM_OCInitTypeDef  TIM_OCInitStructure;
  6.        

  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);        //使能定时器3时钟
  8.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟

  9. //设置该引脚为复用输出功能,输出TIM3 CH3/4的PWM脉冲波形        GPIOB0/1
  10.         GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1; //TIM_CH3/4
  11.         GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;        //复用推挽输出
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.         GPIO_Init(GPIOB, &GPIO_InitStructure);                 //初始化GPIO

  14.    //初始化TIM3
  15.         TIM_TimeBaseStructure.TIM_Period        = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
  16.         TIM_TimeBaseStructure.TIM_Prescaler     = psc; //设置用来作为TIMx时钟频率除数的预分频值
  17.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
  18.         TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;  //TIM向上计数模式
  19.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
  20.        
  21.         //初始化TIM3 Channel3 PWM模式         
  22.         TIM_OCInitStructure.TIM_OCMode      = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
  23.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  24.         TIM_OCInitStructure.TIM_OCPolarity  = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
  25.         TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC3

  26.         TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR3上的预装载寄存器

  27. //初始化TIM3 Channel PWM模式
  28.         TIM_OCInitStructure.TIM_OCMode      = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
  29.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  30.         TIM_OCInitStructure.TIM_OCPolarity  = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
  31.         TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC4

  32.         TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR4上的预装载寄存器

  33.         TIM_Cmd(TIM3, ENABLE);  //使能TIM3
  34.        
  35. }
复制代码
经仿真和示波器接入测试,该PWM输出能正常使用。之后,我又尝试把其他的初始化也揉在一起。
  1. void TIM_PWM_Init(u16 arr, u16 psc)           //PWM 用TIM3CH3、TIM3CH4
  2. {
  3.         GPIO_InitTypeDef GPIO_InitStructure;
  4.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  5.         TIM_OCInitTypeDef  TIM_OCInitStructure;
  6.         TIM_OCStructInit(&TIM_OCInitStructure);

  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3
  8.                                      |RCC_APB1Periph_TIM5, ENABLE);        //使能定时器3/5/8时钟

  9.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB
  10.                                      |RCC_APB2Periph_GPIOA
  11.                                      |RCC_APB2Periph_GPIOC
  12.                                      |RCC_APB2Periph_TIM8
  13.                                      |RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟

  14.                                                            //设置该引脚为复用输出功能,输出TIM3 CH3/4的PWM脉冲波形        GPIOB0/1
  15.         GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1; //TIM3_CH3/4
  16.         GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;        //复用推挽输出
  17.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18.         GPIO_Init(GPIOB, &GPIO_InitStructure);                 //初始化GPIO
  19.        
  20.         GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1; //TIM5_CH1/2
  21.         GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;        //复用推挽输出
  22.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  23.         GPIO_Init(GPIOA, &GPIO_InitStructure);                 //初始化GPIO
  24.        
  25.         GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6
  26.                                            | GPIO_Pin_7
  27.                                            | GPIO_Pin_8
  28.                                            | GPIO_Pin_9; //TIM8_CH1/2/3/4
  29.         GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;        //复用推挽输出
  30.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  31.         GPIO_Init(GPIOC, &GPIO_InitStructure);                 //初始化GPIO       

  32.    //初始化TIM3
  33.         TIM_TimeBaseStructure.TIM_Period        = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
  34.         TIM_TimeBaseStructure.TIM_Prescaler     = psc; //设置用来作为TIMx时钟频率除数的预分频值
  35.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
  36.         TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;  //TIM向上计数模式

  37.         TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
  38.         TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
  39.         TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);


  40. ///////////////////////////////////////////////////////////////////////////////////////////////       
  41.         //初始化TIM3 Channel3 PWM模式         
  42.         TIM_OCInitStructure.TIM_OCMode      = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
  43.         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
  44.         TIM_OCInitStructure.TIM_OCPolarity  = TIM_OCPolarity_Low; //输出极性:低电平有效

  45.         TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC3
  46.         TIM_OC3Init(TIM8, &TIM_OCInitStructure);
  47.         TIM_OC2Init(TIM5, &TIM_OCInitStructure);  
  48.         TIM_OC2Init(TIM8, &TIM_OCInitStructure);

  49.         TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC3
  50.         TIM_OC1Init(TIM8, &TIM_OCInitStructure);
  51.         TIM_OC1Init(TIM5, &TIM_OCInitStructure);  
  52.         TIM_OC4Init(TIM8, &TIM_OCInitStructure);
  53.        
  54.         TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR3上的预装载寄存器
  55.         TIM_OC3PreloadConfig(TIM8, TIM_OCPreload_Enable);        
  56.         TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  
  57.         TIM_OC4PreloadConfig(TIM8, TIM_OCPreload_Enable);

  58.         TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable);  
  59.         TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);        
  60.         TIM_OC2PreloadConfig(TIM5, TIM_OCPreload_Enable);  //使能TIM3在CCR4上的预装载寄存器
  61.         TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);

  62.         TIM_CtrlPWMOutputs(TIM8, ENABLE);

  63.         TIM_Cmd(TIM3, ENABLE);  //使能TIM3
  64.         TIM_Cmd(TIM5, ENABLE);
  65.         TIM_Cmd(TIM8, ENABLE);
复制代码
并在主函数补上了CCRx
  1. TIM_SetCompare3(TIM3, 200);         
  2.   TIM_SetCompare4(TIM3, 200);
  3.         TIM_SetCompare1(TIM5, 200);         
  4.   TIM_SetCompare2(TIM5, 200);       
  5.         TIM_SetCompare1(TIM8, 200);         
  6.   TIM_SetCompare2(TIM8, 200);       
  7.         TIM_SetCompare3(TIM8, 200);         
  8.   TIM_SetCompare4(TIM8, 200);       
复制代码


结果没有成功,于是我尝试去看原子哥的视频,发现对于多路PWM和高级定时器的讲解很少,于是我尝试借助网络,学习到两个点:
     ①要输出多路PWM应该加第五行TIM_OCStructInit(&TIM_OCInitStructure);这个函数(第五行),
     ②对于高级定时器输出PWM波,要加TIM_CtrlPWMOutputs(TIM8, ENABLE);这个函数(倒数第四行)。


通过仿真,我们发现,只有TIM3的通道3、通道4能正常输出PWM波,其他路都不能输出,均为低电平。而在示波器接入测试中,所有定时器通道不能输出任何PWM波
附仿真图片(图片中的第三路为PA1)


初步猜测可能是初始化函数步骤混乱,卡了一天没有解决,希望有配置经验的大佬指点一二。



图片1.png
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2020-8-13 01:46:47 | 显示全部楼层
这种仿真,看下寄存器状态,就比较容易解决问题。
回复

使用道具 举报

17

主题

97

帖子

0

精华

高级会员

Rank: 4

积分
822
金钱
822
注册时间
2020-7-21
在线时间
85 小时
 楼主| 发表于 2020-8-13 15:38:50 | 显示全部楼层
正点原子 发表于 2020-8-13 01:46
这种仿真,看下寄存器状态,就比较容易解决问题。

注意到了,问题出在TIM5的ODR寄存器没有被写入,不知道为啥,目前改成用TIM2临时解决了
回复

使用道具 举报

15

主题

70

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
202
金钱
202
注册时间
2019-8-27
在线时间
44 小时
发表于 2020-8-13 16:13:58 | 显示全部楼层
我之前是用同样的配置,定时器3,通道1,2和定时器4通道3,4输出PWM,然后定时器4的不能输出,找了好久发现前面先配置的pwm输出通道,后面又配置了别的东西,把引脚配置覆盖了。
回复

使用道具 举报

17

主题

97

帖子

0

精华

高级会员

Rank: 4

积分
822
金钱
822
注册时间
2020-7-21
在线时间
85 小时
 楼主| 发表于 2020-8-14 08:57:51 | 显示全部楼层
a7600241 发表于 2020-8-13 16:13
我之前是用同样的配置,定时器3,通道1,2和定时器4通道3,4输出PWM,然后定时器4的不能输出,找了好久发现前 ...

我用仿真看了一下发现问题是出在GPIO的ODR寄存器的值没有写进去
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-9 04:19

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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