找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1087|回复: 0
打印 上一主题 下一主题
收起左侧

STM32F103单片机2通道输出相位任意配置的PWM输出程序

[复制链接]
跳转到指定楼层
楼主
ID:928738 发表于 2023-3-31 14:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
蓝桥杯竞赛的时候练习的程序,嵌入式竞赛的项目中定时器的一个难点,其实也挺简单的,主要是理解了就简单。里面的是一个keil4工程的代码,使用tim3实现同一个定时器输出任意占空比、任意相位差的pwm信号,里面有注释和原理分析,使用示波器验证过。有问题可以留言提问

单片机源程序如下:
  1. #include "stm32f10x.h"
  2. #include "lcd.h"
  3. /*
  4. 两路任意相位差、任意占空比的PWM信号实现
  5. */


  6. #define FRE 5000    //频率
  7. #define DUTY 40                        //占空比
  8. #define PHASE 180                //相位差
  9. u32 TimingDelay = 0;

  10. /*
  11. ccr1 高电平时间  ccr2 低电平时间
  12. cnt 频率对应的计数个数值
  13. deg 两个信号在CCR翻转的差值  这个差值体现相位差
  14. */

  15. u16 ccr1,ccr2;
  16. u16 cnt;
  17. u16 deg;

  18. void Delay_Ms(u32 nTime);
  19. void nvic_config(void);
  20. void tim3_init(void);
  21. void cal_prama(void);


  22. //Main Body
  23. int main(void)
  24. {
  25.                 SysTick_Config(SystemCoreClock/1000);//1ms
  26.                 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  27.                 cal_prama();
  28.                 nvic_config();
  29.                 tim3_init();
  30.                
  31.                 while(1);
  32. }
  33. //
  34. void Delay_Ms(u32 nTime)
  35. {
  36.                 TimingDelay = nTime;
  37.                 while(TimingDelay != 0);        
  38. }
  39. void tim3_init(void)
  40. {
  41.     TIM_TimeBaseInitTypeDef  TIM_TimeBaseInitStructure;
  42.                 TIM_OCInitTypeDef  TIM_OCInitStructure;
  43.                 GPIO_InitTypeDef  GPIO_InitStructure;
  44.         
  45.           TIM_DeInit(TIM3);
  46.                 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  47.           RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  48.         
  49.           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  50.           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  51.           GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  52.           GPIO_Init(GPIOA,&GPIO_InitStructure);
  53.         
  54.          TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;//1us
  55.    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  56.    TIM_TimeBaseInitStructure.TIM_Period         = 65535;//1us*65535 = 65.535ms
  57.    TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;
  58.    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
  59.    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);

  60.                  /*
  61.                 两个通道的CCR值初始为0,在第一次进入翻转的时候,改变两个通道的相位差。
  62.                 两个通道极性设置为一样。具体是什么电平有效取决于要求。改这里即可。
  63.                 TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Disable); 这个必须设置为DISABLE
  64.                 */
  65.                 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;//TIM3 CH1
  66.                 TIM_OCInitStructure.TIM_OutputState        = TIM_OutputState_Enable;
  67.                 TIM_OCInitStructure.TIM_Pulse = 0;   
  68.                 TIM_OCInitStructure.TIM_OCPolarity        = TIM_OCPolarity_High;
  69.                 TIM_OC1Init(TIM3,&TIM_OCInitStructure);
  70.                 TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Disable);
  71.                
  72.                 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;//TIM3 CH2
  73.                 TIM_OCInitStructure.TIM_OutputState        = TIM_OutputState_Enable;
  74.                 TIM_OCInitStructure.TIM_Pulse = 0;        
  75.                 TIM_OCInitStructure.TIM_OCPolarity        = TIM_OCPolarity_High;
  76.                 TIM_OC2Init(TIM3,&TIM_OCInitStructure);
  77.                 TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Disable);
  78.                
  79.                 TIM_ITConfig(TIM3,TIM_IT_CC1|TIM_IT_CC2, ENABLE);
  80.                 TIM_Cmd(TIM3,ENABLE);

  81. }
  82. void nvic_config(void)
  83. {
  84.                 NVIC_InitTypeDef NVIC_InitType;
  85.                 NVIC_InitType.NVIC_IRQChannel=TIM3_IRQn;
  86.                 NVIC_InitType.NVIC_IRQChannelCmd=ENABLE;
  87.                 NVIC_InitType.NVIC_IRQChannelPreemptionPriority=0x01;
  88.                 NVIC_InitType.NVIC_IRQChannelSubPriority=0x02;
  89.                 NVIC_Init(&NVIC_InitType);
  90. }
  91. void cal_prama(void)
  92. {
  93.                 cnt = 1000000/FRE;  //信号频率对应的计数个数
  94.                 ccr1 = (int)(cnt*DUTY/100.0); //高电平计数个数
  95.                 ccr2 = cnt-ccr1;     //低电平计数个数
  96.                 deg = cnt*(PHASE/360.0);   //设置到ccr上的差值,这个差值体现相位差
  97. }
  98. u16 out;
  99. void TIM3_IRQHandler(void)
  100. {
  101.                 static u8 num1=0,num2=2;
  102.                 if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
  103.                 {
  104.                                 TIM_ClearITPendingBit(TIM3, TIM_IT_CC1 );
  105.                                 out=TIM_GetCapture1(TIM3);
  106.                                 if(num1==0)
  107.                                 {
  108.                                                 num1=1;
  109.                                           TIM_SetCompare1(TIM3,out+ccr1);
  110.                                 }
  111.                                 else
  112.                                 {
  113.                                     num1=0;
  114.                                           TIM_SetCompare1(TIM3,out+ccr2);
  115.                                 }
  116.                 }
  117.                 if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
  118.                 {
  119.                                 TIM_ClearITPendingBit(TIM3, TIM_IT_CC2 );
  120.                                 out=TIM_GetCapture2(TIM3);
  121.                                 /*
  122.                                 只有在第一次的时候才需要加deg相位差值。
  123.                                 这个加了后两者的相位就已经改变了。
  124.                                 后面的部分不需要加deg,加了的话,频率就改变了
  125.                                 if(num2==0)
  126.                                 {
  127.                                         num2=1;
  128.                                         TIM_SetCompare2(TIM3,out+ccr1+deg);
  129.                                 }
  130.                                 else
  131.                                 {
  132.                                         num2=0;
  133.                                         TIM_SetCompare2(TIM3,out+ccr2+deg);
  134.                                 }
  135.                                 这时候频率就变为f=fcnt/(ccr1+ccr2+deg*2);
  136.                                 而我们信号的频率应该是f=fcnt/(ccr1+ccr2);
  137.                                 因此注意点:
  138.                                                  只有第一次设置CCR时需要加上deg值。这时相位就改变了
  139.                                                  后面设置的时候,跟通道1一样。 这样两个通道的频率和占空比就是一样的。
  140.                                                  这样设置后就可以产生:相位差不一样,占空比和频率一样的两路PWM信号了。
  141.                                                 
  142.                                                  这个ccr1和ccr2是代表高低电平持续时间的个数,也就是决定了频率和占空比,
  143.                                                  因此两路信号的设置的ccr1和ccr2应该一样。所以第一次设置要加上deg,后面设置
  144.                                                  跟另一通道一样,就不要加deg了,加了后频率就改变了。
  145.                                                 
  146.                                                 
  147.                                                  具体实现为下面代码:
  148.                                 */
  149.                                 if(num2==2)
  150.                                 {
  151.                                                 num2=1;
  152.                                                 TIM_SetCompare2(TIM3,out+ccr1+deg);
  153.                                 }
  154.                                  else if(num2==0)
  155.                                 {
  156.                                                 num2=1;
  157.                                                 TIM_SetCompare2(TIM3,out+ccr1);
  158.                                 }
  159.                                 else
  160.                                 {
  161.                                                 num2=0;
  162.                                                 TIM_SetCompare2(TIM3,out+ccr2);
  163.                                 }
  164.                         
  165.                         
  166.                 }


  167. }
复制代码

Keil代码下载(附件只有代码不含其他任何资料):
Keil程序.7z (183.98 KB, 下载次数: 32)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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