问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

瑞萨单片机利用定时器输入捕获采集PWM波形

创作时间:
作者:
@小白创作中心

瑞萨单片机利用定时器输入捕获采集PWM波形

引用
CSDN
1.
https://m.blog.csdn.net/qq_44377374/article/details/144416217

本文介绍了一种使用瑞萨R7FA2L1AB3CFP单片机通过定时器输入捕获模式采集PWM波形的频率和占空比的具体实现方法。文章详细描述了需求分析、实现方式选择、硬件可行性判断、定时器配置、中断配置以及具体的代码实现,对于从事嵌入式系统开发的工程师具有较高的参考价值。

1.需求

一台设备通过一引脚持续输出PWM波形,需要用瑞萨单片机采集并计算PWM的频率和占空比。

单片机型号:R7FA2L1AB3CFP

编译器版本:e2 studio 2021-01 (21.1.0) fsp:2.3.0

2.实现方式

思路:

1.利用定时器的PWM输入模式,直接获取PWM频率和占空比。

2.利用定时器的输入捕获模式,获取高电平和低电平的维持时间,进而计算PWM的频率和占空比。

3.利用GPIO捕捉引脚电平切换,在中断中在控制定时器的开始与结束,进而计算高电平和低电平的维持时间,进而计算PWM的频率和占空比。

其实三种思路逻辑大体一致,主要看瑞萨单片机是否支持PWM输入模式,这里选用思路2。

3.判断可行性

查阅手册判断瑞萨R7FA2L1AB芯片是否支持以上功能。

可以看到GTI0CnA(n = 0 to 9)、GTIOCnB(n = 0 to 9)引脚支持输入捕获功能。

硬件原本用于测PWM的引脚是P001,该引脚没有定时器功能

选择修改引脚,这里可以看到瑞萨定时器有16位的和32位的,这里选用16位的GPT6

查询引脚图,选择定时器GTIOC6_A通道,对应引脚P400。

4.定时器输入捕获逻辑

在GTIOC6_A引脚上升沿和下降沿时都设置触发捕获,连续计数两个周期后,就可以得到四个捕获值,下降沿捕获值-上升沿捕获值可以得到PWM高电平维持的时间,连续两次下降沿捕获值相减可以得到PWM的周期时间,高电平维持时间/周期时间得到PWM的占空比。

5.定时器配置

/* 定时器输入捕获配置 */
const timer_cfg_t g_input_capture_cfg =
{
    .mode = TIMER_MODE_PERIODIC,           						 	//周期型定时器
    .period_counts = (uint32_t) 0xBB80,    							//重装载值:48000
    .duty_cycle_counts = 0x5DC0,           							//占空比计数值:24000
    .source_div = (timer_source_div_t) 0,  							//时钟源不分频,48MHz
    .channel = 6,                          							//定时器6
    .p_callback = input_capture_user_callback,  					//中断回调函数
    .p_context = NULL,                   
    .p_extend = &g_input_capture_extend,        					//输入捕获扩展配置
    .cycle_end_ipl = (0),
#if defined(VECTOR_NUMBER_GPT6_COUNTER_OVERFLOW)
    .cycle_end_irq       = VECTOR_NUMBER_GPT6_COUNTER_OVERFLOW,  	//GPT6计数器溢出中断
#else
    .cycle_end_irq = FSP_INVALID_VECTOR,
#endif
};
/* 定时器输入捕获扩展配置 */
const gpt_extended_cfg_t g_input_capture_extend =
{
    .gtioca =
        { .output_enabled = false, .stop_level = GPT_PIN_LEVEL_LOW }, //停止时低电平
    .gtiocb =
        { .output_enabled = false, .stop_level = GPT_PIN_LEVEL_LOW },
    .start_source = (gpt_source_t) (GPT_SOURCE_GTIOCA_RISING_WHILE_GTIOCB_LOW),//上升沿触发 
    .stop_source  = (gpt_source_t) (GPT_SOURCE_NONE),
    .clear_source = (gpt_source_t) (GPT_SOURCE_NONE),
    .count_up_source = (gpt_source_t) (GPT_SOURCE_NONE),
    .count_down_source = (gpt_source_t) (GPT_SOURCE_NONE),
    .capture_a_source = (gpt_source_t) ( GPT_SOURCE_GTIOCA_FALLING_WHILE_GTIOCB_LOW  |
                                         GPT_SOURCE_GTIOCA_FALLING_WHILE_GTIOCB_HIGH |
                                         GPT_SOURCE_GTIOCA_RISING_WHILE_GTIOCB_LOW   |
                                         GPT_SOURCE_GTIOCA_RISING_WHILE_GTIOCB_HIGH ),
                                          //上升沿或下降沿触发
    .capture_b_source = (gpt_source_t) (GPT_SOURCE_NONE),
    .capture_a_ipl = (0),
    .capture_b_ipl = (BSP_IRQ_DISABLED),
#if defined(VECTOR_NUMBER_GPT6_CAPTURE_COMPARE_A)
    .capture_a_irq       = VECTOR_NUMBER_GPT6_CAPTURE_COMPARE_A,  //GPT6捕获中断
#else
    .capture_a_irq = FSP_INVALID_VECTOR,
#endif
#if defined(VECTOR_NUMBER_GPT6_CAPTURE_COMPARE_B)
    .capture_b_irq       = VECTOR_NUMBER_GPT6_CAPTURE_COMPARE_B,
#else
    .capture_b_irq = FSP_INVALID_VECTOR,
#endif
    .capture_filter_gtioca = GPT_CAPTURE_FILTER_NONE,  ///捕获不滤波
    .capture_filter_gtiocb = GPT_CAPTURE_FILTER_NONE,
#if 0
    .p_pwm_cfg                   = &g_input_capture_pwm_extend,
#else
    .p_pwm_cfg = NULL,
#endif
};

6.中断配置

/* GPT6定时器溢出中断和A通道捕获中断 */
#define VECTOR_NUMBER_GPT6_COUNTER_OVERFLOW ((IRQn_Type) 6) /* GPT6 COUNTER OVERFLOW (Overflow) */
#define VECTOR_NUMBER_GPT6_CAPTURE_COMPARE_A ((IRQn_Type) 8) /* GPT6 CAPTURE COMPARE A (Compare match A) */
/*******************************************************************************************************************//**
 * @brief       User defined callback
 * @param[in]   p_args
 * @retval      None
 **********************************************************************************************************************/
void input_capture_user_callback(timer_callback_args_t *p_args)
{
    /* Check for the event */
    switch(p_args->event)
    {
        /* A通道捕获中断 */
        case TIMER_EVENT_CAPTURE_A :
        {
            /*读取端口电平状态,如果是低电平则发生的是下降沿,高电平则是上升沿*/
            bsp_io_level_t p_port_value_port_400;
            R_IOPORT_PinRead(&g_ioport_ctrl_1, BMU_TEST_FANPWM_PIN, 		
                    &p_port_value_port_400);

            if(p_port_value_port_400 == BSP_IO_LEVEL_LOW)
            {
                /* 记录上次下降沿捕获数据 */
                failing_capture_last = failing_capture;
                failing_overflow_last = failing_overflow;

                /* 记录本次下降沿捕获数据 */
                failing_overflow = g_capture_overflow;
                failing_capture = p_args->capture;

                /* 计算PWM高电平计数值、1个周期的计数值 */
                if(failing_capture >= rising_capture)
                {
                    high_level_width = failing_capture - rising_capture;
                    cycle_witdh = (failing_overflow - failing_overflow_last) * 48000
                            + (failing_capture - failing_capture_last);
                }
            }
            else
            {
                /* 记录本次上升沿捕获数据 */
                rising_capture = p_args->capture;
            }
            break;
        }
        /* 定时器周期结束 */
        case TIMER_EVENT_CYCLE_END:
        {
            /* 记录溢出次数 */
            g_capture_overflow++;
            break;
        }
        default:
        {
            break;
        }
    }
}

本文原文来自CSDN

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号