IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> GD32定时器——单个定时器下多个通道PWM捕获 -> 正文阅读

[嵌入式]GD32定时器——单个定时器下多个通道PWM捕获

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       (24)
#define ENCODER_ANGLE_CLK       (4095)

//#define ENCODE_PWM 	(4119)

volatile uint32_t ch0_cnt = 0;
volatile uint32_t ch1_cnt = 0;
volatile uint32_t ch2_cnt = 0;
volatile uint32_t ch3_cnt = 0;

volatile uint32_t ch0_1 = 0;
volatile uint32_t ch0_2 = 0;
volatile uint32_t ch1_1 = 0;
volatile uint32_t ch1_2 = 0;
volatile uint32_t ch2_1 = 0;
volatile uint32_t ch2_2 = 0;
volatile uint32_t ch3_1 = 0;
volatile uint32_t ch3_2 = 0;

volatile float encode0 = 0.0;
volatile float encode1 = 0.0;
volatile float encode2 = 0.0;
volatile float encode3 = 0.0;

float to_angle(uint32_t clk_cnt)
{
		float ret = (float)(TIMER_PERIOD_NS * clk_cnt / ENCODER_PEROID_NS - 24) * 360 / ENCODER_ANGLE_CLK;
		float EPSINON = 0.00001;
		if (ret < EPSINON)
				ret = 0.0;
		EPSINON = 359.99999;
		if (ret > EPSINON)
				ret = 360.0;
		return ret;
}

#if 0
void TIMER0_Channel_IRQHandler(void)
#else
void TIMER2_IRQHandler(void)
#endif
{
    if (timer_interrupt_flag_get(ENCODER_TIMER, TIMER_INT_FLAG_CH0) != RESET)
    {
        if (SET == gpio_input_bit_get(GPIO_PORT, TIMER_CHAN0_PIN))
        {
            ch0_1 = TIMER_CH0CV(ENCODER_TIMER);
        }
        else
        {
            ch0_2 = TIMER_CH0CV(ENCODER_TIMER);
        }

        if (ch0_2 > ch0_1)
        {
            ch0_cnt = ch0_2 - ch0_1;
            ch0_2 = ch0_1 = 0;
            encode0 = to_angle(ch0_cnt);
        }
    }
    else if (timer_interrupt_flag_get(ENCODER_TIMER, TIMER_INT_FLAG_CH1) != RESET)
    {
        if (SET == gpio_input_bit_get(GPIO_PORT, TIMER_CHAN1_PIN))
        {
            ch1_1 = TIMER_CH1CV(ENCODER_TIMER);
        }
        else
        {
            ch1_2 = TIMER_CH1CV(ENCODER_TIMER);
        }

        if (ch1_2 > ch1_1)
        {
            ch1_cnt = ch1_2 - ch1_1;
            ch1_2 = ch1_1 = 0;
            encode1 = to_angle(ch1_cnt);
        }
    }
    else if (timer_interrupt_flag_get(ENCODER_TIMER, TIMER_INT_FLAG_CH2) != RESET)
    {
        if (SET == gpio_input_bit_get(GPIO_PORT, TIMER_CHAN2_PIN))
        {
            ch2_1 = TIMER_CH2CV(ENCODER_TIMER);
        }
        else
        {
            ch2_2 = TIMER_CH2CV(ENCODER_TIMER);
        }

        if (ch2_2 > ch2_1)
        {
            ch2_cnt = ch2_2 - ch2_1;
            ch2_2 = ch2_1 = 0;
            encode2 = to_angle(ch2_cnt);
        }
    }
    else if (timer_interrupt_flag_get(ENCODER_TIMER, TIMER_INT_FLAG_CH3) != RESET)
    {
        if (SET == gpio_input_bit_get(GPIO_PORT, TIMER_CHAN3_PIN))
        {
            ch3_1 = TIMER_CH3CV(ENCODER_TIMER);
        }
        else
        {
            ch3_2 = TIMER_CH3CV(ENCODER_TIMER);
        }

        if (ch3_2 > ch3_1)
        {
            ch3_cnt = ch3_2 - ch3_1;
            ch3_2 = ch3_1 = 0;
            encode3 = to_angle(ch3_cnt);
        }
    }
}

void timer_config(void)
{
	timer_parameter_struct timer_initpara;
    timer_ic_parameter_struct timer_icinitpara;

    //rcu	
    rcu_periph_clock_enable(RCU_GPIO_PORT);
    rcu_periph_clock_enable(RCU_TIMER);

    gpio_mode_set(GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, TIMER_CHAN0_PIN);
    gpio_mode_set(GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, TIMER_CHAN1_PIN);
    gpio_mode_set(GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, TIMER_CHAN2_PIN);
    gpio_mode_set(GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, TIMER_CHAN3_PIN);

    gpio_output_options_set(GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, TIMER_CHAN0_PIN);
    gpio_output_options_set(GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, TIMER_CHAN1_PIN);
    gpio_output_options_set(GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, TIMER_CHAN2_PIN);
    gpio_output_options_set(GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, TIMER_CHAN3_PIN);

    //timer init
    /* TIMER configuration */
    timer_deinit(ENCODER_TIMER);

    timer_initpara.prescaler         = TIMER_PRESCALE;
    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(ENCODER_TIMER, &timer_initpara);

    //PWM capture parameters		
    timer_icinitpara.icpolarity = TIMER_IC_POLARITY_BOTH_EDGE;
    timer_icinitpara.icfilter = 0x0;
    timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
    timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;

    timer_input_capture_config(ENCODER_TIMER, TIMER_CH_0, &timer_icinitpara);
    timer_input_capture_config(ENCODER_TIMER, TIMER_CH_1, &timer_icinitpara);
    timer_input_capture_config(ENCODER_TIMER, TIMER_CH_2, &timer_icinitpara);
    timer_input_capture_config(ENCODER_TIMER, TIMER_CH_3, &timer_icinitpara);

    //interrupt priority/flag
#if 0
	vic_irq_enable(TIMER0_Channel_IRQn, 1, 1);
#else
    nvic_irq_enable(TIMER2_IRQn, 1, 1);
#endif

    timer_interrupt_flag_clear(ENCODER_TIMER, TIMER_INT_FLAG_CH0);
    timer_interrupt_flag_clear(ENCODER_TIMER, TIMER_INT_FLAG_CH1);
    timer_interrupt_flag_clear(ENCODER_TIMER, TIMER_INT_FLAG_CH2);
    timer_interrupt_flag_clear(ENCODER_TIMER, TIMER_INT_FLAG_CH3);

    timer_interrupt_flag_clear(ENCODER_TIMER, TIMER_INT_FLAG_UP);

    timer_interrupt_enable(ENCODER_TIMER, TIMER_INT_CH0 | TIMER_INT_UP);
    timer_interrupt_enable(ENCODER_TIMER, TIMER_INT_CH1 | TIMER_INT_UP);
    timer_interrupt_enable(ENCODER_TIMER, TIMER_INT_CH2 | TIMER_INT_UP);
    timer_interrupt_enable(ENCODER_TIMER, TIMER_INT_CH3 | TIMER_INT_UP);

    timer_auto_reload_shadow_enable(ENCODER_TIMER);
    timer_enable(ENCODER_TIMER);
}

void pwm_capture(void)
{
	timer_config();
	while (1)
	{
		;
	}
}

问题

  1. 定时器没有生效
  • 主程序没有while 1语句,需要不停的监听中断
  • 接线问题,定时器的PWM管脚需要检查正确
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 21:07:25  更:2022-03-21 21:10:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:18:26-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码