OpenEdv-开源电子网

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

关于任意I/O输出占空比可调pwm问题,进来看看

[复制链接]

2

主题

10

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2016-8-24
在线时间
7 小时
发表于 2017-6-12 15:51:21 | 显示全部楼层 |阅读模式
1金钱
由于硬件原因,现在需要任意I/O输出多路占空比可调pwm,我尝试利用定时器的比较时间模式(TIM_OCMode_Timing),然后在中断里面更新占空比和频率。可能是我思路不对,只能改变频率,占空比一直是50%,也就是改变不了频率。另外利用翻转模式(TIM_OCMode_Toggle)是不是只能对应TIMx固定的输出引脚?程序如下 有空闲的朋友帮忙看下,或者给点任意I/O输出占空比可调pwm的思路
void TIM2_Int_Init(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
         TIM_OCInitTypeDef TIM_OCInitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //ê±Öóê1Äü

        TIM_TimeBaseStructure.TIM_Period = 65535; //éèÖÃÔúÏÂò»¸ö¸üDÂê¼t×°èë»î¶ˉμÄ×Ô¶ˉÖØ×°ÔØ¼Ä′æÆ÷ÖüÆúμÄÖμ         ¼Æêyμ½5000Îa500ms
        TIM_TimeBaseStructure.TIM_Prescaler =0; //éèÖÃóÃà′×÷ÎaTIMxê±ÖóÆμÂê3yêyμÄÔ¤·ÖÆμÖμ  10KhzμļÆêyÆμÂê  
        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //éèÖÃê±Öó·Ö¸î:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIMÏòéϼÆêyÄ£ê½
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //¸ù¾YTIM_TimeBaseInitStructÖDÖ¸¶¨μÄ2Îêy3õê¼»ˉTIMxμÄê±¼ä»ùêyμ¥λ

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;//éèÖñè½Ïê±¼äÄ£ê½
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//êä3öê1Äü
        TIM_OCInitStructure.TIM_Pulse = 3600;//éèÖñè½ÏÖμ
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //êä3ö¼«DÔ
        TIM_OC1Init(TIM2, &TIM_OCInitStructure);//3õê¼»ˉTIM2μÄêä3öí¨μà1
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);//2»×Ô¶ˉ֨װ¼ÆêyÖμ

        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//êä3öê1Äü
        TIM_OCInitStructure.TIM_Pulse = 3600;//éèÖñè½ÏÖμ
        TIM_OC2Init(TIM2, &TIM_OCInitStructure);//3õê¼»ˉTIM2μÄêä3öí¨μà2
        TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);//2»×Ô¶ˉ֨װ¼ÆêyÖμ
       
        TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2  , ENABLE);//Çå3yÖD¶Ï±êÖ¾
        TIM_Cmd(TIM2, ENABLE);//′ò¿a¶¨ê±Æ÷
       
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM2ÖD¶Ï
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //ÏèÕ¼óÅÏè¼¶0¼¶
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  //′óóÅÏè¼¶3¼¶
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQí¨μà±»ê1Äü
        NVIC_Init(&NVIC_InitStructure);  //¸ù¾YNVIC_InitStructÖDÖ¸¶¨μÄ2Îêy3õê¼»ˉíaéèNVIC¼Ä′æÆ÷

        TIM_Cmd(TIM2, ENABLE);  //ê1ÄüTIMxíaéè
                                                         
}


void OCTiming_GPIO_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
}


void TIM2_IRQHandler(void)
{
        static u16 capture = 0;
        if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//êä3ö±è½Ïí¨μà1
        {
                TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);

                GPIO_WriteBit(GPIOA, GPIO_Pin_6, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_6)));//·-×aμçÆ½Öμ
                capture2 = TIM_GetCapture1(TIM2);//»ñ衱è½ÏÖμ
                TIM_SetCompare1(TIM2, capture2 + 3600);//ÖØDÂéèÖñè½ÏÖμ
        }
        if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//êä3ö±è½Ïí¨μà1
        {
                TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);

                GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_7)));//·-×aμçÆ½Öμ
                capture = TIM_GetCapture2(TIM2);//»ñ衱è½ÏÖμ
                TIM_SetCompare2(TIM2, capture + 3600);//ÖØDÂéèÖñè½ÏÖμ
        }
       
}

最佳答案

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

时间比较没用过。翻转模式不知道你表达的意思,我现在用的是应该是TIMx下所有的翻转。另外想要给点任意I/O输出占空比可调pwm的思路,定时器的引脚是固定的,想要输出可调占空比的PWM,建议直接给寄存器CCR赋值。强烈推荐原子哥的USMART组件
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

13

主题

44

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
232
金钱
232
注册时间
2017-2-4
在线时间
55 小时
发表于 2017-6-12 15:51:22 | 显示全部楼层
时间比较没用过。翻转模式不知道你表达的意思,我现在用的是应该是TIMx下所有的翻转。另外想要给点任意I/O输出占空比可调pwm的思路,定时器的引脚是固定的,想要输出可调占空比的PWM,建议直接给寄存器CCR赋值。强烈推荐原子哥的USMART组件
回复

使用道具 举报

2

主题

10

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2016-8-24
在线时间
7 小时
 楼主| 发表于 2017-6-12 15:52:10 | 显示全部楼层
原子哥求救啊
回复

使用道具 举报

8

主题

45

帖子

0

精华

高级会员

Rank: 4

积分
548
金钱
548
注册时间
2015-1-18
在线时间
173 小时
发表于 2017-6-12 21:15:51 | 显示全部楼层
以前做过输出16路pwm控制舵机的,直接开一个定时器,定时0.1ms中断,然后中断里面计数,计到200次重新计数,即20ms,然后每个pwm输出有一个初始值,在中断里分别用这些初始值对比计数值,大于为高电平,小于为低电平,这样就可以输出16路周期20ms,占空比可调的pwm了。
回复

使用道具 举报

0

主题

12

帖子

0

精华

初级会员

Rank: 2

积分
116
金钱
116
注册时间
2017-5-22
在线时间
24 小时
发表于 2017-6-12 21:21:01 | 显示全部楼层
使用TIMx的PWM模式,专门用来输出PWM波,其实就是设置好了输出捕获模式给你用,频率用ARR寄存器控制(周期值,就是TIM_Period的值),占空比等于CCR寄存器(比较值,就是TIM_Pluse的值)与ARR寄存器值的比,还有I/O口并不是固定的,只要修改PIN口就可以。你的中断服务程序里我不太能看懂是怎么改比较值的。
回复

使用道具 举报

2

主题

10

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2016-8-24
在线时间
7 小时
 楼主| 发表于 2017-6-13 08:37:40 | 显示全部楼层
wdodo0929 发表于 2017-6-12 20:14
时间比较没用过。翻转模式不知道你表达的意思,我现在用的是应该是TIMx下所有的翻转。另外想要给点任意I/O ...

多谢指点,,我去实验在思考一下
回复

使用道具 举报

2

主题

10

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2016-8-24
在线时间
7 小时
 楼主| 发表于 2017-6-13 08:39:00 | 显示全部楼层
一个爱做梦的人 发表于 2017-6-12 21:15
以前做过输出16路pwm控制舵机的,直接开一个定时器,定时0.1ms中断,然后中断里面计数,计到200次重新计数 ...

恩,,这个思路跟51利用定时器模拟pwm差不多,但是频率没办法做的很高
回复

使用道具 举报

2

主题

10

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2016-8-24
在线时间
7 小时
 楼主| 发表于 2017-6-13 08:41:11 | 显示全部楼层
miracle629 发表于 2017-6-12 21:21
使用TIMx的PWM模式,专门用来输出PWM波,其实就是设置好了输出捕获模式给你用,频率用ARR寄存器控制(周期 ...

TIMx的引脚修改也是固定指定的引脚,,硬件的pwm多路输出是调通了的,,但是硬件有所修改,,有的控制端口不是TIMx输出引脚,,所以需要改成软件的pwm
回复

使用道具 举报

2

主题

10

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2016-8-24
在线时间
7 小时
 楼主| 发表于 2017-6-13 09:26:11 | 显示全部楼层
搞出来了,结贴!!    说下思路:还是利用的TIMx的时间比较模式。初始化上面贴出的代码一样,TIM_Period=65535,比较值TIM_Pulse=3600(随意设置,这个值会在比较中断里面更改,更改这个值可以改变占空比和频率)。先对我自己理解的时间比较模式做下介绍(TIM_OCMode_Timing),时间比较模式下对应输出被冻结,输出比较不起作用。其实虽然它对与输出没有任何作用,但是它也是可以产生一个比较事件,也就是说定时器的计数值等于设定的比较值时可以出发一个 定时器中断,然后我们可以在定时器中断中做文章(关闭自动重装计数TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);)。另外时间比较模式它的执行是这样子的:TIM_Period=65535,所以计数器会一直加到65535,假设我设置的比较值为3000,那么计数器开始从0开始计数,到达3000时定时器会产生一个中断,我们可以在中断里面重新设置比较值(TIM_SetCompare1(TIM2, capture + 3000);),capture 是读出的比较值,加上3000,意思就是再过3000个计数在次中断。根据这个原理,我在中断里面翻转I/O口,就可以实现PWM。频率的调节是根据设置的比较值大小来确定,比如时钟为72M,不分频,比较值为3600,那么f=72000000/3600/2=10KHz。占空比的改变就需要动点手脚。我的思路是设置一个全局变量作为标志(局部变量好像不行),假设频率10K,那么100%的占空比就是7200个计数时间,输出占空比41%,那么高电平4200计数时间,低电平3000计数时间,在定时器中断里面设置不同的比较值就可以调节占空比了。中断代码如下
void TIM2_IRQHandler(void)
{
        static u16 capture = 0;
               
        if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//êä3ö±è½Ïí¨μà1
        {
                TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
                GPIO_WriteBit(GPIOA, GPIO_Pin_6, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_6)));//翻转电平
                capture = TIM_GetCapture1(TIM2);//获取比较值
                if(D_flag==1) //D_flag为标志
                {
                        D_flag=0;
                        TIM_SetCompare1(TIM2, capture + 3000);//重新设置比较值
                }
                else
                {       
                        D_flag=1;
                        TIM_SetCompare1(TIM2, capture + 4200);//重新设置比较值
                }
               
               
        }
//        if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)//êä3ö±è½Ïí¨μà1
//        {
//                TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);

//                GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_7)));//·-×aμçÆ½Öμ
//                capture = TIM_GetCapture2(TIM2);//»ñ衱è½ÏÖμ
//                TIM_SetCompare2(TIM2, capture + 3600);//ÖØDÂéèÖñè½ÏÖμ
//        }
       
}
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-8-18 15:49

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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