本帖最后由 nbutjyy 于 2024-3-25 15:03 编辑
CSDN主页: 不及你的温柔-CSDN博客
本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发
以GD32F103RCT6-TIME0高级定时器-检测CH1,CH2,CH3通道是否开启为例
后续项目主要在下面该专栏中发布:
https://blog.csdn.net/qq_62316532/category_12608431.html?spm=1001.2014.3001.5482
感兴趣的点个关注收藏一下吧!
电机驱动开发可以跳转:
手把手教你嵌入式国产化-实战项目-无刷电机驱动(1)
BMS电源系统开发可以跳转:暂未放链接
目录介绍 我们平常在使用定时器过程中,特别是一些对于PWM输出有特定逻辑需求的场所,会反复对PWM进行使能失能,以期望达到在某一时间段,该通道关闭或开启PWM比较输出,因此,本文章针对该逻辑进行一种方法介绍。
主要以操作寄存器来讲。
寄存器知识
首先既然要操作寄存器,那么我们首先得去了解GD32F10x的寄存器信息:
读取GD32F10X系列的手册可以知道,我们查看CHx(x=0,1,2,...)通道是否开启,可以读取该通道的特定使能位。
通道控制寄存器 2(TIMERx_CHCTL2) 是一个32位的寄存器,里面的第0、4、8、12位分别对应通道0-3的开启状态,那么意味着,我们只需要去读取该使能位的状态就能知道该通道是否已经被使能开启或者关闭,并且根据开启关闭状态去完成进一步的操作!
在这里我们先贴上关于这几位寄存器的一个解释:
以此类推!
好了,在有了这个知识铺垫以后,我们就可以开始对寄存器进行操作了!
代码介绍
我们需要先知道该寄存器地址!
这里我使用的是定时器0,所以一开始,我们需要去查阅定时器0的基地址,经过手册查询得到该寄存器基地址,然后我们需要进一步去获取通道控制寄存器 2(TIMERx_CHCTL2)的偏移地址
以达到寻找的目的
这里我们查阅得:
TIMER0基地址:0x4001 2C00
CHCTL2偏移地址是0x20
那么我们就可以在KEIL5中宏定义该地址方便调用,你可能会问为什么要宏定义,那是因为这个版本的GD32库,没有去定义过!
如图所示完成定义,接下来去写我们的读取函数!
如图,我们可以根据返回值的读取,去获取是否已经使能或者失能比较通道,这里我程序以三个通道为例!
接下来,让我们去编写一个判断函数!
通过返回不同的值,去判断对于通道的开启和关闭,我这里是三个通道分开各写一个函数,如果觉得繁琐可以在上一个判断函数中引入新的输入变量以达到一个函数多种判断的方式,这里就暂时以这个例子去介绍。
在完成判断以后,再去根据不同的判断结果去执行不同的响应代码
完整代码
头文件:
#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位
函数:
bool is_timer0_ch0_output_enabled(void) {
if ((*((volatile uint32_t*)(0x40012C00U + 0x20U))) & TIMER_CHCTL2_CH0EN_MASK) {
return 1; // CH0输出比较使能
} else {
return 0; // CH0输出比较未使能
}
}
bool is_timer0_ch1_output_enabled(void) {
if ((*((volatile uint32_t*)(0x40012C00U + 0x20U))) & TIMER_CHCTL2_CH1EN_MASK) {
return 1; // CH0输出比较使能
} else {
return 0; // CH0输出比较未使能
}
}
bool is_timer0_ch2_output_enabled(void) {
if ((*((volatile uint32_t*)(0x40012C00U + 0x20U))) & TIMER_CHCTL2_CH2EN_MASK) {
return 1; // CH0输出比较使能
} else {
return 0; // CH0输出比较未使能
}
}
if (is_timer0_ch0_output_enabled())
{
/* 如果 CH0输出使能,这里是代码 */
}
else
{
/* 如果 CH0没有使能,这里是代码 */
// 开启TIMER0的CH0的PWM输出
timer_channel_output_state_config(TIMER0, TIMER_CH_0, TIMER_CCX_ENABLE);
}
if (is_timer0_ch1_output_enabled())
{
/* 如果 CH1输出使能,这里是代码 */
}
else
{
/* 如果 CH1没有使能,这里是代码 */
// 开启TIMER0的CH1的PWM输出
timer_channel_output_state_config(TIMER0, TIMER_CH_1, TIMER_CCX_ENABLE);
}
if (is_timer0_ch2_output_enabled())
{
/* 如果 CH2输出使能,这里是代码 */
// 关闭TIMER0的CH2的PWM输出
timer_channel_output_state_config(TIMER0, TIMER_CH_2, TIMER_CCX_DISABLE);
}
else
{
/* 如果 CH2没有使能,这里是代码 */
}
自此结束,目前
GD32F103RCT6 基础型 目前已经完成了教程文档开发、源码编写、UCOSIII移植、函数重写,正在进行电机驱动开发
GD32F107RCT6 互联型 目前正在制作多路CAN、485、以太网通讯,输入输出隔离的开发以及源码编写和UCOSIII移植
GD32F407ZET6 目前尚未开始
我会在后续时机合适的时候发表,关注我!第一时间了解!
|