用TIM3通道1产生PWM,用TIM5去测频率,为什么误差那么大??

2019-08-17 03:29发布

求各位大佬解释一下原因和给出点建议


TIm函数
#include "timer.h"
#include "usart.h"
      
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
    GPIO_InitTypeDef         GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef        TIM_OCInitStructure;
   
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);                         //①使能定时器3时钟
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE);                       //Timer3部分重映射  TIM3_CH2->B5   

  //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形    GPIOB.5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                     //TIM_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;               //复用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);                        //初始化GPIO

  //初始化TIM3
    TIM_TimeBaseStructure.TIM_Period = arr;                       //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    TIM_TimeBaseStructure.TIM_Prescaler =psc;                     //设置用来作为TIMx时钟频率除数的预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                  //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //TIM向上计数模式
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);               //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
   
    //初始化TIM3 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;             //选择定时器模式:TIM脉冲宽度调制模式2
     TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //输出极性:TIM输出比较极性高
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);                      //根据T指定的参数初始化外设TIM3 OC2

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

}

TIM_ICInitTypeDef  TIM5_ICInitStructure;

void TIM5_Cap_Init(u16 arr,u16 psc)
{     
    GPIO_InitTypeDef GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);     //使能TIM5时钟
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //使能GPIOA时钟
   
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;             //PA0 清除之前设置  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;          //PA0 输入  
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_ResetBits(GPIOA,GPIO_Pin_0);                                   //PA0 下拉
   
    //初始化定时器5 TIM5     
    TIM_TimeBaseStructure.TIM_Period = arr;                      //设定计数器自动重装值
    TIM_TimeBaseStructure.TIM_Prescaler =psc;                      //预分频器   
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;      //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);              //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
  
    //初始化TIM5输入捕获参数
    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1;                //CC1S=01     选择输入端 IC1映射到TI1上
    TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;       //上升沿捕获
    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;             //配置输入分频,不分频
    TIM5_ICInitStructure.TIM_ICFilter = 0x00;                        //IC1F=0000 配置输入滤波器 不滤波
    TIM_ICInit(TIM5, &TIM5_ICInitStructure);

    //中断分组初始化
    NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;              //TIM3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;    //先占优先级2级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;           //从优先级0级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;              //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);                              //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器     
    TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);          //允许更新中断 ,允许CC1IE捕获中断   
  TIM_Cmd(TIM5,ENABLE );                                          //使能定时器5
   


}

u8  TIM5CH1_CAPTURE_STA=0;    //输入捕获状态    完成标志+捕获上升沿标志+捕获的一个下降沿标志(1位)+溢出次数(5位)                        
u8  TIM5CH1_CAPTURE_STA1=0;
u16    TIM5CH1_CAPTURE_VAL;      //输入捕获上升沿的值
u16 TIM5CH1_CAPTURE_VAL1;   //输入捕获下降沿的值
//定时器5中断服务程序     
void TIM5_IRQHandler(void)
{
     if((TIM5CH1_CAPTURE_STA&0X80)==0)                          //还未成功捕获   
    {      
        if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)     
        {        
                if(TIM5CH1_CAPTURE_STA&0X40)           //已经捕获到高电平了
                {
                    if((TIM5CH1_CAPTURE_STA&0X0F)==0X0F)//高电平太长了
                    {
                      //TIM5CH1_CAPTURE_STA|=0X20;        //标记成功捕获了一次
                        TIM5CH1_CAPTURE_VAL=0XFFFF;
                    }
                    else
                    {
                        TIM5CH1_CAPTURE_STA++;
               
                    }
                }

                if(TIM5CH1_CAPTURE_STA&0X20)        //已经捕获到低电平了
                {
                            if((TIM5CH1_CAPTURE_STA&0X0F)==0X0F)//低电平太长了
                            {
                                TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
                                TIM5CH1_CAPTURE_VAL1=0XFFFF;
                            }
                            else
                            {
                                TIM5CH1_CAPTURE_STA1++;
                        
                            }
                }
               
        }
            
      if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)             //捕获1发生捕获事件
        {   
                 if(TIM5CH1_CAPTURE_STA&0X40)                                //捕获到一个下降沿         
                 {      
          if(TIM5CH1_CAPTURE_STA&0X20)           //捕获到第二次上升沿
                    {
            TIM5CH1_CAPTURE_STA|=0X80;
                        TIM5CH1_CAPTURE_VAL1=TIM_GetCapture1(TIM5);
                         TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);
                    }
                    else
                    {
                 TIM5CH1_CAPTURE_STA|=0X20;   
                          TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
                          TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising);
                          TIM_SetCounter(TIM5,0);
                    }                    
                }
                else                                  //还未开始,第一次捕获上升沿
                {
                    TIM5CH1_CAPTURE_STA=0;            //清空
                    TIM5CH1_CAPTURE_VAL=0;
                    TIM_SetCounter(TIM5,0);
                    TIM5CH1_CAPTURE_STA|=0X40;                                //标记捕获到了上升沿
                    TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling);        //CC1P=1 设置为下降沿捕获
                }        
       if(TIM5CH1_CAPTURE_STA&0X40)
             {
               
             }     
        }                                                
     }

    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}
主函数:
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "timer.h"
/*
实现功能:通过输出方波,利用TIM5的通道1(PA0)做为输入捕获,
          通过串口打印出方波周期
*/

extern u8   TIM5CH1_CAPTURE_STA;        //输入捕获状态                           
extern u8   TIM5CH1_CAPTURE_STA1;   
extern u16    TIM5CH1_CAPTURE_VAL;      //输入捕获值   
extern u16    TIM5CH1_CAPTURE_VAL1;      //输入捕获值   
int main(void)
{        
     u32 temp=0;
    u32 temp1=0;
     u32 temp2=0;
    float  f;
    delay_init();             //延时函数初始化      
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);     //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    TIM3_PWM_Init(1999,0);
    uart_init(115200);                                 //串口初始化为115200
     TIM5_Cap_Init(0XFFFF,72-1);                         //以1Mhz的频率计数,其单位为1毫秒 72M/(x+1)
       while(1)
    {
        TIM_SetCompare2(TIM3,1000);   
         delay_ms(10);              
         if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次上升沿
        {
            temp=TIM5CH1_CAPTURE_STA&0X0F;
            temp1=TIM5CH1_CAPTURE_STA1&0XFF;
            temp*=65536;                        //高电平溢出时间总和
            temp1*=65536;                       //低电平溢出时间总和
            temp+=TIM5CH1_CAPTURE_VAL;          //高电平得到总的高电平时间
            temp1+=TIM5CH1_CAPTURE_VAL;         //低电平得到总的高电平时间
            temp2=temp+temp1;                   //总时间
          f=1000.0/temp;
            printf("HIGH:%d us ",temp);      //打印总的高点平时间
            printf("LOW:%d us ",temp1);      //打印总的高点平时间
            printf("T:%d us ",temp2);        //打印总的高点平时间
            printf("频率:%f KHz ",f);        //打印总的高点平时间
            TIM5CH1_CAPTURE_STA=0;              //开启下一次捕获
        }
    }
}



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
2条回答
单片机入门
1楼-- · 2019-08-17 06:23
 精彩回答 2  元偷偷看……
单片机入门
2楼-- · 2019-08-17 07:02
没人理睬吗????求大佬们帮忙

一周热门 更多>