OpenEdv-开源电子网

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

最详细的SPWM产生方法

[复制链接]

1

主题

3

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2017-5-20
在线时间
0 小时
发表于 2017-5-29 15:08:35 | 显示全部楼层 |阅读模式
1金钱
        淘来的绝对详细的SPWM产生方法,分享给大家。哪位大哥发出了波形上传看看,小弟对于这个文档的一些细节配置不太清楚。

经典STM32产生SPWM.pdf

433.76 KB, 下载次数: 1611

最佳答案

查看完整内容[请看2#楼]

谢谢分享,不过建议发分享贴。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2017-5-29 15:08:36 | 显示全部楼层
谢谢分享,不过建议发分享贴。
回复

使用道具 举报

15

主题

83

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
211
金钱
211
注册时间
2016-9-27
在线时间
42 小时
发表于 2017-5-29 17:10:19 | 显示全部楼层
Mark。。
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2017-5-20
在线时间
0 小时
 楼主| 发表于 2017-5-29 20:01:43 | 显示全部楼层
原子哥,我按照文档里的内容在高级定时器内设置通道1,通道2。利用通道2每次向下计数溢出时将正弦表数据赋给通道1比较寄存器,可是波形出不来啊,感觉向下溢出这方面配置有点错误。
#include "pwm.h"
#include "stm32f10x_tim.h"
extern uint16_t NUM;
extern uint16_t SPWM[];
extern uint16_t i;
//PWMêä3ö3õê¼»ˉ
//arr£o×Ô¶ˉ֨װÖμ
//psc£oê±ÖóÔ¤·ÖÆμêy

void TIM1_PWM_Init(u16 arr,u16 psc)
{  
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
        //GPIOê±Öóê1Äü
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);  //ê1ÄüGPIOíaéèê±Öóê1Äü
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
       
        //éèÖøÃòy½ÅÎa¸′óÃêä3ö1|Äü,êä3öTIM1 CH1,CH2μ&#196WMÂö3å2¨DÎ
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; //TIM1-CH1/CH2
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //¸′óÃíÆíìêä3ö
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
       
        //éèÖøÃòy½ÅÎa¸′óÃêä3ö1|Äü,êä3öTIM1 CH1,CH2μ&#196WMÂö3å2¨DÎ
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14; //TIM1-CH1/CH2μÄêä3ö»¥21í¨μà¡£
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //¸′óÃíÆíìêä3ö
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);   
       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
        NVIC_InitStructure.NVIC_IRQChannel =TIM1_CC_IRQn;  //TIM1ÖD¶Ï
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //ÏèÕ¼óÅÏè¼¶0¼¶
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //′óóÅÏè¼¶3¼¶
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQí¨μà±»ê1Äü
        NVIC_Init(&NVIC_InitStructure);  //¸ù¾YNVIC_InitStructÖDÖ¸¶¨μÄ2Îêy3õê¼»ˉíaéèNVIC¼Ä′æÆ÷
       
        TIM_DeInit(TIM1);
        //TIMx¶¨ê±Æ÷3õê¼»ˉ
        TIM_TimeBaseStructure.TIM_Period = arr; //èçéèÖÃarr=999£¬μ±¶¨ê±Æ÷′ó0¼Æêyμ½999£¬ò»121000′Σ¬Îaò»¸ö¶¨ê±ÖüÆú¡£
        TIM_TimeBaseStructure.TIM_Prescaler =psc; //éèÖÃÔ¤·ÖÆμÖμ£¬Ö¸μÄêÇ′óAPB2×üÏ߯μÂêμ½Ïàó|μĶ¨ê±Æ÷TIMxμÄ·ÖÆμÏμêy¡£
        TIM_TimeBaseStructure.TIM_ClockDivision =0; //éèÖÃê±Öó·ÖÆμÏμêy¡£Ö¸μÄêÇTIMx¶¨ê±Æ÷ê±Öóμ½Ïàó|μÄTIMx_CNT¶¨ê±Æ÷¼ÆêyÆ÷μÄ·ÖÆμÏμêy¡£
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//¸üDÂÕ¼¿Õ±è
        TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_CenterAligned1;  //TIMÖDÑë¶ÔÆëÄ£ê½1
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //¸ù¾YTIM_TimeBaseInitStructÖDÖ¸¶¨μÄ2Îêy3õê¼»ˉTIMxμÄê±¼ä»ùêyμ¥λ
        TIM_ClearFlag(TIM1,TIM_FLAG_CC2);
  TIM_ITConfig(TIM1,TIM_IT_CC2,ENABLE);

       
         
        /*--------------------------------------------------------------------------------------------------------------------------------*/
  //TIM1--CH1êä3öí¨μàPWMÄ£ê½ÅäÖã¨í¨óÃêä3öí¨μàPWMÄ£ê½ÅäÖã©
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //Ñ¡Ôñ¶¨ê±Æ÷Ä£ê½:TIMÂö3å¿í¶èμ÷ÖÆÄ£ê½2
       
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //±è½Ïêä3öê1Äü
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //±è½Ïêä3öê1Äü
        TIM_OCInitStructure.TIM_Pulse =0; //éèÖÃìø±äÖμ£¬μ±¼ÆêyÆ÷¼Æêyμ½Õa¸öÖ죬μçÆ½·¢éúìø±ä
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //μ±¶¨ê±Æ÷ÖμD¡óúéÏÃæËùéèÖÃμÄTIM_PulseÖμê±£&#172WMêä3ö¸ßμçÆ½(衾öóúTIMμļÆêyÄ£ê½)
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
        TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset;
        TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCIdleState_Reset;
        //ê1ÄüTIMxêä3öí¨μà1 PWMģ꽣¨±ØDëê1ÄüÏàó|μÄÖØ×°ÔØ¼Ä′æÆ÷TIMx_CCRx£©

        TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //¸ù¾YTIM_OCInitStructÖDÖ¸¶¨μÄ2Îêy3õê¼»ˉíaéèTIMx
  TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH1Ô¤×°ÔØê1Äü         
        //TIM1->DIER=0X01<<1;
       
  //TIM1--CH2ê&#228;3&#246;í¨μàPWM&#196;£ê&#189;&#197;&#228;&#214;&#195;£¨í¨ó&#195;ê&#228;3&#246;í¨μàPWM&#196;£ê&#189;&#197;&#228;&#214;&#195;£&#169;
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //&#209;&#161;&#212;&#241;&#182;¨ê±&#198;÷&#196;£ê&#189;:TIM&#194;&#246;3&#229;&#191;í&#182;èμ÷&#214;&#198;&#196;£ê&#189;2
       
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //±è&#189;&#207;ê&#228;3&#246;ê1&#196;ü
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //±è&#189;&#207;ê&#228;3&#246;ê1&#196;ü
        TIM_OCInitStructure.TIM_Pulse =0; //éè&#214;&#195;ì&#248;±&#228;&#214;μ£&#172;μ±&#188;&#198;êy&#198;÷&#188;&#198;êyμ&#189;&#213;a&#184;&#246;&#214;μ£&#172;μ&#231;&#198;&#189;·¢éúì&#248;±&#228;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //μ±&#182;¨ê±&#198;÷&#214;μD&#161;óúé&#207;&#195;&#230;&#203;ùéè&#214;&#195;μ&#196;TIM_Pulse&#214;μê±£&#172WMê&#228;3&#246;&#184;&#223;μ&#231;&#198;&#189;(è&#161;&#190;&#246;óúTIMμ&#196;&#188;&#198;êy&#196;£ê&#189;)
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
        TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset;
        TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCIdleState_Reset;
        //ê1&#196;üTIMxê&#228;3&#246;í¨μà1 PWM&#196;£ê&#189;£¨±&#216;D&#235;ê1&#196;ü&#207;àó|μ&#196;&#214;&#216;×°&#212;&#216;&#188;&#196;′&#230;&#198;÷TIMx_CCRx£&#169;

        TIM_OC2Init(TIM1, &TIM_OCInitStructure);  //&#184;ù&#190;YTIM_OCInitStruct&#214;D&#214;&#184;&#182;¨μ&#196;2&#206;êy3&#245;ê&#188;&#187;ˉíaéèTIMx
  TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH2&#212;¤×°&#212;&#216;ê1&#196;ü       
        //TIM1->DIER=0X01<<2;
       
        /*---------------------------------------------------------------------------------------------------------------------------------*/
       
        TIM_CtrlPWMOutputs(TIM1, ENABLE);   
        TIM_ARRPreloadConfig(TIM1, ENABLE); //ê1&#196;üTIMx&#212;úARRé&#207;μ&#196;&#212;¤×°&#212;&#216;&#188;&#196;′&#230;&#198;÷
        TIM_Cmd(TIM1, ENABLE);  //ê1&#196;üTIM1  
}


void TIM1_CC_IRQHandler(void)   //TIM3&#214;D&#182;&#207;
{
       
        if (TIM_GetITStatus(TIM1,TIM_IT_CC2) != RESET) //&#188;ì2é&#214;&#184;&#182;¨μ&#196;TIM&#214;D&#182;&#207;·¢éúó&#235;·&#241;:TIM &#214;D&#182;&#207;&#212;′
                {
                          
                                TIM1->CCR1=SPWM[i++];
                                  if(i>=NUM)
                        {
                                 i=0;
                         }
   
                            
                }
                TIM_ClearITPendingBit(TIM1,TIM_IT_CC2); //&#199;&#229;3yTIMxμ&#196;&#214;D&#182;&#207;′y′|àí&#206;&#187;:TIM &#214;D&#182;&#207;&#212;′
               
}
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2017-5-20
在线时间
0 小时
 楼主| 发表于 2017-5-29 20:07:20 | 显示全部楼层
重新上传一遍
#include "pwm.h"
#include "stm32f10x_tim.h"
extern uint16_t NUM;
extern uint16_t SPWM[];
extern uint16_t i;

void TIM1_PWM_Init(u16 arr,u16 psc)
{  
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);  
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
       
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);   
       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
        NVIC_InitStructure.NVIC_IRQChannel =TIM1_CC_IRQn;  
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
       
        TIM_DeInit(TIM1);
        TIM_TimeBaseStructure.TIM_Period = arr;
        TIM_TimeBaseStructure.TIM_Prescaler =psc;
        TIM_TimeBaseStructure.TIM_ClockDivision =0;
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
        TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_CenterAligned1;
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
        TIM_ClearFlag(TIM1,TIM_FLAG_CC2);
      TIM_ITConfig(TIM1,TIM_IT_CC2,ENABLE);

        /*--------------------------------------------------------------------------------------------------------------------------------*/
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
       
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
        TIM_OCInitStructure.TIM_Pulse =0;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
        TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset;
        TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCIdleState_Reset;

        TIM_OC1Init(TIM1, &TIM_OCInitStructure);  
  TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

       

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
       
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
        TIM_OCInitStructure.TIM_Pulse =0;
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
        TIM_OCInitStructure.TIM_OCIdleState=TIM_OCIdleState_Reset;
        TIM_OCInitStructure.TIM_OCNIdleState=TIM_OCIdleState_Reset;
       

        TIM_OC2Init(TIM1, &TIM_OCInitStructure);  
  TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);  
       
        /*---------------------------------------------------------------------------------------------------------------------------------*/
       
        TIM_CtrlPWMOutputs(TIM1, ENABLE);   
        TIM_ARRPreloadConfig(TIM1, ENABLE);
        TIM_Cmd(TIM1, ENABLE);
}


void TIM1_CC_IRQHandler(void)
{
       
        if (TIM_GetITStatus(TIM1,TIM_IT_CC2) != RESET)
                {
                          
                                TIM1->CCR1=SPWM[i++];
                                  if(i>=NUM)
                        {
                                 i=0;
                         }
   
                            
                }
                TIM_ClearITPendingBit(TIM1,TIM_IT_CC2);
               
}
回复

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
47
金钱
47
注册时间
2017-5-28
在线时间
12 小时
发表于 2017-5-29 23:22:37 来自手机 | 显示全部楼层
我最近也在写spwm有机会可以交流学习我微信ZC138285
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
2
金钱
2
注册时间
2017-7-15
在线时间
0 小时
发表于 2017-7-15 08:30:54 | 显示全部楼层
谢谢楼主分享
回复

使用道具 举报

5

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2017-7-6
在线时间
35 小时
发表于 2017-7-24 09:36:50 | 显示全部楼层
幻影觉123 发表于 2017-5-29 20:07
重新上传一遍
#include "pwm.h"
#include "stm32f10x_tim.h"

我也是按照文档里自己写的,和你的一模一样,但是也没有出结果,不知道你现在调出来没有
回复

使用道具 举报

7

主题

72

帖子

0

精华

高级会员

Rank: 4

积分
620
金钱
620
注册时间
2016-10-20
在线时间
74 小时
发表于 2017-8-4 21:19:39 | 显示全部楼层
STM32 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输出型的DAC。DAC 可以配置为 8 位或 12 位模式,   
请问   那个12位数字输入  是什么意思?     8位或12位模式又是???
回复

使用道具 举报

9

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2018-7-14
在线时间
17 小时
发表于 2018-7-23 22:03:31 | 显示全部楼层
谢谢分享
回复

使用道具 举报

1

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
123
金钱
123
注册时间
2019-2-27
在线时间
23 小时
发表于 2019-5-17 21:16:42 | 显示全部楼层
幻影觉123 发表于 2017-5-29 20:07
**** 作者被禁止或删除 内容自动屏蔽 ****

你TIM1定时器,又写spwm又写中断,系统默认最后一个,前面写的都会被覆盖,你可以考虑用两个定时器分别写
回复

使用道具 举报

1

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
92
金钱
92
注册时间
2019-4-11
在线时间
16 小时
发表于 2019-5-20 21:03:08 | 显示全部楼层
谢谢分享
回复

使用道具 举报

4

主题

98

帖子

0

精华

初级会员

Rank: 2

积分
195
金钱
195
注册时间
2018-6-27
在线时间
45 小时
发表于 2019-7-4 13:23:43 | 显示全部楼层
谢谢分享
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
14
金钱
14
注册时间
2019-7-6
在线时间
4 小时
发表于 2019-7-12 18:55:24 | 显示全部楼层
文档正弦规律变化推到的时候是不是错了呀,数学功底不是很好,求解!
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2019-7-8
在线时间
3 小时
发表于 2019-7-13 21:02:40 | 显示全部楼层
感谢楼主,我按照你发的这个PDF结合网上的一个程序好像写出了基于规则采样法的SPWM程序,不过我是用另一个定时器计时到来改变TIM1的CCRx
C:\Users\Administrator\Desktop\IMG20190710144651
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2019-7-8
在线时间
3 小时
发表于 2019-7-13 21:06:58 | 显示全部楼层
图中那些看上去不一样高的方波,在移动到示波器中央时是一样高的
QQ图片20190713210357.jpg
QQ图片20190713210332.jpg
IMG20190710144651.jpg
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2019-7-8
在线时间
3 小时
发表于 2019-7-13 21:19:04 | 显示全部楼层
#include "spwm.h"
#include "stm32f10x.h"


uint16_t spwm[100] = {
0x4000,0x4405,0x4805,0x4BFE,0x4FEA,0x53C7,0x578F,0x5B40,0x5ED5,0x624A,
0x659E,0x68CB,0x6BCF,0x6EA7,0x714F,0x73C6,0x7609,0x7815,0x79E8,0x7B81,
0x7CDD,0x7DFC,0x7EDD,0x7F7E,0x7FDF,0x7FFF,0x7FDF,0x7F7E,0x7EDD,0x7DFC,
0x7CDD,0x7B81,0x79E8,0x7815,0x7609,0x73C6,0x714F,0x6EA7,0x6BCF,0x68CB,
0x659E,0x624A,0x5ED5,0x5B40,0x578F,0x53C7,0x4FEA,0x4BFE,0x4805,0x4405,
0x4000,0x3BFB,0x37FB,0x3402,0x3016,0x2C39,0x2871,0x24C0,0x212B,0x1DB6,
0x1A62,0x1735,0x1431,0x1159,0x0EB1,0x0C3A,0x09F7,0x07EB,0x0618,0x047F,
0x0323,0x0204,0x0123,0x0082,0x0021,0x0001,0x0021,0x0082,0x0123,0x0204,
0x0323,0x047F,0x0618,0x07EB,0x09F7,0x0C3A,0x0EB1,0x1159,0x1431,0x1735,
0x1A62,0x1DB6,0x212B,0x24C0,0x2871,0x2C39,0x3016,0x3402,0x37FB,0x3BFB,
};//这里采样点为1个全波100采样点,精度为15,则数值大小为0-32767(2^15)
static u16 i = 0;               //表示正弦波取样点

u16 TimerPeriod   = 0;          //自动重装载值
u16 Channel1Pulse = 0;         
u16 Channel2Pulse = 0;

/*****************************************************************
* 功能: 定时器1产生2路互补的PWM波(频率 = pfreq / (psc+1))      
* 说明: channel2,  channel3  --> PA.9, PA.10   
*       channel2N, channel3N --> PB.14, PB.15 (互补通道)
*       TimerPeriod          --> 自动重装载周期值
*       ChannelxPulse        --> 占空周期值
*****************************************************************/

void TIM1_PWM_Init(u16 pfreq ,u16 psc)          //pfreq为不分频时的PWM频率,psc为预分频值
{  
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;      
    TIM_OCInitTypeDef TIM_OCInitStructure;          //输出通道配置
    TIM_BDTRInitTypeDef TIM_BDTRInitStructure;      //死区和刹车配置

    TimerPeriod = (SystemCoreClock / pfreq) - 1;            //自动重装载周期值

    /* ChannelxPulse = DutyCycle * (TIM1_Period - 1) / 100 */
    Channel1Pulse = (u16)((u32)(50  * (TimerPeriod - 1)) / 100 );   //占空比50%
    Channel2Pulse = (u16)((u32)(50  * (TimerPeriod - 1)) / 100 );   //占空比50%

    /* 使能TIM1,GPIOA,GPIOB*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);

    /*channel1 ,channel2  --> PA.9, PA.10*
     *channel1N,channel2N --> PB.14, PB.15*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                                 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /*  初始化TIM1  */
    TIM_TimeBaseStructure.TIM_Period            = TimerPeriod;          //设置重装载周期值  
    TIM_TimeBaseStructure.TIM_Prescaler         = psc;                  //设置预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision     = 0;                    //时钟分频因子,仅与输入捕获有关(定时器与滤波器的频率比)
    TIM_TimeBaseStructure.TIM_CounterMode       = TIM_CounterMode_CenterAligned1;//TIM_CounterMode_Up;   TIM向上计数模式 计数器交替地向上和向下计数。输出比较中断标志位,只在计数器向下计数时被设置
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;                    //重复溢出中断
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);                     //初始化定时器基本配置

    /* Channel_2   TIM_OCMode_PWM1模式 */  
    TIM_OCInitStructure.TIM_OCMode       = TIM_OCMode_PWM2;//TIM_OCMode_PWM1;             //在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平 在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为
                                                                                                                                                                                  //有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
    TIM_OCInitStructure.TIM_OutputState  = TIM_OutputState_Enable;      //比较输出使能
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;     //PWM互补输出使能
    TIM_OCInitStructure.TIM_Pulse        = Channel1Pulse;               //占空比 = TIM_Pulse/TIM_Period;设置了待装入捕获比较寄存器的脉冲值。它的取值必须在 0x0000 和 0xFFFF 之间。
    TIM_OCInitStructure.TIM_OCPolarity   = TIM_OCPolarity_High;         //有效电平为高电平
    TIM_OCInitStructure.TIM_OCNPolarity  = TIM_OCNPolarity_High;        //互补通道电平与普通通道电平相反
    TIM_OCInitStructure.TIM_OCIdleState  = TIM_OCIdleState_Set;         //输出空闲状态
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;      //PWM互补输出空闲状态
    TIM_OC2Init(TIM1, &TIM_OCInitStructure);                            //根据指定的参数初始化外设TIM1 OC1

    /* Channel_3      TIM_OCMode_PWM1模式 */  
    TIM_OCInitStructure.TIM_OCMode       = TIM_OCMode_PWM2;//TIM_OCMode_PWM1;             //在向上计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平
    TIM_OCInitStructure.TIM_OutputState  = TIM_OutputState_Enable;      //比较输出使能
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;     //PWM互补输出使能
    TIM_OCInitStructure.TIM_Pulse        = Channel2Pulse;               //占空比 = TIM_Pulse/TIM_Period;
    TIM_OCInitStructure.TIM_OCPolarity   = TIM_OCPolarity_High;         //有效电平为高电平TIM_OCPolarity_Low
    TIM_OCInitStructure.TIM_OCNPolarity  = TIM_OCNPolarity_High;        //互补通道电平与普通通道电平相反
    TIM_OCInitStructure.TIM_OCIdleState  = TIM_OCIdleState_Set;         //输出空闲状态 如果实现了OC1N,则死区后OC1=1。
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;      //PWM互补输出空闲状态 0:当MOE=0时,死区后OC1N=0;
    TIM_OC3Init(TIM1, &TIM_OCInitStructure);                            //根据指定的参数初始化外设TIM1 OC2

    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);                   //使能TIM3在CCR1上的预装载寄存器
    TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);                   //使能TIM3在CCR2上的预装载寄存器

    /*死区和刹车功能配置*/
    TIM_BDTRInitStructure.TIM_OSSRState       = TIM_OSSRState_Enable;
    TIM_BDTRInitStructure.TIM_OSSIState       = TIM_OSSIState_Enable;
    TIM_BDTRInitStructure.TIM_LOCKLevel       = TIM_LOCKLevel_1;
    TIM_BDTRInitStructure.TIM_DeadTime        = 0x2F;                   //设置TIM1_BDTR的DTG[7:0]
    TIM_BDTRInitStructure.TIM_Break           = TIM_Break_Disable;
    TIM_BDTRInitStructure.TIM_BreakPolarity   = TIM_BreakPolarity_High; //刹车输入高电平有效
    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
    TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);

    TIM_Cmd(TIM1, ENABLE);                                              //使能TIM1
    TIM_CtrlPWMOutputs(TIM1,ENABLE);                                    //PWM输出使能(输出PWM的这句一定要加)


}

/**************************************************
*   名称:利用定时器2产生中断改变SPWM波的占空比  
***************************************************/
void TIM2_Int_Init(u16 ifreq,u16 psc)                       //ifreq为不分频时的更新中断频率,psc为预分频值
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);         //时钟使能

    TimerPeriod = (SystemCoreClock / ifreq) - 1;                             

    TIM_TimeBaseStructure.TIM_Period        = 2*TimerPeriod;              //设置自动重装载寄存器周期值
    TIM_TimeBaseStructure.TIM_Prescaler     = psc;                      //设置预分频值  10Khz的计数频率  
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                        //设置时钟分频系数
    TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;       //TIM向上计数模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);           

    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE );                           //使能指定的TIM2中断,允许更新中断(计数器溢出或软件初始化时)

    NVIC_InitStructure.NVIC_IRQChannel                   = TIM2_IRQn;   //TIM2中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;           //主优先级3级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 4;           //从优先级4级
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;      //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);                                     //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

    TIM_Cmd(TIM2, ENABLE);                                              //使能TIM2                 
}

//定时器2中断服务程序
void TIM2_IRQHandler(void)  
{
    extern float Period_percent;

    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)                  //检查TIM2更新中断发生与否
    {   
        TIM_SetCompare2(TIM1,(u16)(Period_percent*spwm[i])) ;       //修改TIM1通道1的PWM占空比,后者为捕获/比较寄存器1的值
        TIM_SetCompare3(TIM1,(u16)(Period_percent*spwm[i++]));      //修改TIM1通道2的PWM占空比,后者为捕获/比较寄存器2的值
        if(i == 100)  //一周期采样100个点
        {
            i = 0;
        }
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  //清除TIM2更新中断标志
    }
}

main.c:
#include "delay.h"
#include "sys.h"
#include "SPWM.h"
#include "led.h"

vu16 freq = 10000, Period = 0;                       //PWM与定时器中断频率;自动重装载值
__IO float Period_percent;                          //PWM占空比变化因子,用于修改脉宽

int main(void)
{   

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    delay_init();
    Period_percent = ((SystemCoreClock / freq) - 1) / 32767.0;

        LED_Init();
               
    TIM1_PWM_Init(10000,0);                          //输出PWM的频率为10KHz(一周期100个点,正弦波的频率为10000/2/100=50Hz)
    TIM2_Int_Init(10000,0);                          //定时器中断的频率为10KHz
       
        while(1)
        {
                LED1=0;
        }
}


看了楼主的程序后,我感觉我对TIM_OCIdleState和TIM_OCNIdleState这些还未考虑,不过先马克一下,以后再说
最后说明一下,TIM2计时到时,即TIM1先增后减计数发生下溢时更新CCRx,至于第二次捕获更新我就先不管了,目前以我的水平还看不出来增加一个第二次捕获会有什么改进


回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-9 22:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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