ESE模块9 PWM 脉冲宽度调制
在mySTM32 light板上调光LED。脉冲宽度调制PWM是一种重要的技术,用于生成伪模拟值。通过相对较低的成本,例如使用一个RC电路,也可以从这个信号中生成真正的模拟值。 通常情况下,这并不是必需的,就像我们将在这个例子中真正看到的那样。实际上,我们应该说看不到。我们的眼睛不会察觉PWM信号由许多脉冲组成。PWM不仅用于驱动LED,还用于驱动直流电机、步进电机、伺服电机、逆变器、电加热器、电磁阀等,可能的应用案例列表相当长。因此,所有现代微控制器都具有使用硬件模块生成PWM信号的能力。定时器非常适合执行此任务。
任务
准备
进行以下准备工作:
- 创建一个新的类图
- 目标语言ARM C ++
- 目标平台STM32F042 mySTM32板灯HAL
- 为PEC应用程序(XMC,STM32,AVR)的下载图模板应用程序框架
- 为STM32F0分配驱动程序包
- (可选)分配模板stm32F042_48Mhz
解决路径
任务是对LED进行平滑的渐变控制,让人眼感觉LED在渐亮和渐暗。为此,需要生成相应的PWM信号。PWM信号不是模拟信号,而是一系列脉冲,脉冲宽度不同。每个脉冲始终对应于完整的可用电压,即在我们的情况下是3.3V,脉冲之间的间隔相应为0V。高电平和低电平之间的比例产生了所需的有效电压。
几乎所有现代微控制器都具有定时器生成一个或多个PWM信号的功能。为此,硬件和软件开发人员需要在数据手册中了解可能的定时器、PWM通道和引脚分配。硬件PWM不能在任何引脚上使用。我们可以使用mySTM32 light参考卡来了解这些信息。mySTM32 light Referenzkarte
对于引脚B0,可以使用TIMER 3通道3。 在PEC框架中,我们可以使用库模块PecPwmChannel。该模块具有使LED变暗所需的所有功能。
UML设计图,帮助理清逻辑思维。
必须将特定的硬件定时器3、通道3、引脚B0相互连接。
MERKE: PWM = Timer + Channel + Pin 注意:PWM =计时器+通道+引脚
实现
实现应包括上述设计图中描述的元素。另外必须将Timer3,Channel3和PinB0的特定硬件连接。在资源管理器中搜索相应的元素,拖放到图中,并将其连接到Led类的Pwm。为使Led灯缓慢的变亮或变弱,我们需要一个变量作为计数器,在类控制器的属性里添加duty。由于库模块将PWM信号控制在0到1000之间,因此我们至少需要一个16位的值。使用以下表示形式可以帮助实现设计:
在这个例子中,需要初始化和启动具有所需PWM频率的定时器。PWM频率对于眼睛来说不应低于60 Hz,对于耳朵来说不应低于200 Hz(在实际应用中,功放会发出嗡嗡声),但也不应该太高。过高的频率可能会导致不希望的效果,取决于导线长度和被驱动的器件。因此,我们应该避免将频率设置得太高。请在Controller类的onStart()操作中补充以下代码。
Controller::onStart():void// boot sequence after start SysTick // Initialisierung PWM Channel // startet Timer mit gewünschter PWM Frequenz pwm.configHz(1000);
代码解释:
1. pwm.configHz(1000);:配置PWM通道的频率为1000 Hz。这意味着PWM信号将以1000赫兹的频率发出。
首先,我们开发一个简单的解决方案,以相对缓慢的速度增加PWM信号的占空比。为此,我们使用计数变量duty。PecPwmChannel库模块的setDuty(duty)操作预期的值范围是从0(LED关闭)到1000(LED最大亮度)。因此,计数器可以从0到1000递增。通过添加一个小的延迟,我们确保缓慢增加的过程确实足够慢,以供眼睛感知。请将以下代码记录在Controller类的onWork()操作中。
Controller::onWork():duty++; if (duty>=1000) { duty=0; } pwm.setDuty(duty); waitMs(1);
代码解析:
1. duty++;:增加duty变量的值,使PWM的占空比逐渐增加。
2. if (duty>=1000):检查duty变量是否大于等于1000。
- 如果是,则执行以下操作:
- 将duty变量重置为0,以便重新开始PWM的占空比增加过程。
3. pwm.setDuty(duty);:设置PWM通道的占空比为当前duty变量的值。这确定了LED的亮度。
4. waitMs(1);:等待1毫秒。这个语句是为了控制PWM信号变化的速度,使其不要太快。
测试
另一种变体
第一个简单的解决方案生成以下波形:
通过信号线波,可以很好地看到LED的闪烁。 下一个解决方案是实现LED的缓慢调光。 我们需要生成以下波形:
因此必须使用计数器,在上升之后,下降的信号曲线也随之变化。
更改Controller类的onWork()操作的代码,如下所示:
Controller::onWork():voidduty++; if (duty<1000) { pwm.setDuty(duty); } else if (duty<2000) { pwm.setDuty(2000-duty); } else { duty=0; } waitMs(1);
解析代码:
1. duty++;:递增duty变量的值,以便控制PWM的占空比。
2. if (duty<1000):检查duty变量是否小于1000。
- 如果是,则执行以下操作:
- 使用当前的duty值设置PWM通道的占空比。
3. else if (duty<2000):如果duty大于或等于1000,但小于2000,则执行以下操作:
- 使用2000减去duty的值来设置PWM通道的占空比。这样做的效果是,LED的亮度会在duty达到1000后逐渐减小。
4. else:如果duty大于等于2000,则执行以下操作:
- 将duty重置为0,以便重新开始PWM的占空比调整过程。
5. waitMs(1);:等待1毫秒。是为了控制PWM信号的变化速度,使其不要太快。
创建,传输和再测试此应用程序。
可以清楚地看到LED的变化。
但是,即使是这种信号波形对我们的眼睛来说也并不是非常舒适的。这是因为我们对亮度的感知不是线性的。在低亮度范围内,我们的眼睛可以很好地感知到亮度的小变化。
但是从至少50%开始,我们几乎无法感知到亮度的变化。一种解决方法是将信号波形不是线性地而是指数地调整。这可能看起来是这样的,如下图信号曲线所示:
使用公式POTENCE(X,Y),可以在Excel中以1000个步骤实验确定所需的信号曲线。 结果大约为POTENCY(1.00693; step)。相应的C / C ++函数是pow(x,y),可以在#include“ math.h”中找到。 为此,必须在Controller类中进行相应的输入。选择控制器类,然后在上下文菜单(鼠标右键)中选择菜单项“定义…”。 在“声明/实现”对话框中,添加以下内容:
现在我们可以使用math.h中的函数pow(x,y)。 更改Controller类的onWork()操作的代码,如下所示:
这段代码实现了一个呼吸灯效果,使用了指数函数作为PWM的占空比。下面是代码的解析:
1. duty++;:递增duty变量的值,以便控制PWM的占空比。
2. if (duty<1000):检查duty变量是否小于1000。
- 如果是,则执行以下操作:
- 使用pow函数计算以1.00693为底的duty次幂,并将结果作为PWM的占空比。这样做的效果是,LED的亮度会根据duty的增加呈指数增加。
3. else if (duty<2000):如果duty大于或等于1000,但小于2000,则执行以下操作:
- 使用pow函数计算以1.00693为底的(2000-duty)次幂,并将结果作为PWM的占空比。这样做的效果是,LED的亮度会根据duty的减小呈指数减小。
4. else:如果duty大于等于2000,则执行以下操作:
- 将duty重置为0,以便重新开始PWM的占空比调整过程。
5. waitMs(1);:等待1毫秒。是为了控制PWM信号的变化速度,使其不要太快。
创建,传输和测试此应用程序变体。
现在可以清楚地看到LED柔和灯光变化,LED呼吸灯。
总结
- 1.创建并打开类图
- 2.选择用于PEC应用程序的图模板,为STM32F0加载并插入驱动程序包
- 3.在资源管理器/导航器中找到所需的块并拖到图中
- 4. 聚合类
- 5.创建类的属性和操作
- 6.将类和模板组装到组件中
- 7.在操作中创建必要的源代码
- 8.在类图中创建并刻录ARM应用程序
- 9.配置和使用SiSy ControlCenter
视频总结