单片机
返回首页

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

2024-11-18 来源:elecfans

概述

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

在这里插入图片描述

在这里插入图片描述

生成例程

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

管脚图如下所示。

在这里插入图片描述

在这里插入图片描述

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

串口重定向

/* 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;

}

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


占空比与频率计算

占空比=(t1-t0)/(t2-t0) 频率=(t2-t0)/时钟频率= =(t2-t0)/(120M/(psc+1))

在这里插入图片描述

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

在这里插入图片描述


GPIO初始化

/*!

    rief      configure the GPIO ports

    param[in]  none

    param[out] none

    

etval     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);        

}

开启中断

/*!

    rief      configure the nested vectored interrupt controller

    param[in]  none

    param[out] none

    

etval     none

*/

void nvic_configuration(void)

{

    nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);

    nvic_irq_enable(TIMER2_IRQn, 1, 1);

}

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);

}

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);

}

中断

#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); // 计数清零,从头开始计


        }




}

初始化

gpio_configuration(); 

    nvic_configuration();

    timer1_config();

    timer2_config();

主程序

while (1)

    {            

        time_frequency=1000000/time_up_num;//频率

        time_duty = (float)time_dowm_num/(float)time_up_num;//占空比    

        printf('

time_frequency=%.2f,time_duty=%.2f',time_frequency,time_duty*100)    ;        

        delay_1ms(1000);                            

    }


测试结果

当输出1k频率,50%正占空比。

在这里插入图片描述


进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 简洁的过零调功器电路设计与分析

  • 永不缺相启动运行的电动机控制电路

  • IGBT模块通过控制门极阻断过电流

  • 开关电源的基本组成及工作原理

  • 基于CA3193的热电偶放大器电路

  • 基于TDA1554的立体声放大器电路

    相关电子头条文章