搜索
查看: 4435|回复: 3

[分享] STM32一定时器产生不同频率的PWM

[复制链接]
  • TA的每日心情
    开心
    2018-2-6 09:20
  • 签到天数: 1 天

    [LV.1]初来乍到

    1182

    主题

    4967

    帖子

    1

    蝴蝶豆

    论坛元老

    最后登录
    2020-3-17
    发表于 2017-6-13 11:16:18 | 显示全部楼层 |阅读模式
    平时记性实在太差,调试完的程序,过两天又忘了,往往需要一阵子才能想起来,有时以前的资料找不到了,更是恼火,不得不重复到网上搜索。刚刚调试成功了一个类型的程序,立刻记下来,呵呵,不要又忘记了。

    STM32产生PWM是非常的方便的,要需要简单的设置定时器,即刻产生!当然,简单的设置对于新手来产,也是麻烦的,主要包括:

    (1)使能定时器时钟:RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    (2)定义相应的GPIO

    1. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
    2. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //下拉接地,检测输入的高电平
    3. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
    4. GPIO_Init(GPIOA, &GPIO_InitStructure);

    5. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    6. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    7. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
    8. GPIO_Init(GPIOA, &GPIO_InitStructure);
    复制代码

    (3)如果是产生PWM(频率不变,占空比可变),记得打开PWM控制,在TIM_Configuration()中。

    1. TIM_Cmd(TIM3,ENABLE);

    2. TIM_CtrlPWMOutputs(TIM1,ENABLE);
    复制代码

    利用定时器产生不同频率的PWM

    有时候,需要产生不同频率的PWM,这个时候,设置与产生相同PWM的程序,有关键的不一样。

    (一) 设置的原理

       利用改变定时器输出比较通道的捕获值,当输出通道捕获值产生中断时,在中断中将捕获值改变,这时, 输出的I/O会产生一个电平翻转,利用这种办法,实现不同频率的PWM输出。

    (二)关键设置

    在定时器设置中:TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);

    在中断函数中:


    1. if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
    2.    {
    3.    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
    4. capture = TIM_GetCapture2(TIM3);
    5.    TIM_SetCompare2(TIM3, capture + Key_Value);
    6. }
    复制代码

    一个定时器四个通道,分别产生不同频率(这个例子网上也有)

    1. <span style="background-color: white;">vu16 CCR1_Val = 32768;
    2. vu16 CCR2_Val = 16384;
    3. vu16 CCR3_Val = 8192;
    4. vu16 CCR4_Val = 4096;

    5. void TIM_Configuration(void)
    6. {
    7. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    8. TIM_OCInitTypeDef TIM_OCInitStructure;

    9. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    10. TIM_TimeBaseStructure.TIM_Period = 65535;      
    11. TIM_TimeBaseStructure.TIM_Prescaler = 2;     
    12. TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    13. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    14. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    15. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;      //PWM模式2
    16. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //正向通道有效
    17. TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//反向通道无效
    18. TIM_OCInitStructure.TIM_Pulse = CCR1_Val;        //占空时间
    19. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;    //输出极性
    20. TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;    //互补端的极性
    21. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    22. TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

    23. TIM_OC1Init(TIM2,&TIM_OCInitStructure);        //通道1
    24. TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);

    25. TIM_OCInitStructure.TIM_Pulse = CCR2_Val;        //占空时间
    26. TIM_OC2Init(TIM2,&TIM_OCInitStructure);        //通道2
    27. TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);

    28. TIM_OCInitStructure.TIM_Pulse = CCR3_Val;        //占空时间
    29. TIM_OC3Init(TIM2,&TIM_OCInitStructure);        //通道3
    30. TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);

    31. TIM_OCInitStructure.TIM_Pulse = CCR4_Val;        //占空时间
    32. TIM_OC4Init(TIM2,&TIM_OCInitStructure);        //通道4
    33. TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);

    34. TIM_Cmd(TIM2,ENABLE);

    35. //TIM_CtrlPWMOutputs(TIM2,ENABLE);

    36. TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);

    37. }

    38. void GPIO_Configuration(void)
    39. {
    40. GPIO_InitTypeDef GPIO_InitStructure;

    41. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    42. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    43. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    44. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);

    45. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
    46. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
    47. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
    48. GPIO_Init(GPIOA, &GPIO_InitStructure);

    49. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
    50. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //开漏输出
    51. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M时钟速度
    52. GPIO_Init(GPIOB, &GPIO_InitStructure);

    53. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
    54. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //上拉输入
    55. GPIO_Init(GPIOA, &GPIO_InitStructure);

    56. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    57. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //上拉输入
    58. GPIO_Init(GPIOC, &GPIO_InitStructure);

    59. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    60. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  //上拉输入
    61. GPIO_Init(GPIOB, &GPIO_InitStructure);

    62. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    63. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    64. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    65. GPIO_Init(GPIOA, &GPIO_InitStructure);
    66. }

    67. void NVIC_Configuration(void)
    68. {
    69. NVIC_InitTypeDef NVIC_InitStructure;

    70. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    71. NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
    72. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
    73. NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
    74. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    75. NVIC_Init(&NVIC_InitStructure);
    76. }

    77. u16 capture = 0;
    78. extern vu16 CCR1_Val;
    79. extern vu16 CCR2_Val;
    80. extern vu16 CCR3_Val;
    81. extern vu16 CCR4_Val;

    82. void TIM2_IRQHandler(void)
    83. {


    84. if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
    85. {
    86.     TIM_ClearITPendingBit(TIM2, TIM_IT_CC1 );
    87. capture = TIM_GetCapture1(TIM2);
    88. TIM_SetCompare1(TIM2, capture + CCR1_Val );
    89. }

    90. if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
    91. {
    92.     TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
    93. capture = TIM_GetCapture2(TIM2);
    94.     TIM_SetCompare2(TIM2, capture + CCR2_Val);
    95. }

    96. if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)
    97. {
    98.     TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
    99. capture = TIM_GetCapture3(TIM2);
    100.     TIM_SetCompare3(TIM2, capture + CCR3_Val);
    101. }

    102. if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)
    103. {
    104.     TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
    105. capture = TIM_GetCapture4(TIM2);
    106.     TIM_SetCompare4(TIM2, capture + CCR4_Val);
    107. }

    108. }</span>
    复制代码

    一个定时器一个通道,产生不同频率

    其它的设置都一样,就是在主函数中修改一个参数,然后在定时器中断中,根据这个参数,改变频率。

    1. <span style="background-color: white;">#include "stm32lib\\stm32f10x.h"
    2. #include "hal.h"
    3. volatile u16 Key_Value=1000;  //用于保存按键相应的PWM波占空比值
    4. int main(void)
    5. {
    6. ChipHalInit();
    7. ChipOutHalInit();
    8. while(1)
    9. {
    10.   if( (!Get_Key_Up)&(!Get_Key_Down)&(!Get_Key_Left)&(!Get_Key_Right)&(!Get_Key_Ctrl) )
    11.   {
    12.     Key_Value=12000;
    13.   }
    14.   else
    15.   {
    16.     if(Get_Key_Up)    //按键前进按下 ,对应1kHz
    17.     {
    18.     Key_Value=6000;
    19.     }
    20.     else if(Get_Key_Down)  //按键后退按下 ,对应2kHz
    21.     {
    22.       Key_Value=3000;
    23.     }
    24.     Delay_Ms(20);      //10ms延时

    25.     if(Get_Key_Left)    //按键左转按下,对应3kHz
    26.     {
    27.     Key_Value=2000;
    28.     }
    29.     else if(Get_Key_Right) //按键右转按下,对应4kHz
    30.     {
    31.       Key_Value=1500;
    32.     }
    33.     Delay_Ms(20);      //10ms延时

    34.     if(Get_Key_Ctrl)    //按键控制按下,对应5kHz
    35.     {
    36.       Key_Value=1200;
    37.     }
    38.     Delay_Ms(20);      //10ms延时
    39.   }
    40. }
    41. }
    42. extern volatile u16 Key_Value;
    43. u16 capture=0;
    44. void TIM3_IRQHandler(void)
    45. {

    46. if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
    47. {
    48.     TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
    49. capture = TIM_GetCapture2(TIM3);
    50.     TIM_SetCompare2(TIM3, capture + Key_Value);
    51. }
    52. }
    53. void TIM3_Configuration(void)
    54. {
    55. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    56. TIM_OCInitTypeDef TIM_OCInitStructure;

    57. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    58. TIM_TimeBaseStructure.TIM_Prescaler = 5;      //预分频(时钟分频)72M/6=12M
    59. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
    60. TIM_TimeBaseStructure.TIM_Period = 65535;        //装载值选择最大
    61. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    62. TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;
    63. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);

    64. TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;      //PWM模式2
    65. TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //正向通道有效
    66. TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;//反向通道无效
    67. TIM_OCInitStructure.TIM_Pulse = Key_Value;        //占空时间
    68. TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;    //输出极性
    69. TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;    //互补端的极性
    70. TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    71. TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

    72. TIM_OC2Init(TIM3,&TIM_OCInitStructure);        //通道2
    73. TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);

    74. TIM_Cmd(TIM3,ENABLE);

    75. //TIM_CtrlPWMOutputs(TIM1,ENABLE);
    76. TIM_ITConfig(TIM3, TIM_IT_CC2 , ENABLE);
    77. }
    78. </span>
    复制代码

    转自:牛牛的博客
    回复

    使用道具 举报

    该用户从未签到

    23

    主题

    611

    帖子

    0

    蝴蝶豆

    高级会员

    最后登录
    2018-4-11
    发表于 2017-6-13 11:21:55 | 显示全部楼层
    谢谢  很好的总结!!!!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    47

    主题

    3456

    帖子

    30

    蝴蝶豆

    版主

    最后登录
    2022-12-25
    发表于 2017-6-13 15:29:57 | 显示全部楼层
    搬个板凳
    回复

    使用道具 举报

    该用户从未签到

    2

    主题

    4

    帖子

    0

    蝴蝶豆

    初级会员

    最后登录
    2020-12-4
    发表于 2017-6-19 08:51:24 | 显示全部楼层
    看懂这套路了,不过在cube生成的工程里面还未实现到。。囧
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

    GMT+8, 2024-4-29 07:31 , Processed in 1.183484 second(s), 37 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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