请教:如何使用一个定时器实现多路频率可调PWM(占空比不要求可调)?

2019-07-21 08:07发布

本帖最后由 bootblack 于 2018-10-31 13:46 编辑

如题,由于硬件上仅剩余一个硬件定时器(通用定时器),需要实现如下功能:
1、实现5路PWM
2、每路PWM频率都可调整(各路PWM频率都是独立的)
3、占空比没有要求,一般保持50%左右即可
4、每路频率都低于10KHz
5、要求频率误差小于等于1Hz

额,想请教下各路大神,有没有很好的思路,敬请指教!感谢!



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
18条回答
Electronic
1楼-- · 2019-07-21 10:18
本帖最后由 Electronic 于 2018-11-8 17:37 编辑

说干就干,用原子的MINI的TIM1的4个通道配置输出4路不同频率的方波,频率可调,提供源码附件
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "timer.h"


//下次增量值
uint16_t TIM1_OC1_PulseAdd = 3600;        //72M/10K/2=3600
uint16_t TIM1_OC2_PulseAdd = 3600;        //72M/10K/2=3600
uint16_t TIM1_OC3_PulseAdd = 3600;        //72M/10K/2=3600
uint16_t TIM1_OC4_PulseAdd = 3600;        //72M/10K/2=3600
//比较捕获值
uint16_t TIM1_OC1_PulseVal = 0;
uint16_t TIM1_OC2_PulseVal = 0;
uint16_t TIM1_OC3_PulseVal = 0;
uint16_t TIM1_OC4_PulseVal = 0;


void TIM1_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStruct;
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStruct;
        NVIC_InitTypeDef NVIC_InitStructure;
        
        //使能时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        
        //PA8 PA9 PA10 PA11复用推挽输出
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11;
        GPIO_Init(GPIOA, &GPIO_InitStruct);
        
        //配置定时器1
        TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
        TIM_TimeBaseStructure.TIM_Prescaler = 0;                //分频越小、精度越高、范围越小; 分频越大、精度越低、范围越大
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
        
        //清除比较捕获中断标志
        TIM_ClearFlag(TIM1, TIM_FLAG_CC1);
        TIM_ClearFlag(TIM1, TIM_FLAG_CC2);
        TIM_ClearFlag(TIM1, TIM_FLAG_CC3);
        TIM_ClearFlag(TIM1, TIM_FLAG_CC4);
        
        //配置比较捕获中断
        TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
        TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE);
        TIM_ITConfig(TIM1, TIM_IT_CC3, ENABLE);
        TIM_ITConfig(TIM1, TIM_IT_CC4, ENABLE);
        
        //比较捕获初值(必须设置,不然波形不对齐)
        TIM1_OC1_PulseVal = TIM1_OC1_PulseAdd;
        TIM1_OC2_PulseVal = TIM1_OC2_PulseAdd;
        TIM1_OC3_PulseVal = TIM1_OC3_PulseAdd;
        TIM1_OC4_PulseVal = TIM1_OC4_PulseAdd;
        
        //清除比较模式
        TIM1->CCMR1 &= ~((7<<4) | (7<<12));
        TIM1->CCMR2 &= ~((7<<4) | (7<<12));
        //强制为无效电平(不设置,边沿不能对其)
        TIM1->CCMR1 |= ((4<<4) | (4<<12));
        TIM1->CCMR2 |= ((4<<4) | (4<<12));
        
        //翻转模式
        TIM_OCStructInit(&TIM_OCInitStruct);
        TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;
        TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_Toggle;                //翻转
        TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;        //有效电平
        TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
        //比较捕获通道1
        TIM_OCInitStruct.TIM_Pulse = TIM1_OC1_PulseVal;
        TIM_OC1Init(TIM1, &TIM_OCInitStruct);
        //比较捕获通道2
        TIM_OCInitStruct.TIM_Pulse = TIM1_OC2_PulseVal;
        TIM_OC2Init(TIM1, &TIM_OCInitStruct);
        //比较捕获通道3
        TIM_OCInitStruct.TIM_Pulse = TIM1_OC3_PulseVal;
        TIM_OC3Init(TIM1, &TIM_OCInitStruct);
        //比较捕获通道4
        TIM_OCInitStruct.TIM_Pulse = TIM1_OC4_PulseVal;
        TIM_OC4Init(TIM1, &TIM_OCInitStruct);
        
        //使能中断线
        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_CtrlPWMOutputs(TIM1, ENABLE);
        //使能定时器
        TIM_Cmd(TIM1, ENABLE);
}


int main(void)
{
        delay_init();                                                                        //延时函数初始化
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);        //设置中断优先级分组2
        LED_Init();                                                                                  //初始化与LED连接的硬件接口
        TIM1_Init();                                                                        //PA8被配置为复用功能
        
        //重新配置频率
        TIM1_OC1_PulseAdd = 2400;        //72M/15K/2=2400
        TIM1_OC2_PulseAdd = 3600;        //72M/10K/2=3600
        TIM1_OC3_PulseAdd = 7200;        //72M/ 5K/2=7200
        TIM1_OC4_PulseAdd = 36000;        //72M/ 1K/2=36000
           while(1)
        {
                LED1 = !LED1;
                delay_ms(300);
        }
}

//定时器1比较捕获中断
void TIM1_CC_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET)        //比较捕获通道1
        {
                TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
                TIM1_OC1_PulseVal += TIM1_OC1_PulseAdd;                //计算下次的比较捕获值
                TIM_SetCompare1(TIM1, TIM1_OC1_PulseVal);
        }
        
        if(TIM_GetITStatus(TIM1, TIM_IT_CC2) != RESET)        //比较捕获通道2
        {
                TIM_ClearITPendingBit(TIM1, TIM_IT_CC2);
                TIM1_OC2_PulseVal += TIM1_OC2_PulseAdd;                //计算下次的比较捕获值
                TIM_SetCompare2(TIM1, TIM1_OC2_PulseVal);
        }
        
        if(TIM_GetITStatus(TIM1, TIM_IT_CC3) != RESET)        //比较捕获通道3
        {
                TIM_ClearITPendingBit(TIM1, TIM_IT_CC3);
                TIM1_OC3_PulseVal += TIM1_OC3_PulseAdd;                //计算下次的比较捕获值
                TIM_SetCompare3(TIM1, TIM1_OC3_PulseVal);
        }
        
        if(TIM_GetITStatus(TIM1, TIM_IT_CC4) != RESET)        //比较捕获通道4
        {
                TIM_ClearITPendingBit(TIM1, TIM_IT_CC4);
                TIM1_OC4_PulseVal += TIM1_OC4_PulseAdd;                //计算下次的比较捕获值
                TIM_SetCompare4(TIM1, TIM1_OC4_PulseVal);
        }
}


不知道怎么上传代码,只能复制到上面

STM32 单定时器4路不同频率的方波-2018-11-08.rar (296.27 KB, 下载次数: 22) 2018-11-8 09:38 上传 点击文件名下载附件


peng1554
2楼-- · 2019-07-21 12:11
帮顶!!
wangmingwei093
3楼-- · 2019-07-21 15:12
帮顶!!!!!!!!!!!!!!!!!!!!
banxiafeixia
4楼-- · 2019-07-21 17:39
不嫌麻烦的话,初始化定时器,设置成一秒进入几十K次的中断,挨个设定翻转的时间。有点麻烦,但是可行。
lacha
5楼-- · 2019-07-21 19:56
 精彩回答 2  元偷偷看……
wangmingwei093
6楼-- · 2019-07-22 01:38
banxiafeixia 发表于 2018-10-31 09:27
不嫌麻烦的话,初始化定时器,设置成一秒进入几十K次的中断,挨个设定翻转的时间。有点麻烦,但是可行。

定时器翻转一路最快也就500K的频率,5路更低,要求不高的话确实可以。

一周热门 更多>