GD32定时器——单个定时器下多个通道PWM捕获

本文介绍了如何在GD32F330RBT6芯片上利用Timer2和单个定时器的多个通道实现PWM捕获功能。由于硬件资源限制,通过配置Timer2的CH0~CH3通道,检测电平变化并计数,从而计算每个通道的PWM占空比。代码示例中展示了如何设置定时器、中断和捕获配置,以及计算编码器角度的方法。遇到的问题包括定时器未生效和可能的接线错误。
摘要由CSDN通过智能技术生成

GD32定时器——单个定时器下多个通道PWM捕获

背景

目前在GD32上开发,由于IO资源不足,需要在一个定时器下进行多个PWM的捕获。
定时器可以配置PWM捕获,方法有二:

  • 配置定时器通道的PWM模式
    部分定时器配置为PWM模式后,可以直接捕获PWM,这样做方便快捷,缺点是需要定时器通道本身支持该功能,并不是所有的定时器通道都支持配置PWM捕获。
  • 定时器计数,通过计数值(高电平和低电平)换算
    原理也很简单,检测电平边缘触发,例如电平从低到高,则开始计数,记为count1,从高到低时,开始计数,记为count2,则可以换算出高低电平的时长,从而计算出占空比。例如高电平的占空比为:count1/(count1+count2)

本文主要描述第二种方案。

方案实现

受限于硬件资源,需要在一个定时器上开通四个通道,然后在四个通道上捕获电平变化,然后开始计数,从而计算出每个通道的占空比。
这里选定的是
芯片型号:GD32F330RBT6,主频为84Mhz。
定时器通过阅读Datasheet,选的是Timer2,然后通过读取四个通道的PWM输入,读入,获取每个通道对应的编码器的角度。
TIMER_CH0CV宏的定义可以看出,用于获取对应定时器的通道计数值。
CH0也可以是CH1/CH2/CH3这些,这对于单个定时器多个通道的场景,很方便。
这里,编码器配置为PWM波输出。
根据编码器的规格书,共计4119个PWM时钟,故最好便是计数为4119或者其倍数,频率为994.4Hz,而GD32芯片主频为84MHz,将prescale定为20,那么就是84MHz/(20+1),即4MHz的频率,每个时钟为1/4Mhz,即250ns。
编码器的则是:1s/994.4Mz/4119,为244ns,做个简单转换,如果定时器计数值为x,编码器角度值为y,则:

x * 250 = 244 * (24 + y / 360 * 4095)

所以可以计算y,即编码器角度可知。

代码

main.c

#include <stdio.h>
#include <string.h>
#include "gd32f3x0_it.h"
#include "gd32f3x0_timer.h"
#include "gd32f3x0.h"
#include "systick.h"
#include "pwm_capture.h"

int main(void)
{
   
	pwm_capture();
}

pwm_capture.c:

#include "gd32f3x0_gpio.h"
#include "gd32f3x0_timer.h"
#include "stdint.h"
#include "pwm_capture.h"

#define RCU_GPIO_PORT 		RCU_GPIOC
#define RCU_TIMER			RCU_TIMER2
#define GPIO_PORT			GPIOC
#define ENCODER_TIMER		TIMER2
#define TIMER_CHAN0_PIN		GPIO_PIN_6
#define TIMER_CHAN1_PIN		GPIO_PIN_7
#define TIMER_CHAN2_PIN		GPIO_PIN_8
#define TIMER_CHAN3_PIN		GPIO_PIN_9
#define TIMER_PRESCALE		(20) //21 - 1

#define TIMER_PERIOD_NS         (250)
#define ENCODER_PEROID_NS       (244)
#define ENCODER_FIXED_CLK       
  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个示例代码,实现了定时器0通道0的输入捕获功能: ```c #include "gd32f3x0.h" void timer0_capture_config(void); int main(void) { /* 1. 开启GPIO时钟和定时器0时钟 */ rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_TIMER0); /* 2. 配置GPIO为定时器输入捕获模式 */ gpio_af_set(GPIOB, GPIO_AF_2, GPIO_PIN_6); gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_6); /* 3. 配置定时器0为输入捕获模式 */ timer0_capture_config(); /* 4. 启动定时器0 */ timer_enable(TIMER0); while (1) { /* 主循环中可以进行其他操作 */ } } void timer0_capture_config(void) { /* 1. 配置定时器0的时钟源为内部时钟 */ timer_ck_souce_config(TIMER0, TIMER_CLKSRC_INTERCLK); /* 2. 配置定时器0的计数模式为边沿对齐计数 */ timer_alignment_mode_config(TIMER0, TIMER_ALIGNED_EDGE); /* 3. 配置定时器0的计数方向为上升计数 */ timer_direction_config(TIMER0, TIMER_DIR_UP); /* 4. 配置定时器0的预分频值为0,即不预分频 */ timer_prescaler_config(TIMER0, 0); /* 5. 配置定时器0的计数器周期为65535 */ timer_auto_reload_shadow_config(TIMER0, 65535); /* 6. 配置定时器0的输入捕获通道0 */ timer_input_capture_config(TIMER0, TIMER_CH_0, TIMER_IC_POLARITY_BOTHEDGE); /* 上面这句代码中,TIMER_IC_POLARITY_BOTHEDGE表示捕获上升沿和下降沿 */ /* 7. 配置定时器0的输入捕获中断 */ timer_interrupt_enable(TIMER0, TIMER_INT_CH0); /* 8. 配置定时器0的DMA传输 */ timer_dma_enable(TIMER0, TIMER_DMA_CH0); /* 9. 配置NVIC中断优先级 */ nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3); nvic_irq_enable(TIMER0_IRQn, 1, 1); } /* 中断处理函数 */ void TIMER0_IRQHandler(void) { if (timer_interrupt_flag_get(TIMER0, TIMER_INT_CH0)) { /* 处理输入捕获事件 */ uint16_t capture_value = timer_channel_capture_value_register_get(TIMER0, TIMER_CH_0); /* 上面这句代码获取捕获到的计数器值 */ } /* 清除中断标志位 */ timer_interrupt_flag_clear(TIMER0, TIMER_INT_CH0); } ``` 注意:以上代码仅供参考,具体实现方式可能因为具体应用场景和硬件配置而有所不同,需要根据实际需求进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值