【stm32】TIM定时器输出比较-PWM驱动LED呼吸灯/舵机/直流电机 ...

打印 上一主题 下一主题

主题 822|帖子 822|积分 2466

一、输出比较简介

1、OC(Output Compare)输出比较



  • 输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平举行置1、置0或翻转的操作,用于输出肯定频率和占空比的PWM波形
  • 每个高级定时器和通用定时器都拥有4个输出比较通道
  • 高级定时器的前3个通道额外拥有死区生成和互补输出的功能
2、PWM简介



  • PWM(Pulse Width Modulation)脉冲宽度调制
  • 在具有惯性的体系中,可以通过对一系列脉冲的宽度举行调制,来等效地获得所需要的模拟参量,常应用于电机控速等范畴
  • PWM参数:
    频率 = 1 / T(S)
    占空比 = T(ON) / T(S)
    分辨率 = 占空比变化步距

    占空比决定了PWM等效出来的模拟电压的巨细,占空比越大,等效的模拟电压就越趋近于高电平
   如:此时高电平是5V,低电平是0V,50%占空比就等效于中间电压2.5V,20%占空比就等效于1/5处的电压1V
  3、输出比较通道(高级)


4、输出比较通道(通用)

CCR(Capture Compare Register):捕获比较寄存器

                                                 \quad                  左边是CNT计数器和CCR1第一路的捕获/比较寄存器,这两者之间举行比较,当CNT>CCR1,大概CNT=CCR1时,就会给输出模式控制器传一个信号,然后输出模式控制器就会改变它输出OC1REF的高低电平, REF信号现实上就是指图上oc1ref信号的高低电平,ETRF输入,是定时器的一个小功能(不需了解),此时高低电平输出到极性选择上(主模式控制器较少使用),给CC1P寄存器写0,信号走上面那路,就是信号电平不翻转,写1的话,信号走下面那路,信号通过一个非门取反,输出的信号就是输入信号高低电昭雪转的信号,这就是极性选择,即选择是否要把高低电昭雪转,接着走到输出使能电路,选择要不要输出,末了就是OC1引脚,这个引脚就是CH1通道的引脚。
5、输出比较模式


   解释上图:
冻结即PWM暂停输出,有效电平即高电平,无效电平即低电平
PWM模式2和PWM模式1的区别在于比较值相同时,REF的高低电平相反,由此可以看出PWM模式2现实上就是PWM模式1输出的取反,改变PWM模式1和PWM模式2,就是改变REF电平的极性
  6、PWM根本布局


   蓝线为CNT值,黄线ARR值,红线为CCR值
占空比受CCR值调控, CCR值越大,占空比越大,反之输出的占空比越小
上图的REF是一个频率可调,占空比也可调的PWM波形
  配置好时基单位后CNT自增运行,CCR由程序员自行设定,当CNT在自增运行时,CNT与CCR不断举行比较
配置步调:

1、RCC开启时钟,打开TIM外设和GPIO外设的时钟;
2、配置时基单位,包罗时钟源选择;
3、配置输出比较单位,包罗CCR的值、输出比较模式、极性选择、输出使能等参数;
4、配置GPIO,把PWM对应的GPIO口,初始化为复用推挽输出的配置;
5、运行控制,启动计数器,输出PWIM。



配置PWM的GPIO口时需使用复用推挽输出,原因是:
                                                 \quad                  对于普通的开漏/推挽输出,引脚的控制权是来自于输出数据寄存器(如下图1),假如想让定时器来控制引脚,就需要使用复用开漏/推挽输出的模式,在这里输出数据寄存器将被断开(如下图2),输出控制权将转移给片上外设,通过引脚定义表可知,这里片上外设引脚毗连的是TIM2的CH1通道,所以只有把GPIO设置成复用推挽输出,引脚的控制权才能交给片上外设,PWM波形才能通过引脚输出。
图1:

图2:

要得到一个1KHZ,占空比50%,分辨率为1%的波形,盘算如下:

程序代码:PWM驱动LED呼吸灯

  1. // pwm.c
  2. #include "stm32f10x.h"                  // Device header
  3. void PWM_Init(void)
  4. {
  5.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  7.    
  8.    
  9.     GPIO_InitTypeDef GPIO_InitStructure;
  10.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;        //GPIO_Pin_15;
  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  14.    
  15.     TIM_InternalClockConfig(TIM2);
  16.    
  17.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  18.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  19.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  20.     TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;        // ARR
  21.     TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;    //PSC
  22.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  23.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
  24.    
  25.     TIM_OCInitTypeDef TIM_OCInitStructure;
  26.     TIM_OCStructInit(&TIM_OCInitStructure); // 给TIM_OCInitStructure结构体赋初始值,不使用的参数就可不配置
  27.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  // 设置输出比较的模式   
  28.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 设置输出比较的极性
  29.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  // 设置输出使能
  30.     TIM_OCInitStructure.TIM_Pulse = 0;        // 设置CCR初始值(若使用TIM_SetCompare1函数设置了CCR寄存器的值时,此参数可不设置)
  31.     TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  32.    
  33.     TIM_Cmd(TIM2, ENABLE);
  34. }
  35. void PWM_SetCompare1(uint16_t Compare)
  36. {
  37.     TIM_SetCompare1(TIM2, Compare);
  38. }
  39. // main.c
  40. #include "stm32f10x.h"                  // Device header
  41. #include "Delay.h"
  42. #include "OLED.h"
  43. #include "PWM.h"
  44. uint8_t i;
  45. int main(void)
  46. {
  47.     OLED_Init();
  48.     PWM_Init();
  49.    
  50.     while (1)
  51.     {
  52.         for (i = 0; i <= 100; i++)
  53.         {
  54.             PWM_SetCompare1(i); // 这里设置的是CCR寄存器的值,占空比是由CCR和ARR共同决定的
  55.             Delay_ms(10);
  56.         }
  57.         for (i = 0; i <= 100; i++)
  58.         {
  59.             PWM_SetCompare1(100 - i);
  60.             Delay_ms(10);
  61.         }
  62.     }
  63. }
复制代码
7、参数盘算




  • PWM频率(计数器更新频率公式): Freq = CK_PSC / (PSC + 1) / (ARR + 1)
    上图可以看出,PWM的一个周期对应着计数器的一个溢出更新周期,所以PWM的频率就等于计数器的更新频率
  • PWM占空比: Duty = CCR / (ARR + 1)
    30/(99+1) = 30%
  • PWM分辨率: Reso = 1 / (ARR + 1)

    • CCR 的值范围是在0到ARR的值范围内,所以CCR的变化范围取决于ARR的值,ARR越大,CCR的范围就越大,对应的分辨率就越大。
    • 上面公式定义的分辨率是占空比最小的变化步距,使用的是ARR的值,ARR值越大,分辨率越小,占空比变化越精致。

8、舵机简介



  • 舵机是一种根据输入PWM信号占空比来控制输出角度的装置
  • 输入PWM信号要求:周期为20ms,高电平宽度为0.5ms~2.5ms
周期为20ms,频率:1/20ms = 50HZ

硬件电路:


同一个定时器差别通道输出PWM的特点:
                                                 \quad                  若想要同肯定时器的多通道输出PWM,使用对应通道的函数即可,需要注意的是,对于同一个定时器的差别通道输出的PWM,由于差别通道共用一个计数器,所以这几个通道的频率必须是一样的;这几个通道的占空比由各自的CCR决定,可自行设定;还由于计数器更新,全部PWM同时跳变,所以这几个通道的相位是同步的

程序代码:PWM驱动舵机

  1. // PWM驱动舵机
  2. // pwm.c
  3. #include "stm32f10x.h"                  // Device header
  4. void PWM_Init(void)
  5. {
  6.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  8.    
  9.     GPIO_InitTypeDef GPIO_InitStructure;
  10.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.     GPIO_Init(GPIOA, &GPIO_InitStructure);  // PA1对应TIM2通道2
  14.    
  15.     TIM_InternalClockConfig(TIM2);
  16.    
  17.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  18.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  19.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  20.     TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;        //ARR
  21.     TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;        //PSC
  22.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  23.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
  24.    
  25.     TIM_OCInitTypeDef TIM_OCInitStructure;
  26.     TIM_OCStructInit(&TIM_OCInitStructure);
  27.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  28.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  29.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  30.     TIM_OCInitStructure.TIM_Pulse = 0;        //CCR
  31.     TIM_OC2Init(TIM2, &TIM_OCInitStructure);  // 初始化通道2
  32.    
  33.     TIM_Cmd(TIM2, ENABLE);
  34. }
  35. void PWM_SetCompare2(uint16_t Compare)
  36. {
  37.     TIM_SetCompare2(TIM2, Compare);
  38. }
  39. // Servo.c  舵机模块
  40. #include "stm32f10x.h"                  // Device header
  41. #include "PWM.h"
  42. void Servo_Init(void)
  43. {
  44.     PWM_Init();
  45. }
  46. void Servo_SetAngle(float Angle)
  47. {
  48.     PWM_SetCompare2(Angle / 180 * 2000 + 500);
  49. }
  50. // main.c
  51. // 按下按键,舵机每次加30°,超180°后重新置0°
  52. #include "stm32f10x.h"                  // Device header
  53. #include "Delay.h"
  54. #include "OLED.h"
  55. #include "Servo.h"
  56. #include "Key.h"
  57. uint8_t KeyNum;
  58. float Angle;
  59. int main(void)
  60. {
  61.     OLED_Init();
  62.     Servo_Init();
  63.     Key_Init();
  64.    
  65.     OLED_ShowString(1, 1, "Angle:");
  66.    
  67.     while (1)
  68.     {
  69.         KeyNum = Key_GetNum();
  70.         if (KeyNum == 1)
  71.         {
  72.             Angle += 30;
  73.             if (Angle > 180)
  74.             {
  75.                 Angle = 0;
  76.             }
  77.         }
  78.         Servo_SetAngle(Angle);
  79.         OLED_ShowNum(1, 7, Angle, 3);
  80.     }
  81. }
复制代码
9、直流电机及驱动简介



  • 直流电机是一种将电能转换为机器能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转
  • 直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作
  • TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向

    硬件电路:


程序代码:PWM驱动直流电机

  1. // PWM驱动直流电机
  2. // motor.c
  3. #include "stm32f10x.h"                  // Device header
  4. #include "PWM.h"
  5. void Motor_Init(void)
  6. {
  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  8.    
  9.     GPIO_InitTypeDef GPIO_InitStructure;
  10.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  11.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
  12.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  14.    
  15.     PWM_Init();
  16. }
  17. void Motor_SetSpeed(int8_t Speed)
  18. {
  19.     if (Speed >= 0)  // 正转
  20.     {
  21.         GPIO_SetBits(GPIOA, GPIO_Pin_4);
  22.         GPIO_ResetBits(GPIOA, GPIO_Pin_5);
  23.         PWM_SetCompare3(Speed);
  24.     }
  25.     else   // 反转
  26.     {
  27.         GPIO_ResetBits(GPIOA, GPIO_Pin_4);
  28.         GPIO_SetBits(GPIOA, GPIO_Pin_5);
  29.         PWM_SetCompare3(-Speed);
  30.     }
  31. }
  32. // pwm.c
  33. #include "stm32f10x.h"                  // Device header
  34. void PWM_Init(void)
  35. {
  36.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  37.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  38.    
  39.     GPIO_InitTypeDef GPIO_InitStructure;
  40.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  41.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  42.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  43.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  44.    
  45.     TIM_InternalClockConfig(TIM2);
  46.    
  47.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  48.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  49.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  50.     TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;        //ARR
  51.     TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;        //PSC
  52.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  53.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
  54.    
  55.     TIM_OCInitTypeDef TIM_OCInitStructure;
  56.     TIM_OCStructInit(&TIM_OCInitStructure);
  57.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  58.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  59.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  60.     TIM_OCInitStructure.TIM_Pulse = 0;        //CCR
  61.     TIM_OC3Init(TIM2, &TIM_OCInitStructure);
  62.    
  63.     TIM_Cmd(TIM2, ENABLE);
  64. }
  65. void PWM_SetCompare3(uint16_t Compare)
  66. {
  67.     TIM_SetCompare3(TIM2, Compare);
  68. }
  69. // main.c
  70. #include "stm32f10x.h"                  // Device header
  71. #include "Delay.h"
  72. #include "OLED.h"
  73. #include "Motor.h"
  74. #include "Key.h"
  75. uint8_t KeyNum;
  76. int8_t Speed;
  77. int main(void)
  78. {
  79.     OLED_Init();
  80.     Motor_Init();
  81.     Key_Init();
  82.    
  83.     OLED_ShowString(1, 1, "Speed:");
  84.    
  85.     while (1)
  86.     {
  87.         KeyNum = Key_GetNum();
  88.         if (KeyNum == 1)
  89.         {
  90.             Speed += 20;
  91.             if (Speed > 100)
  92.             {
  93.                 Speed = -100;
  94.             }
  95.         }
  96.         Motor_SetSpeed(Speed);
  97.         OLED_ShowSignedNum(1, 7, Speed, 3);
  98.     }
  99. }
复制代码
附加:引脚重映射


把TIM2的CH1从PA0重映射到PA15引脚,使用AFIO
使用的函数:

查数据手册:重映射方式和引脚对应关系,把PA0改到PA15,可以选择部门重映射方式1大概完全重映射

配置参数选择:

注意:使用引脚重映射时要注意引脚默认复用的是普通GPIO口照旧调试端口,若是调试端口需先关闭调试端口的复用
                                                 \quad                  PA15上电后默认复用为调试端口JTDI,假如要让PA15作为普通的GPIO大概复用定时器的通道,需要先关闭调试端口的复用,使用GPIO_PinRemapConfig函数举行关闭,参照下表

  1. 1、把PA15,PB3,PB4当作普通IO使用需配置的
  2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 开启AFIO RCC时钟
  3. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 解除JTAG的使用(PA15,PB3,PB4),,保留SWD的使用
  4. 2、重映射定时器或者其他外设的复用引脚需配置的(重映射引脚默认复用端口不是调试端口的情况)
  5. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 开启AFIO RCC时钟
  6. GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); // 配置重映射引脚(对照数据手册),选择部分重映射1
  7. 3、重映射定时器或者其他外设的复用引脚需配置的(重映射引脚是调试端口的情况)
  8. RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 开启AFIO RCC时钟
  9. GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE); // 配置重映射引脚(对照数据手册),选择部分重映射1
  10. GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 解除JTAG的使用(PA15,PB3,PB4),,保留SWD的使用
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

南飓风

金牌会员
这个人很懒什么都没写!

标签云

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