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

【经验分享】STM32F103单片机PWM单脉冲输出模式

[复制链接]
STMCU小助手 发布时间:2022-3-19 20:37
  通常输出PWM波形的时候是一直输出的。但是在电机控制中往往只需要输出一定个数的脉冲,不需要一直输出,那么这就需要每次输出PWM时,输出的脉冲个数可控。要实现这个功能,一般有三种方法。

  方法一:

  1. void TIM1_PWM_Init(u16 arr, u16 psc)
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure;
  4.     NVIC_InitTypeDef NVIC_InitStructure;

  5.     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  6.     TIM_OCInitTypeDef TIM_OCInitSturcture;

  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE);

  8.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  9.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  10.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  11.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  12.     NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
  13.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  14.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  15.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  16.     NVIC_Init(&NVIC_InitStructure);

  17.     TIM_TimeBaseInitStructure.TIM_Period = arr;
  18.     TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
  19.     TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  20.     TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  21.     TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;
  22.     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);

  23.     TIM_OCStructInit(& TIM_OCInitSturcture);

  24.     TIM_OCInitSturcture.TIM_OCMode = TIM_OCMode_PWM2;
  25.     TIM_OCInitSturcture.TIM_OutputState = TIM_OutputState_Enable;
  26.     TIM_OCInitSturcture.TIM_Pulse = 0;
  27.     TIM_OCInitSturcture.TIM_OCPolarity = TIM_OCPolarity_Low;
  28.     TIM_OC1Init(TIM1, &TIM_OCInitSturcture);

  29.     TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
  30.     TIM_CtrlPWMOutputs(TIM1, ENABLE);        //主输出使能
  31.     TIM_ARRPreloadConfig(TIM1, ENABLE);

  32.     TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
  33.     TIM_Cmd(TIM1, ENABLE);                                //使能计数器
  34.     TIM_SetCompare1(TIM1, arr / 2);
  35. }

  36. void TIM1_UP_IRQHandler(void)
  37. {
  38.     static  u16 y;
  39.     if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)
  40.     {
  41.         TIM_ClearITPendingBit(TIM1, TIM_IT_Update );
  42.         y++;
  43.         if(y > 60)                        //设置输出脉冲数
  44.         {
  45.             y = 0;
  46.             TIM_Cmd(TIM1, DISABLE);
  47.         }
  48.     }
  49. }
复制代码

  这个方法实现的原理最简单,就是开启PWM输出的更新中断功能,当计时器值重新加载一次时,就会产生一个中断,就代表输出了一个脉冲。这样每进一次中断,就统计一次中断次数,当中断的次数和需要的脉冲数相等时就关闭PWM的输出。这样也就实现了指定脉冲输出的功能。

  方法二:


  1. void PWMS8_Init(u32 Cycle, u32 PulseNum)
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure;
  4.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  5.     TIM_OCInitTypeDef  TIM_OCInitStructure;

  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);

  7.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);

  8.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  9.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  10.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  11.     GPIO_Init(GPIOC, &GPIO_InitStructure);

  12.     TIM_TimeBaseStructure.TIM_Period = Cycle;                        //频率
  13.     TIM_TimeBaseStructure.TIM_Prescaler = 71;                        //分频值  72M/(71+1) = 1M
  14.     TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  15.     TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
  16.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  17.     TIM_TimeBaseStructure.TIM_RepetitionCounter = PulseNum - 1;          //输出脉冲个数
  18.     TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);

  19.     TIM_GenerateEvent(TIM8, TIM_EventSource_Update);
  20.     TIM_InternalClockConfig(TIM8);
  21.     TIM_SelectOCxM(TIM8, TIM_Channel_2, TIM_OCMode_PWM2);

  22.     /* PWM1 Mode configuration: Channel2 */
  23.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
  24.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  25.     TIM_OCInitStructure.TIM_Pulse = Cycle / 2;                // 低电平时间  占空比
  26.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_Low;
  27.     TIM_OC2Init(TIM8, &TIM_OCInitStructure);        
  28.                
  29.     TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);
  30.     TIM_ARRPreloadConfig(TIM8, ENABLE);
  31.                
  32.     /* TIM8 enable counter */
  33.     TIM_CtrlPWMOutputs(TIM8, ENABLE);

  34.     TIM_SelectOnePulseMode(TIM8, TIM_OPMode_Single);
  35.     TIM_Cmd(TIM8, ENABLE);
  36. }
复制代码

  在方法一中是通过代码自己统计ARR的装载次数,而单片机内部也自带了这个功能,方法二中就直接使用这个系统自带的功能。这个功能就是重复计数器。

E`IP60)AW(N]6PV}OIW0]`N.png

1SI3F2WHR}Y3J8[I8KSBS.png
JSO@YR0$())Q_%B@XYZ$P67.png

  在初始化时将要输出的脉冲个数写入到重复计数器中,这样系统就会自动统计输出PWM的脉冲个数,当输出脉冲个数完成后就会自动停止PWM输出。

  方法三:

  1. /***********************TIM1初始化函数*************************/
  2. /****参数:****************************************************/
  3. /******u32 Cycle用于设定计数频率(计算公式:Cycle=1Mhz/目标频率)*/
  4. /****返回值:**************************************************/
  5. /******无*****************************************************/
  6. void TIM1_config(u32 Cycle)
  7. {
  8.     GPIO_InitTypeDef GPIO_InitStructure;
  9.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  10.     TIM_OCInitTypeDef  TIM_OCInitStructure;
  11.         
  12.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_TIM1 , ENABLE); //时钟使能

  13.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                   //TIM1_CH1 PA10
  14.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;             //复用推挽输出
  15.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  16.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  17.     TIM_TimeBaseStructure.TIM_Period = Cycle-1;                 //使用Cycle来控制频率(f=72/(71+1)/Cycle)  当Cycle为100时脉冲频率为10KHZ                           
  18.     TIM_TimeBaseStructure.TIM_Prescaler =71;         //设置用来作为TIMx时钟频率除数的预分频值                                                     
  19.     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //设置时钟分割:TDTS= Tck_tim            
  20.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
  21.     TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;            //重复计数,一定要=0!!!(高级定时器特有)
  22.     TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);                                       

  23.     TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;                          //选择定时器模式:TIM脉冲宽度调制模式2     
  24.     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;         //比较输出使能
  25.     TIM_OCInitStructure.TIM_Pulse = Cycle/2-1;                            //设置待装入捕获寄存器的脉冲值(占空比:默认50%,这可也可以调节如果需要的话将它作为一个参数传入即可)                                   
  26.     TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;              //输出极性      

  27.     TIM_OC3Init(TIM1, &TIM_OCInitStructure);                                               //使能通道1                                             

  28.     TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);        //设置为主从模式
  29.     TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);                        //选择定时器1的触发方式(使用更新事件作为触发输出)


  30.     TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);               //使能通道1预装载寄存器               
  31.     TIM_ARRPreloadConfig(TIM1, ENABLE);                             //使能TIM1在ARR上的预装载寄存器      
  32. }
  33. /***********************TIM2初始化函数*************************/
  34. /****参数:****************************************************/
  35. /******u32 PulseNum用于设定脉冲数量****************************/
  36. /****返回值:*************************************************/
  37. /******无*****************************************************/
  38. void TIM2_config(u32 PulseNum)
  39. {
  40.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  41.     NVIC_InitTypeDef NVIC_InitStructure;
  42.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);                //使能定时器2的时钟

  43.     TIM_TimeBaseStructure.TIM_Period = PulseNum;                           //脉冲数
  44.     TIM_TimeBaseStructure.TIM_Prescaler =0;   
  45.     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     
  46.     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
  47.     TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  

  48.     TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0);        //选择定时器2的输入触发源(内部触发(TIM1))

  49.     TIM2->SMCR|=0x07;                    //设置从模式寄存器(SMS[2:0]:111 外部时钟模式1)

  50.     TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE);                //更新中断失能

  51.     NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;        
  52.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  53.     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;     
  54.     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  55.     NVIC_Init(&NVIC_InitStructure);                                                                //定时器2中断初始化
  56. }
  57. /************************脉冲输出函数**************************/
  58. /****参数:****************************************************/
  59. /******u32 Cycle用于设定计数频率(计算公式:Cycle=1Mhz/目标频率)*/
  60. /******u32 PulseNum用于设定输出脉冲的数量(单位:个)************/
  61. /****返回值:**************************************************/
  62. /******无*****************************************************/
  63. void Pulse_output(u32 Cycle,u32 PulseNum)
  64. {
  65.     TIM2_config(PulseNum);                                                //设置脉冲数量
  66.     TIM_Cmd(TIM2, ENABLE);                                                //使能TIM2(从定时器)
  67.     TIM_ClearITPendingBit(TIM2,TIM_IT_Update);        //清除中断标志位
  68.     TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);        //使能更新中断
  69.     TIM1_config(Cycle);                                                        //使能定时器1(主定时器)

  70.     TIM_Cmd(TIM1, ENABLE);                                                //使能定时器1
  71.     TIM_CtrlPWMOutputs(TIM1, ENABLE);                   //高级定时器一定要加上,主输出使能
  72. }

  73. /********************定时器2的中断服务函数**********************/
  74. /****参数:****************************************************/
  75. /******u32 PulseNum用于设定脉冲数量****************************/
  76. /****返回值:*************************************************/
  77. /******无*****************************************************/
  78. /****函数说明:************************************************/
  79. /*当TIM的CNT寄存器的值到达设定的Update值会触发更新中断,此时设定的脉冲数已输出完毕,关闭TIM1和TIM2*/
  80. void TIM2_IRQHandler(void)
  81. {
  82.     if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)         //TIM_IT_Update
  83.     {
  84.         TIM_ClearITPendingBit(TIM2, TIM_IT_Update);          // 清除中断标志位
  85.         TIM_CtrlPWMOutputs(TIM1, DISABLE);                                     //主输出失能
  86.         TIM_Cmd(TIM1, DISABLE);                                                            //关闭定时器
  87.         TIM_Cmd(TIM2, DISABLE);                                                           //关闭定时器
  88.         TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);         //关闭TIM2更新中断

  89.     }
  90. }
复制代码

  方法三使用了系统自带的定时器同步功能,也就是定时器1输出PWM波,然后将定时器1的输出同步到定时器2上,然后通过定时器2的计数器给定时器1输出的脉冲计数,当计数值等于指定值时,关闭定时器1的输出。

O[K[E874Z(Q3$%MM4@@LKV5.png

M5SVPO4K]KG3Z`EXGJVKV.png

  定时器1设置为主模式,定时器2设置为从模式。将定时器1的PWM输出作为定时器2的时钟。这样设置定时器2的频率值,也就相当于设置的是定时器1的脉冲输出个数。

  将这三种模式统一在主函数中进行测试。


  1. int main(void)
  2. {   
  3.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  4.     delay_init();        
  5.     while(1)
  6.     {                        
  7.       //调用一次 发一次脉冲
  8.       //TIM1_PWM_Init(899,0);                        //方法一
  9.       Pulse_output(100,16);                        //方法二               
  10.       //PWMS8_Init(1000,6);                     //方法三        
  11.       delay_ms(500);
  12.     }
  13. }
复制代码

在主函数中分别调用这三种方法,然后通过示波器就可以看出,当PWM输出一定的脉冲数后就会停止输出。



收藏 评论0 发布时间:2022-3-19 20:37

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版