• STM32 IO中断方式测试频率


     一、STM32 IO中断方式测试频率有要求,频率不能过快,目前测试2M没问题,频率过高中断触发就处理不过来。

    二、过快的频率得先降频,用D触发器对频率进行降频,如下图所示,2、4、8、16分频,此例用2M时钟进行测试,对2M时钟进行2、4、8、16分频

    三、设置一个定时器,用于计时,可用于测试一段函数使用的时间

    用TIM2或TIM5定时器,是因为计数器可以支持到32位,一般都可以满足测试函数时间,而不需要再去写定时器中断函数。

    定时器框图如下:

    (1)、自动重装载寄存器TIM_Period 设置最大,也就0~0xFFFFFFFF

    (2)、预分频TIM_Prescaler,设置定时器计数时钟,也就是计一个数需要的时间。

        <a>、得知道当前用的定时器是挂在哪个总线上?

         >>可以查看资料手册,当前用的TIM2定时器挂在APB1上


        <b>、要得到CK_CNT,得知道CK_PSC,也就是TIMxCLK(CK_INT)是多少?

                   >>从上面知道TIM2是挂在APB1上,也就是PCLK1,再system_stm32f4xx.c ->static void SetSysClock(void)中

         查看PCLK1和PCLK2分别是由HCLK 4分频和2分频得到,PCLK1=180/4=45M 和PCLK2=180/2 =90M, 分频系数PPRE1 = 4、PPRE2 =2,      TIMxCLK(CK_INT) = 45M ?其实是不对的

    搜索TIMxCLK关键字,可以找到这段文字. 从上面看可得知分频系数PPRE1 = 4、PPRE2 =2,所以 TIMxCLK = 2 * PCLKx ,即TIMxCLK = 2 * 45M =90M

       TIMxCLK = 2x45M =90M ,为了便于计算,将定时器时钟设置为1M,也就是计一个数用1us的时间,可将预分频器值设置90-1=89,定时器时钟CK_CNT = (89-0+1)* 1 /(45*2) = 1M .注意:预分频器是从开始计数,所以是(89-0+1)

     3、基本定时器没有预分频功能,此项会被忽略,故TIM_ClockDivision = 0,也可以设置几个参数看看是否变动。

     4、计数方式TIM_CounterMode 设置为递增计数

     1 void times_on(void)
     2 {
     3   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
     4 
     5   RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM2, ENABLE);
     6 
     7   /* Time base configuration */
     8   TIM_TimeBaseStructure.TIM_Period = 0xFFFFFFFF;  //自动重装载寄存器的值  TIM2/TIM5定时器是32位计数器,计数器从0开始计数
     9   TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) ((SystemCoreClock / 2) / 1000000) - 1;   //预分频器从0开始计数,180M/2-1 = 89,故预分频器值是90,定时器时钟TIMx_clk = 90*1/(pclk1*2) = 90*1/(45*2)=1MHz
    10   TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //可以忽略
    11   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //递增计数
    12 
    13   TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);    //结构体进行初始化
    14   TIM_ARRPreloadConfig(TIM2, ENABLE);                //使能自动加载
    15    
    16   /* TIM Interrupts disable */
    17   TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, DISABLE);
    18 
    19   /* TIM2 enable counter */
    20   TIM_Cmd(TIM2, ENABLE);
    21   
    22 }
    23 void times_off(void)
    24 {
    25   TIM_Cmd(TIM2, DISABLE);
    26   
    27 }
    28 
    29 uint32_t get_cur_times()  //获取计时器当前值,通过前后两次获取的值做差值,算出所得耗时时间
    30 {
    31     return TIM2->CNT;
    32 }

    四、利用IO上升沿中断方式触发,在中断里计数,比如计数10000次,也就是10000个时钟周期

    IO配置:

    void  gpio_config(void)
    {
        //PA0外部中断触发
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    }

    中断配置:

    void EXTI_Config(void)
    {
        EXTI_InitTypeDef EXTI_InitStructure;
        
        //PA0作为外部中断,得相连接
        SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
        
        EXTI_InitStructure.EXTI_Line = EXTI_Line0;//通道
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿
        EXTI_InitStructure.EXTI_LineCmd  = ENABLE;//使能
        EXTI_Init(&EXTI_InitStructure);
    }
    
    void NVIC_Config(void)
    {
        NVIC_InitTypeDef NVIC_InitStructure;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //由于使用的是PA0,对应的是EXTI0通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
        NVIC_Init(&NVIC_InitStructure);    
    }

    stm32f4xx_it.c 中断函数:

    #define EXIT_CNT  10000  //测试10000个时钟周期计数
    
    float T = 0.0;
    float Fre = 0.0;
    uint32_t  exit_cnt = 0;
    uint8_t exit_flg = 0;
    __IO uint32_t time_1 = 0;
    __IO uint32_t time_2 = 0;
    
    void EXTI0_IRQHandler()
    {
        if(0 == exit_cnt)
        {
            time_1 =  get_cur_times(); //首次触发进入中断,获取当前值
        }
        
        EXTI_ClearITPendingBit(EXTI_Line0);
        exit_cnt ++;
        
        if(EXIT_CNT == exit_cnt)
        {
            time_2 =  get_cur_times();//计数达到设定值后,获取当前值
            exit_cnt = 0;
            T = (time_2 - time_1)*1.0/EXIT_CNT;  //前后获取的值做差值,算出一个时钟周期时间
            Fre = 1/T * 1000*1000; //换算出频率
            exit_flg = 1;
        }
    }

    主函数:

    int main(void)
    {  
       gpio_config();
       Debug_USART_Config(); times_on(); //开启定时器 EXTI_Config(); NVIC_Config();
    while(1) {
         demo_chipid_read();
    if(1 == exit_flg) { exit_flg = 0; printf("------------------------------------------ "); printf("T = %lf(us) ", T); printf("Fre = %lf(Hz) ", Fre); printf("------------------------------------------ "); } Delay_ms(850); }
    }

    测试2M源时钟、4分频、8分频、16分频结果如下:

          

     

  • 相关阅读:
    菜鸟版JAVA设计模式—从买房子看代理模式
    NTP工作机制及时间同步的方法
    Java工厂模式
    圣魔大战3(Castle Fantisia)艾伦希亚战记完美攻略
    对javabean的内省操作
    插入排序(insertion sort)
    中英文对照 —— 十二星座
    中英文对照 —— 十二星座
    数学归纳法的相关证明
    数学归纳法的相关证明
  • 原文地址:https://www.cnblogs.com/wen2376/p/13346479.html
Copyright © 2020-2023  润新知