GD32F103RCT6/GD32F303RCT6(9)高级定时器互补PWM波输出实验

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发

后续项目主要在下面该专栏中发布:

手把手教你嵌入式国产化_不及你的温柔的博客-CSDN博客

感兴趣的点个关注收藏一下吧!

电机驱动开发可以跳转:

手把手教你嵌入式国产化-实战项目-无刷电机驱动(1)-CSDN博客

BMS电源系统开发可以跳转:暂未放链接

向上代码兼容GD32F303RCT6中使用

本项目配套开发板:

基于GD32F103RCT6国产GD32平台,以下教程编写基于该开发板

图片:

原理图以及例程请联系客服获取!

注意:

本教程致力于解决所有在调试中出现的所有问题,如有未包含在的问题,请联系QQ:2049363803,有奖更新文档!

定时器介绍

在上一节中,我们已经完成了对高级/通用定时器输出PWM波的实验

本次实验将会研究高级定时器TIMER0的互补PWM输出

这里需要强调一下,和串口一样,GD32的定时器定义是从0为编号开始的!

在逻辑框图中,关于互补波形输出的控制是在右下角的输出逻辑中实现的

寄存器

涉及到的寄存器主要是以下几个:

常规的时钟源配置和时钟预分频器、计数模式等在上一篇文章中有介绍就不作为主要讲解,今天主要是是关于互补寄存器。

控制寄存器1TIMERx_CTL1

主要涉及到互补波形的空闲状态电平以及通道的触发源选择和模式控制,其次就是DMA以及影子寄存器的控制这里使用不到就不做讲解;

第八位和第九位的ISO0 以及ISO0N作为主要控制位。

通道控制寄存器2TIMERx_CHCTL2

涉及到互补的主要配置:有效极性、使能状态等,该寄存器是读写寄存器,意味着我们可以随时读取以获取通道使能状态或者写入数据使得通道启用或者禁用、包括在运行过程中改变输出互补波形的极性状态。

互补PWM实验

编程要点:

1.初始化结构体

2.使能GPIO时钟

3.设置GPIO工作模式

4.使能复用时钟和定时器时钟

5.初始化定时器参数

6.配置互补通道参数

7.使能通道输出

bsp_timer.c

复制代码
#include "bsp_timer.h"
#include "bsp_led.h"
#include "oled.h"



//GPIO管脚配置
void gpio_config(void)
{	  
		rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_AF);

    /*Configure PA8 PA9 PA10(TIMER0 CH0 CH1 CH2) as alternate function*/
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

    /*Configure PB13 PB14 PB15(TIMER0 CH0N CH1N CH2N) as alternate function*/
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
			
}

/**
 @brief PWM初始化
 @param 无
 @return 无
*/

//定时器配置,TIM1,通道1,通道2,通道3
void timer_config(uint16_t arr,uint16_t psc)
{
	gpio_config();
	

	
	  rcu_periph_clock_enable(RCU_TIMER0);
	
    timer_oc_parameter_struct timer_ocintpara;
	  timer_oc_parameter_struct timer_ocintpara1;
	  timer_oc_parameter_struct timer_ocintpara2;
	
    timer_parameter_struct timer_initpara;

    

    timer_deinit(TIMER0);

    /* TIMER0 configuration */
    timer_initpara.prescaler         = psc;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = arr;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER0,&timer_initpara);

     /* CH1,CH2 and CH3 configuration in PWM mode */
    timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
    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_ocintpara1.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara1.outputnstate = TIMER_CCXN_ENABLE;
    timer_ocintpara1.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara1.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara1.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara1.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
		
		timer_ocintpara2.outputstate  = TIMER_CCX_ENABLE;
    timer_ocintpara2.outputnstate = TIMER_CCXN_ENABLE;
    timer_ocintpara2.ocpolarity   = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara2.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara2.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara2.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
		

    timer_channel_output_config(TIMER0,TIMER_CH_0,&timer_ocintpara);
    timer_channel_output_config(TIMER0,TIMER_CH_1,&timer_ocintpara1);
    timer_channel_output_config(TIMER0,TIMER_CH_2,&timer_ocintpara2);

    timer_channel_output_pulse_value_config(TIMER0,TIMER_CH_0,500);
    timer_channel_output_mode_config(TIMER0,TIMER_CH_0,TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);

    timer_channel_output_pulse_value_config(TIMER0,TIMER_CH_1,500);
    timer_channel_output_mode_config(TIMER0,TIMER_CH_1,TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0,TIMER_CH_1,TIMER_OC_SHADOW_DISABLE);

    timer_channel_output_pulse_value_config(TIMER0,TIMER_CH_2,500);
    timer_channel_output_mode_config(TIMER0,TIMER_CH_2,TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0,TIMER_CH_2,TIMER_OC_SHADOW_DISABLE);

    timer_primary_output_config(TIMER0,ENABLE);
    
    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER0);
    timer_enable(TIMER0);
}


//设置TIMER0通道0的占空比
//compare:比较值
void TIM_SetTIM0Compare1(uint32_t compare)
{
  timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, compare);
}

//设置TIMER0通道0的占空比
//compare:比较值
void TIM_SetTIM0Compare2(uint32_t compare)
{
  timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, compare);
}

//设置TIMER0通道0的占空比
//compare:比较值
void TIM_SetTIM0Compare3(uint32_t compare)
{
  timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2, compare);
}


// TIMER0更新中断服务程序
void TIMER0_UP_IRQHandler(void) {
    if (SET == timer_interrupt_flag_get(TIMER0, TIMER_INT_FLAG_UP)) 
		{
        timer_interrupt_flag_clear(TIMER0, TIMER_INT_FLAG_UP);
//			  LED1_ON; // 点亮LED
//			  LED2_ON; // 点亮LED
        // 在这里添加触发中间对齐中断的处理代码
    }
}

我们在这里设置初始化默认占空比大小

主函数中完成初始化设置

实验结果

其中黄色通道1是PA8输出的波形,通道2是PB13输出的波形,完成实验。

拓展部分

在使用GD32驱动EG2133的过程中,需要互补的波形有效电平极性能根据我的使用情况发生改变,使得互补的PWM波与主通道相同或者反相

前文我们讲到,改变互补PWM极性是更改TIMER_CHCTL2寄存器中的CH0NP位的数据

那么我们只需要根据寄存器地址寻址,对3号位置寄存器的数据进行更改就行。

上代码:
复制代码
#define TIMER0_BASE_ADDRESS 0x40012C00 // TIMER0的基地址
#define TIMER_CHCTL2_OFFSET 0x20       // TIMER_CHCTL2寄存器相对于基地址的偏移
#define TIMER0_CHCTL2       (*((volatile uint32_t*)(0x40012C00 + 0x20)))

#define TIMER_CHCTL2_CH0EN_MASK (1U << 0) // CH0EN位在第0位
#define TIMER_CHCTL2_CH1EN_MASK (1U << 4) // CH1EN位在第4位
#define TIMER_CHCTL2_CH2EN_MASK (1U << 8) // CH2EN位在第8位

#define TIMER_CHCTL2_CH0NP_MASK (1U << 3) // CH0EN位在第0位
#define TIMER_CHCTL2_CH1NP_MASK (1U << 7) // CH1EN位在第4位
#define TIMER_CHCTL2_CH2NP_MASK (1U << 11) // CH2EN位在第8位

#define TIMER_CHCTL2_CH0NP_PC_0   TIMER0_CHCTL2 &= (~(1U<<3))
#define TIMER_CHCTL2_CH0NP_PC_1   TIMER0_CHCTL2 |= 1U<<3            //或只需要改变要操作的位数

#define TIMER_CHCTL2_CH1NP_PC_0   TIMER0_CHCTL2 &= (~(1U<<7))
#define TIMER_CHCTL2_CH1NP_PC_1   TIMER0_CHCTL2 |= 1U<<7       

#define TIMER_CHCTL2_CH2NP_PC_0   TIMER0_CHCTL2 &= (~(1U<<11))
#define TIMER_CHCTL2_CH2NP_PC_1   TIMER0_CHCTL2 |= 1U<<11 

想找到一个寄存器的位置,首先需要知道定时器0的总地址,然后其中每个地址对于该地址的偏移就能完成偏移寻址。

主函数代码

在mian中调用:TIMER_CHCTL2_CH0NP_PC_1; 使得由反相变成同向

示波器结果:

再次调用反相函数使得其更改为反相

完成本次实验!!

创作不易,点个赞收藏一下吧,求求了。比个爱心

相关推荐
无人装备硬件开发爱好者1 小时前
STM32G474 + 1.32 寸 OLED(128×96)俄罗斯方块游戏实现指南
stm32·嵌入式硬件·游戏
三佛科技-134163842121 小时前
SM2850P无电感离线稳压器 5V输出 典型应用电路分析(管脚、关键设计要点)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
潜创微科技2 小时前
IT6636+USB 协同芯片 3 进 1 出 HDMI2.1 KVM 切换器一体化方案
嵌入式硬件·音视频
dqsh063 小时前
关于STM32G474芯片有规律的自动重启的问题
stm32·单片机·嵌入式硬件·系统重启·原因解析
时空自由民.3 小时前
BLDC无刷直流电机作为发电机的波形图
单片机
yong99903 小时前
基于 STM32 的 4×4 矩阵键盘源码
stm32·矩阵·计算机外设
JSMSEMI113 小时前
JSM63006 5A 28V三相无刷电机驱动电路
单片机·嵌入式硬件
国产芯片设计3 小时前
【LCD驱动实战】单颗YL1621脚位不足?双芯片联动驱动方案详解
stm32·单片机·mcu·51单片机·硬件工程
不怕犯错,就怕不做4 小时前
RK3562的CPU如何降频及关闭硬件编解码
linux·驱动开发·嵌入式硬件
Hical_W4 小时前
Hical 踩坑实录五部曲(二):MSVC / GCC / Clang 三平台 C++20 编译差异
linux·windows·经验分享·嵌入式硬件·macos·开源·c++20