朋友您好!在过去的文章中,我
谈到了我的项目 及其软件部分 。 在本文中,我将告诉您如何为4个通道(两个模拟通道和两个PWM通道)制作一个简单的信号发生器。

模拟通道
STM32F415RG微控制器在两个独立的通道中
集成了一个12位
DAC (数模)转换器,从而可以产生不同的信号。 您可以将数据直接加载到转换器的寄存器中,但这不适用于生成信号。 最好的解决方案是使用一个阵列,在该阵列中产生一个信号波,然后使用来自计时器和DMA的触发器来运行DAC。 通过更改计时器的频率,可以更改生成信号的频率。
“
经典 ”波形包括:正弦,曲折,三角形和锯齿形。

在函数中,您需要将指针传递给数组的开头,数组的大小,最大值和所需的波形。 调用之后,该阵列将充满所需形状的一个波形的样本,您可以启动计时器以定期将新值加载到DAC中。
该微控制器中的DAC有一个局限性:典型的建立时间(将
新值加载到DAC中并在输出出现时的时间 )为3 ms。 但并非一切都那么简单-这次是最大的时间,即 从最小值更改为最大值,反之亦然。 尝试撤回弯道时,这些乱蓬蓬的正面非常清晰可见:

如果输出正弦波,则由于波形的原因,前部的障碍不再那么明显。 但是,如果频率增加,则正弦信号变成三角信号,并且随着频率的进一步增加,信号幅度减小。
以1 KHz( 振幅90% )产生:
以10 KHz( 振幅90% )产生:
以100 KHz( 振幅90% )产生:
步骤已经可见-因为新数据以4 MHz的频率加载到DAC中。
此外,锯齿波信号的后沿杂乱,信号从下方未达到其应有的值。 这是因为信号没有时间达到指定的低电平,并且软件正在加载新值
以200 KHz( 振幅90% )产生:
在这里,您已经可以看到所有波浪如何变成三角形。
数字频道
使用数字通道,一切都变得更加简单-几乎在任何微控制器中都有计时器,可让您将PWM信号输出到微控制器的输出。 最好使用32位定时器-在这种情况下,您无需对定时器预定时器进行计数,只需将周期加载到一个寄存器中,并将所需的占空比加载到另一个寄存器中。
使用者介面
决定将用户界面组织为四个矩形,每个矩形均带有输出信号,频率和幅度/占空比的图片。 对于当前选择的通道,文本数据显示为白色,其余显示为灰色。

决定对编码器进行控制:左边的一个负责频率和当前选择的通道(
按下按钮时改变 ),右边的一个负责振幅/占空比和波形(
按下按钮时改变 )。
此外,还实现了对触摸屏的支持-单击非活动通道时,它将变为活动状态;单击活动通道时,波形将发生变化。
当然,DevCore用于完成所有这一切。 用于初始化用户界面和更新屏幕上的数据的代码如下所示:
屏幕更新代码 for(uint32_t i = 0U; i < CHANNEL_CNT; i++) { ch_dsc[i].img.SetImage(waveforms[ch_dsc[i].waveform]); snprintf(ch_dsc[i].freq_str_data, NumberOf(ch_dsc[i].freq_str_data), "Freq: %7lu Hz", ch_dsc[i].frequency); if(IsAnalogChannel(i)) snprintf(ch_dsc[i].duty_str_data, NumberOf(ch_dsc[i].duty_str_data), "Ampl: %7d %%", ch_dsc[i].duty); else snprintf(ch_dsc[i].duty_str_data, NumberOf(ch_dsc[i].duty_str_data), "Duty: %7d %%", ch_dsc[i].duty);
实现了按钮单击的一个有趣的实现(它
是一个在其上绘制其余元素的矩形 )。 如果看了一下代码,您应该已经注意到这样的事情:
ch_dsc [i] .box.SetCallback(&Callback,this,nullptr,i); 循环调用。 这是按下按钮时将调用的回调函数的工作。 将以下内容传递给该函数:类的静态函数的静态函数的地址,this指针以及两个将传递给回调函数的用户参数-一个指针(
在这种情况下不使用-传递nullptr )和一个数字(
发送通道号 )。
我在大学里记得这样的假设:“
静态函数无法访问非静态班级成员 。” 所以这是
不正确的 。 由于静态函数是类的
成员,因此如果它具有指向该类的链接/指针,则它
可以访问该类的所有成员 。 现在看一下回调函数:
在此函数的第一行中,出现“
magic ”,之后您可以访问该类的任何成员,包括私有成员。
顺便说一下,此函数在另一个任务(
渲染屏幕 )中被调用,因此在此函数内部您需要注意同步。 在这个简单的“
两晚 ”项目中,我没有这样做,因为在这种特殊情况下它不是必需的。
生成器源代码上传到GitHub:
https :
//github.com/nickshl/WaveformGenerator现在,
DevCore已分配给单独的存储库,并作为子模块包含在内。
好吧,为什么我需要一个信号发生器,它会在下一篇文章(
或以下文章
之一 )中出现。