• GD32F303固件库开发(13)----定时器TIM捕获PWM测量频率与占空比


    概述

    本章配置GD32F303输出PWM,同时使用TIM测量PWM频率和正占空比。
    查阅手册可以得知,PB11为定时器1的通道3,让其输出PWM,PA6为定时器2的通道0,让作为TIM定时器输入。
    需要GD样片的可以加群申请:615061293 。
    在这里插入图片描述
    在这里插入图片描述

    视频教学

    https://www.bilibili.com/video/BV1tg411m7pb/

    GD32F303固件库开发(13)----定时器TIM捕获PWM测量频率与占空比

    csdn课程

    课程更加详细。
    https://download.csdn.net/course/detail/37144

    样品申请

    https://www.wjx.top/vm/wFGhGPF.aspx#

    生成例程

    这里准备了自己绘制的开发板进行验证。

    管脚图如下所示。

    在这里插入图片描述
    在这里插入图片描述

    keil配置

    microlib 进行了高度优化以使代码变得很小。 它的功能比缺省 C 库少,并且根本不具备某些 ISO C 特性。 某些库函数的运行速度也比较慢,如果要使用printf(),必须开启。

    在这里插入图片描述

    使能串口

      /* 使能GPI0A,用PA9、PA10为串口 */
        rcu_periph_clock_enable(RCU_GPIOA);
    
        /*使能串口0的时钟 */
        rcu_periph_clock_enable(RCU_USART0);
    
        /*配置USARTx_Tx(PA9)为复用推挽输出*/
        gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
     
        /*配置USARTx_RxPA9)为浮空输入 */
        gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
    
        /* USART 配置 */
        usart_deinit(USART0);//重置串口0
        usart_baudrate_set(USART0, 115200U);//设置串口0的波特率为115200
        usart_word_length_set(USART0, USART_WL_8BIT);      	// 帧数据字长
    		usart_stop_bit_set(USART0, USART_STB_1BIT);      	 	// 停止位1位
        usart_parity_config(USART0, USART_PM_NONE);       	// 无奇偶校验位
        usart_receive_config(USART0, USART_RECEIVE_ENABLE);//使能接收器
        usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);//使能发送器
        usart_enable(USART0);//使能USART
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    串口重定向

    /* retarget the C library printf function to the USART */
    int fputc(int ch, FILE *f)
    {
        usart_data_transmit(USART0, (uint8_t)ch);
        while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
        return ch;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    串口重定向后就可以使用printf进行打印。

    占空比与频率计算

    占空比=(t1-t0)/(t2-t0)
    频率=(t2-t0)/时钟频率= =(t2-t0)/(120M/(psc+1))
    在这里插入图片描述

    周期需要2个上升沿去判断,设定第一个上升沿time_flag由0->1,下降沿time_dowm_flag由0->1,此时就知道正占空比时间,当在产生上升沿时候,就可以计算出周期使用的时间。
    在这里插入图片描述

    GPIO初始化

    /*!
        \brief      configure the GPIO ports
        \param[in]  none
        \param[out] none
        \retval     none
    */
    void gpio_configuration(void)
    {
    		rcu_periph_clock_enable(RCU_GPIOB);
        rcu_periph_clock_enable(RCU_GPIOA);
        rcu_periph_clock_enable(RCU_AF);
    
        /*configure PA6 (TIMER2 CH0) as alternate function*/
        gpio_init(GPIOA,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_6);
    		//TIMER1-CH3
    		gpio_pin_remap_config(GPIO_TIMER1_PARTIAL_REMAP1, ENABLE);
    		gpio_init(GPIOB,GPIO_MODE_AF_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_11);		
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    开启中断

    /*!
        \brief      configure the nested vectored interrupt controller
        \param[in]  none
        \param[out] none
        \retval     none
    */
    void nvic_configuration(void)
    {
        nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
        nvic_irq_enable(TIMER2_IRQn, 1, 1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    TIM1输出PWM初始化

    PWM频率计算如下所示。
    在这里插入图片描述

    void timer1_config(void)
    {
        /* -----------------------------------------------------------------------
        TIMER1 configuration: generate 3 PWM signals with 3 different duty cycles:
        TIMER1CLK = SystemCoreClock / 120 = 1MHz
    
        TIMER1 channel0 duty cycle = (4000/ 16000)* 100  = 25%
        TIMER1 channel1 duty cycle = (8000/ 16000)* 100  = 50%
        TIMER1 channel2 duty cycle = (12000/ 16000)* 100 = 75%
        ----------------------------------------------------------------------- */
        timer_oc_parameter_struct timer_ocintpara;
        timer_parameter_struct timer_initpara;
    	
        rcu_periph_clock_enable(RCU_TIMER1);
    
        timer_deinit(TIMER1);
    
        /* TIMER1 configuration */
        timer_initpara.prescaler         = 119;
        timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
        timer_initpara.counterdirection  = TIMER_COUNTER_UP;
        timer_initpara.period            = 1000;
        timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
        timer_initpara.repetitioncounter = 0;
        timer_init(TIMER1,&timer_initpara);
    
        /* CH0,CH1 and CH2 configuration in PWM mode */
        timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
        timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
        timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
        timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
        timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
        timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
        timer_channel_output_config(TIMER1,TIMER_CH_3,&timer_ocintpara);
    
        /* CH3 configuration in PWM mode0,duty cycle 50% */
        timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_3,500);
        timer_channel_output_mode_config(TIMER1,TIMER_CH_3,TIMER_OC_MODE_PWM0);
        timer_channel_output_shadow_config(TIMER1,TIMER_CH_3,TIMER_OC_SHADOW_DISABLE);
    		
        /* auto-reload preload enable */
        timer_auto_reload_shadow_enable(TIMER1);
        /* auto-reload preload enable */
        timer_enable(TIMER1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    TIM2输入捕获设置

    void timer2_config(void)
    {
        /* TIMER2 configuration: input capture mode -------------------
        the external signal is connected to TIMER2 CH0 pin (PB4)
        the rising edge is used as active edge
        the TIMER2 CH0CV is used to compute the frequency value
        ------------------------------------------------------------ */
        timer_ic_parameter_struct timer_icinitpara;
        timer_parameter_struct timer_initpara;
    		//开启定时器时钟
        rcu_periph_clock_enable(RCU_TIMER2);
    
        timer_deinit(TIMER2);
    
        /* TIMER2 configuration */
        timer_initpara.prescaler         = 120-1;//定时器的时钟频率是120MHz,预分频120-1
        timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;//对齐模式
        timer_initpara.counterdirection  = TIMER_COUNTER_UP;//向上计数
        timer_initpara.period            = 65535;//重载值
        timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;//不分频
        timer_initpara.repetitioncounter = 0;//重复计数
        timer_init(TIMER2,&timer_initpara);
    
        /* TIMER2  configuration */
        /* TIMER2 CH0 input capture configuration */
        timer_icinitpara.icpolarity  = TIMER_IC_POLARITY_RISING;//捕获极性,上升沿捕获
        timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;//通道输入模式选择
        timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;//分频
        timer_icinitpara.icfilter    = 0x0;//滤波
        timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);
    
        /* auto-reload preload enable */
        timer_auto_reload_shadow_enable(TIMER2);//自动重载使能
        /* clear channel 0 interrupt bit */
        timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH0);//CH0 通道中断清除
        /* channel 0 interrupt enable */
        timer_interrupt_enable(TIMER2,TIMER_INT_CH0);//CH0 通道中断使能
    
        /* TIMER2 counter enable */
        timer_enable(TIMER2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    中断

    #define IR_IN1  gpio_input_bit_get (GPIOA, GPIO_PIN_6)
    uint8_t time_up_flag=0;//上升沿标志位
    uint8_t time_dowm_flag=0;//下降沿标志位
    
    uint32_t time_up_num=0;//上升沿计数
    uint32_t time_dowm_num=0;//下降沿计数
    float time_frequency;//频率
    float time_duty;//占空比
    
    
    void TIMER2_IRQHandler(void)
    {
        		timer_ic_parameter_struct timer_icinitpara;
        timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
        timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
        timer_icinitpara.icfilter    = 0x0;		
     if(SET == timer_interrupt_flag_get(TIMER2,TIMER_INT_FLAG_CH0)){
            /* clear channel 0 interrupt bit */
            timer_interrupt_flag_clear(TIMER2,TIMER_INT_FLAG_CH0);		
    		
    		if(IR_IN1&&time_up_flag==0)//第一次上升
    		{
    			time_up_flag=1;
    			timer_icinitpara.icpolarity = TIMER_IC_POLARITY_FALLING;  //设置为下降沿
    			timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);	
    			timer_counter_value_config(TIMER2 , 0); // 计数清零,从头开始计
    		
    		}
    		else if(IR_IN1==0&&time_dowm_flag==0)//下降
    		{
    			
    			time_dowm_num = timer_channel_capture_value_register_read(TIMER2,TIMER_CH_0)+1; // 读取捕获计数,这个时间即为上升沿持续的时间
    			timer_icinitpara.icpolarity = TIMER_IC_POLARITY_RISING;  //设置为上升沿
    			timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);	
    			time_dowm_flag=1;
    		}		
    		else if(IR_IN1&&time_dowm_flag==1)//第二次之后上升
    		{		
    			time_up_num = timer_channel_capture_value_register_read(TIMER2,TIMER_CH_0)+1;; // 读取捕获计数,这个时间即为上升沿持续的时间
    				timer_icinitpara.icpolarity = TIMER_IC_POLARITY_FALLING;  //设置为下降沿
    				timer_input_capture_config(TIMER2,TIMER_CH_0,&timer_icinitpara);
    			time_dowm_flag=0;
    			timer_counter_value_config(TIMER2 , 0); // 计数清零,从头开始计
    		
    		}
    
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    初始化

        gpio_configuration(); 
        nvic_configuration();
    	timer1_config();
        timer2_config();
    
    • 1
    • 2
    • 3
    • 4

    主程序

        while (1)
        {			
    		time_frequency=1000000/time_up_num;//频率
    		time_duty = (float)time_dowm_num/(float)time_up_num;//占空比	
    		printf("\ntime_frequency=%.2f,time_duty=%.2f",time_frequency,time_duty*100)	;		
    		delay_1ms(1000);							
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试结果

    当输出1k频率,50%正占空比。
    在这里插入图片描述

  • 相关阅读:
    解决u盘在我的电脑中重复显示两个
    使用Kali Linux Metasploit 对WEB应用进行攻击 以DVWA为例
    北大肖臻老师《区块链技术与应用》系列课程学习笔记[14]以太坊-状态树2
    SynchronousQueue简介
    Redis 数据类型
    视频理解学习笔记(三)
    nginx(六十五)proxy模块(六)处理上游的响应头部
    云数据安全:在数字时代保护您的宝贵资产
    KVM 虚拟化
    GBase8d使用的LDAP基础知识(一):
  • 原文地址:https://blog.csdn.net/qq_24312945/article/details/126741286