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