记:关于输出任意占空比与频率的一种方式——基于STM32单片机

8 篇文章 0 订阅
7 篇文章 0 订阅
本文介绍了使用STM32高级定时器实现任意频率和占空比PWM信号的方法,通过固定定时器累加值计算占空比阈值,以及根据频率和系统时钟计算分频系数。同时,详细探讨了死区时间的计算,包括不同分频比的区间划分,并给出了伪代码示例。该方法适用于需要精确控制PWM输出的嵌入式系统设计。
摘要由CSDN通过智能技术生成

0x00前言

写下这篇文章的主要目的时总结一下最近发现的一个较方便的波形调制方式。可以一定程度脱离手工计算,支持发出任意频率、任意占空比PWM控制信号的方式,使用了较为方便的寄存器的方式进行驱动。本文分为两部分,分别讲述了一个调制信号的思路以及实现的方式、一个计算死区的方式。
阅读本文,您可能需要掌握的知识:

技能熟练度
英语熟练
知识检索熟练
数学计算基础
逻辑思维熟练

0x10 调制信号的方式

项目的主要要求在于,可以随意的调制出任意占空比1~10KHzPWM方波。因为这个需求的难度,所以使得软件模拟变成了很难的一件事情。遂我使用STM32系列的高级定时器对波形进行模拟。再查阅了相关资料后我得出的结论,计算波形主要的参数在于占空比以及分频系数上。

0x11 占空比

计算占空比的公式主要是:

P W M 占 空 比 = 占 空 比 阈 值 定 时 器 累 加 值 PWM占空比= \frac {占空比阈值} {定时器累加值} PWM=

项目除了较为宽泛的频率选择,还有宽泛的占空比选择。所以为了方便选择占空比,本人主要的思想在于:确认一个固定的定时器累加值。从而在给定了PWM占空比的情况下,就可以得到当前占空比的阈值。而且只需要调高定时器累加值(分母),就可以得到更高的占空比精度。一般的占空比范围于定时器累加值范围表述约为:

占空比范围定时器累加值
0~100100
0~100.01000
0~100.0010000

一般来说,占空比精度做到大约万分之一即可。

0x12 分频系数

仔细翻找了官方的一些文档,以及第三方标准库(StdLib)。得到了一个较为完备的公式:

1 计 时 时 间 = ( 定 时 器 累 加 值 − 1 ) ∗ ( 定 时 器 分 频 值 − 1 ) 当 前 系 统 时 间 \frac {1}{计时时间}=\frac{(定时器累加值 - 1) * (定时器分频值-1)}{当前系统时间} 1=(1)(1)

而频率对于计时时间的转换公式为:
频 率 = 1 计 时 时 间 频率=\frac{1}{计时时间} =1
则公式可以简化成:
频 率 = ( 定 时 器 累 加 值 − 1 ) ∗ ( 定 时 器 分 频 值 − 1 ) 当 前 系 统 时 间 频率=\frac{(定时器累加值 - 1) * (定时器分频值-1)}{当前系统时间} =(1)(1)

根据此公式,在已知频率、累加器、系统时钟的情况下,可以轻松得出当前定时器分频系数为:

定 时 器 分 频 系 数 = 频 率 ∗ 当 前 系 统 时 钟 定 时 器 累 加 器 − 1 + 1 定时器分频系数=\frac{频率*当前系统时钟}{定时器累加器-1}+1 =1+1

直接带入即可计算出可以使用的分频系数,而且基本上不会溢出。也可以通过分频系数推断出当前最高输出的频率。

0x20 死区时间

根据官方给的记录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-omvJ2pJM-1611468191137)(https://www.abcde.engineer/wp-content/uploads/2019/04/7bd8743e14ab72157360d33fddfb9774.png)]
而官方的寄存器记录中并没有提到关于DTS相关的信息,但是在前面的地方就会有解释,这个DTS可以认为是定时器总线时钟片的原子单位。本人使用了120MHz的时钟,也就是说t_DTS=8μs。

单 个 分 频 比 = 死 区 时 间 t D T S 单个分频比=\frac{死区时间}{t_{DTS}} =tDTS

可以先得到官方例子中的125ns得到对应的分频比:

死区时间单个分频比十六进制
0~158750~1270~0x7F
16000~31750128~2540x80~0xFE
32000~63000256~5040x100~0x1F8
64000~126000512~10080x1FF~0x3F0

对此,就可以根据这个分频比就可以分出几个层级,并套用上方给出的几个公式。这里需要注意的是,这个DT计算出DTC的值,需要将其拼接在一起。
根据:
1 秒 120 M H z = 8 n s \frac{1秒}{120MHz} = 8ns 120MHz1=8ns
8ns的分片可以得到:

单个分频比死区区间
0~1270~1000ns
128~2541024~2032ns
256~5042048~4032ns
512~10084096~8064ns

而计算方式反推示例:
D T G [ 区 间 ] = 死 区 时 间 ( 比 例 系 数 ∗ 单 个 分 频 比 ) − 固 定 比 例 DTG[区间]=\frac{死区时间}{(比例系数*单个分频比)}-固定比例 DTG[]=()
其中,区间为上述文档中的数据区间,比例系数则为当前的区间比例(1,2,8,16),固定比例为64或者32。

0x30 伪代码

最后自然贴上一段伪代码,虽然加入了较为友好的注释,但是如果不仔细阅读前文估计还是会看的一头雾水…… 而且代码仅仅是伪代码,也就是表明了需要的变量以及一部分必要的流程,但是运行还需要一定的改进。仅供参考!!!!

void TIMER_Init(u16 Period,u16 dead_time,float PWM_Val)
	u16 PerTime,PerPsc,DeadTimeValue;                                                     /* 核心变量,分别是定时器累加值和分频系数以及死区时间 */
	float PreTemp;                                                                        /* 关于分频系数计算,因为精度问题,所以需要浮点运算 */
	float DeadTimeGen = 1000000000 / SystemClock;//时钟频率值		                      /* 晶振周期,一般为固定值 */
	float death_time;                                                                     /* 核心变量,单个分频比 */     
	death_time = dead_time / DeadTimeGen;                                                 /* 单个分频比基数 */
	
	if (death_time > 0 && death_time <= 127)	/* 1倍DTG */                              /* 第一个区间 */
	{                                                                                     
		DeadTimeValue = (u16)death_time;                                                  /* 按照第一个区间定义而得 */
	}                                                                                     
	else if (death_time >128 && death_time <= 254)/* 2倍DTG */                            /* 第二个区间 */
	{                                                                                     /*  */
		DeadTimeValue = 0x80 | (u16)(dead_time /(DeadTimeGen * 2) -64);                   /* 按照第二个区间定义公式而得 */
	}                                                                                     /*  */
	else if (death_time > 256 && death_time <=504)/* 8倍DTG */                            /* 第三个区间 */
	{                                                                                     /*  */
		DeadTimeValue = 0xC0 | (u16)(dead_time / (DeadTimeGen * 8) - 32);                 /* 按照第三个区间定义公式而得 */
	}                                                                                     /*  */
	else if (death_time > 512 && death_time <= 1008)/* 16倍DTG */                         /* 第四个区间 */
	{                                                                                     /*  */
		DeadTimeValue = 0xE0 | (u16)(dead_time / (DeadTimeGen * 16) - 32);                /* 按照第四个区间定义公式而得 */
	}
	else
	{
		printf("OverFlow DeadTime!!,Please check your param,Error Value:%d",dead_time);   /* 因为这样一定会出现没有包括的地区,所以需要提醒别人,查询配置表 */
	}
	PreTemp = 1000000 / Period;                                                           /* 计算出当前的周期,精度0.0 */
	/* 分频系数 */                                                                        
	PreTemp = (SystemCoreClock / 1000000 * PreTemp  / 999) - 1;                           /* 根据上面计算分频系数的方式计算出当前的分频系数 */
	PerPsc = (u16)PreTemp;                                                                /* 人工去除浮点小数 */
		/* 定时器累加值  */                                                               /*  */
	PerTime = 999;                                                                        /* 固定的定时器累加值 */
	/* 占空比--输入例如21.5这样的数字 */                                                  /*  */
	PWM_Val = (PWM_Val * 10);                                                             /* 占空比取千分之一0.1% */


0x40 更多

本文首发自 记:关于输出任意占空比与频率的一种方式——基于STM32单片机,更多文章可进入我的博客详查。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GreenDreamer

如果帮到了你,还望请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值