当前位置:首页 > 工业控制 > 电路设计项目集锦
[导读]本项目是我们课程BCA143:裸机编程的第9次实验。在本次实验中,我们的目标是编写一个基于STM32F407XX的裸机RT Spark程序,该程序将PA4引脚上的DAC组件用于生成信号,并通过DMA(直接内存访问)对DAC进行数据传输。我们需要生成方波、斜坡波和正弦波信号,并在示波器上观察其波形。

本项目是我们课程BCA143:裸机编程的第9次实验。在本次实验中,我们的目标是编写一个基于STM32F407XX的裸机RT Spark程序,该程序将PA4引脚上的DAC组件用于生成信号,并通过DMA(直接内存访问)对DAC进行数据传输。我们需要生成方波、斜坡波和正弦波信号,并在示波器上观察其波形。

工作原理

该项目通过利用STM32F407XX微控制器内置的DAC(数模转换器)功能来实现。如下图所示,该功能在STM32F407XX数据手册中的微控制器方框图中体现。

因此,我们将使用 DMA1(直接内存访问)来通过 DAC1 发送数据。如下面的框图所示,DMA1 与 DAC1 当前所连接的 AHB/APB1(高级外设总线 1)在物理上是直接相连的。

我们还使用了一个定时器组件TIM6,该组件在下方的方框图中也有所标注。它与DAC直接连接到同一总线,如下图所示。你可以追踪总线线路,发现TIM6和DAC1是相互连接的。TIM8也是一个基本的定时器,因此我们无需额外配置其他功能。这个定时器仅通过TRGO触发输出来触发DAC即可。

当这三种组件协同工作时,我们现在就可以使用MCU中的DAC组件生成信号了。

项目随后将使用C语言代码输出不同形式的方波、正弦波和斜坡波DAC电压。

本项目所采用的整个系统流程如下图所示

流程显示,在电源开启或复位后,系统会初始化HAL、系统时钟、GPIO、DMA、DAC和TIM6的配置。接下来,在我们的用户代码部分,我们启动了TIM6定时器,然后调用tone_play(WAVEFORM),其中WAVEFORM将是我们稍后定义的枚举类型,用于表示SQUARE、RAMP和SINE波形。在tone_play函数内部,它会先停止所有请求,然后根据我们想要的波形创建新的请求配置,从而重置DAC。

如上代码所示,我们使用 switch 语句来检查并初始化对应所需波形的正确查找表(LUT)。该 LUT 只是一个用于存储发送到 DAC 以触发特定波形所需数值的查找表数组。

之后,我们的代码进入 while(1) 循环。但由于代码将由 TIM6 触发以生成 DAC 输出波形,因此在循环中我们不会执行任何操作。

在下图所示中,定义了TIM6定时器的流程。首先检查ARR是否已大于9或等于9(计数器从0开始计数),如果满足条件,则向DAC发送TRGO脉冲信号;否则,仅递增ARR计数器,直到达到阈值并再次触发。

一旦发送TRGO脉冲,它将从波形查找表(Waveform LUT)数组中读取1字节数据,然后通过DMA控制器将其写入DAC寄存器以输出。接着,由于定时器已触发执行且ARR值已达到或超过9,因此会重置ARR计数器。

因此,当DAC寄存器被写入时,它会将数据输出到我们的DAC引脚PA4。该引脚随后将通过示波器进行监测,之后在我们完成所有设置后,结果将会显示出来。

软件设置

MCU 配置设置

为了设置本项目所需的软件环境,我们将使用 STM32CubeMX 来生成 MCU 的基础配置模板,然后在 STM32CubeIDE 中用于编程我们的 RT Spark 1 开发板。

首先,我们需要打开 STM32CubeMX 并创建一个新项目。

打开后,您的屏幕应显示如下图所示的内容。

转到“文件”>“新建项目”以创建新项目

之后,应该会弹出一个窗口,这就是项目创建界面。

我们需要使用 RT Spark 1 的微控制器型号,即 STM32F407ZGT6。用该型号在 STM32CubeMX 软件中搜索并选择对应的 MCU。

选定确切的MCU零件号后,点击“新建项目”窗口右上角的“开始项目”按钮。

然后你应该会看到下方的屏幕,这表示STM32CubeMX项目已成功创建。

GPIO 配置

我们将首先配置本项目中需要使用的GPIO。

以下是我们本项目将使用的GPIO引脚列表。

•PA4 - DAC_OUT1 模式,这是我们将连接示波器一个通道的引脚。它是 DAC1 的输出端,用于输出生成的波形。

由于这是一个非常基础且以软件为主的项目,目前我们只使用一个GPIO引脚。

我们先将 PA4 配置为 DAC_OUT1 模式下的输出引脚。点击引脚 PA4,或在屏幕底部输入内容进行搜索。

在将DAC设置为正确模式后,我们就可以进入系统核心 > GPIO 来检查全局GPIO设置。

如您所见,PA4 设置为模拟输出模式,信号引脚为 DAC_OUT1。以上就是我们完成这个项目所需的一切。

现在,让我们在 STM32CubeMX 中配置其他内容。

我们从时钟配置开始。为了获得更平滑的波形,以便后续观察,我们需要让时钟以尽可能高的速度运行。为此,请进入“时钟配置”选项卡。

在此标签页中,找到 HCLK 输入框并输入 168。这将使我们的 MCU 运行在最大速度 168MHz 上。

在输入框中输入168后,按下键盘上的回车键,应该会弹出如下图所示的提示信息。

系统将提示您使用其他资源,因为时钟配置需要相互依赖。更改HCLK时,还需相应调整其他设备的频率。要自动完成此操作,只需在弹出的确认窗口中按回车键或点击“确定”,系统便会自动为时钟配置找到合适的解决方案。

完成之后,我们将开始配置DAC外设。为此,请按如下图所示进入“模拟”>“DAC”。

请确保勾选 OUT1 配置复选框以启用 DAC1。然后在窗口底部勾选参数设置,务必按照上图所示进行设置。

•输出缓冲区 - 启用

•触发器 - 定时器6 触发输出事件

•波形生成模式 - 已禁用

应按照上述方式配置,以确保DAC正常工作。

接下来,我们将配置DMA(直接内存访问)以向DAC外设写入数据。为此,请转到屏幕底部,切换到DMA设置选项卡进行配置。

当你首次看到此菜单时,DMA设置下的DAC列表将完全为空。点击“添加”按钮,然后选择DAC1。接着将配置设置为以下内容:

•方向:内存到外设

•模式:循环(使波形自动无限重复)

•数据宽度:将外设和内存均设置为字节(因为我们的实验手册规定DAC使用8位分辨率,而非12位)。

•增量地址:我们仅检查“内存”(即读取我们的数组),并保持“外设”未选中(即始终向单个DAC寄存器写入数据)。

一旦DAC1和DMA正确配置,我们将进入本项目中的定时器6配置。

要配置定时器,必须进入“定时器” > “TIM6”,如下图所示。

首先,勾选顶部的“已激活”复选框,以启用定时器6外设。启用后,请在参数设置窗口底部进行勾选。

我们必须确保定时器6按上图所示进行配置。

在参数设置中,我们需要设定速度。我们希望每秒更新DAC 100,000次,即频率为100kHz。由于APB1为84MHz,我们采用以下配置:

•预分频器:84 - 1(将时钟降低到1MHz。)

•计数周期(自动重载寄存器):10 - 1(每10个时钟周期触发一次事件,使我们获得精确的100kHz。)

•触发事件选择 TRGO:选择更新事件(这是发送到DAC的实际脉冲)。

现在,我们进入如下所示的项目经理选项卡。

我们将为项目命名并设置目录。之后,由于要使用 STM32CubeIDE 编写程序,必须将工具链/IDE 设置为 STM32CubeIDE。点击窗口右上角的“生成代码”按钮,即可在指定目录下生成项目。

项目生成后,将显示“项目已成功生成”的提示信息。当出现此提示时,我们即可进入下一步操作。

现在,既然我们已经完成了STM32CubeMX的配置部分,就可以进入程序代码了。

程序代码设置

现在我们打开在STM32CubeMX中生成的项目到STM32CubeIDE。为此,先打开IDE,然后进入“文件”>“从文件系统打开项目”……

现在应该会弹出一个新窗口,用于导入项目目录。

请确保选择 STM32CubeMX 生成项目所在的文件夹,然后在导入窗口中勾选列表中的复选框,最后点击“完成”。此时项目应该已成功导入到 IDE 中。

现在,导入项目后,我们打开项目资源管理器面板中的“项目名称”,然后在“核心 > 源文件 > main.c”下打开 main.c 文件。

打开 main.c 后,我们现在就可以开始编写使项目正常运行的代码了。

现在我们从枚举和定义开始。首先,在 main.c 中找到 BEGIN USER CODE PTD 代码注释,然后我们将把以下代码放入其中:

现在我们已使用枚举定义了波形类型,并设置了查找表大小为100。接下来我们将进入下一个部分,即“USER CODE BEGIN PV”。找到“USER CODE BEGIN PV”这一行,在其内部使用以下代码:

现在我们已经定义了方波、斜坡波和正弦波的查找表。接下来,进入下一个部分——用户代码中的函数定义。我们将在此处定义 tone_play() 函数。为此,请找到 USER CODE BEGIN 0 部分,并插入以下代码:

在设置好主代码后,我们现在将配置代码的最后部分,即位于主函数中的“USER CODE BEGIN 2”。

为此,请找到 USER CODE BEGIN 2 部分,并将以下代码放入其中:

在我们的用户代码开始2中,我们已将tone_play()函数设置为默认生成RAMP波形。稍后在测试时可以看到这一点。

由于我们已经完成了代码,现在可以将其编译并烧录到RT Spark 1开发板上。为此,我们需要执行一些额外的步骤。

首先,在项目资源管理器中右键单击项目名称,然后选择“以...运行”>“1 个 STM32 C/C++ 应用程序”。

现在将弹出一个“以...运行”配置窗口。请勿更改任何内容,直接点击“确定”按钮即可。

配置已经自动设置好了,我们只需将项目配置为STM32应用程序,以便将其烧录到我们的RT Spark 1开发板上。

配置完“以运行身份”设置后,我们就可以通过工具栏点击锤子图标来构建并烧录代码到板子上。

构建成功且无错误后,应显示“Build Finished”。构建完成后,点击工具栏中播放图标旁边的向下箭头图标,选择要烧录到板上的STM32应用程序。请确保RT Spark 1已通过USB-C线缆连接。

代码烧录完成后,恭喜!现在我们可以开始测试,并使用示波器查看生成的波形。

测试

为了测试和可视化我们生成的波形,首先需要将示波器的一个通道连接到 DAC_OUT1 引脚(即 PA4)。同时,请别忘了用探头的黑色鳄鱼夹夹住 RT Spark 1 开发板上的任意金属点,或将探针的 GND 引脚接地。探针需要一个 GND 参考,该参考应为 RT Spark 1 板的 0V 电平。

在我的情况下,CH2 是我连接到 PA4 的通道,然后将黑色鳄鱼夹的 GND 接到一根跳线,再连接到 RT Spark 1 的 GND 引脚。启动 RT Spark 1 后,应该能看到 RAMP 波形。

视频1:示波器上的阶梯波

如上视频所示,斜坡波已在示波器中清晰呈现。我已调整了伏特/格和时间旋钮,以便精确观察我们的DAC所生成的斜坡波。

现在,我们将尝试下一个波形,即方波。为此,我们只需更改在 tone_play() 函数中传入的枚举值即可。

如上图所示,我们已将 tone_play() 函数参数传递的枚举值从 RAMP 更改为 SQUARE。接下来需要重新构建项目,并再次将其烧录到 RT Spark 1 开发板上。

我们应能通过 DAC_OUT1(即 PA4 引脚)看到由 DAC 生成的方波。

视频2:示波器上的方波

如上视频所示,SQUARE波已在同一PA4DAC_OUT1引脚上的示波器中成功读取。这意味着我们用于SQUARE和RAMP波的代码均正常工作。

现在,我们进入代码中最后一个波形,即正弦波(SINE)。要将DAC输出设置为正弦波,我们需要再次修改tone_play()函数的参数,将其从SQUARE改为SINE。

如上图所示,我们已将传递给 tone_play() 函数的枚举值修改为 SINE。要查看结果,只需重新构建项目,然后将其烧录回开发板即可。现在,我们应能观察到示波器输出的是正弦波。

视频3:示波器上的正弦波

如上视频所示,我们已成功生成了正弦波形。

这意味着我们的DAC波形发生器代码已完全正常运行,没有问题。现在我们可以根据实验室指南中教授提出的问题,进一步分析这些示波器读数的含义。

分析与解读

方波

1. 最低输出电压是多少?

答:DAC对方波的最小输出电压为0V。如上图31所示,Va为-52.8mV,这就是我们的电压最低值。

但为什么是 0V 而不是 -52.8mV?这是因为示波器电压游标显示的数值是基于显示屏上图形的偏移位置。这意味着我们需要将显示屏最下方的图形实际偏移,才能使 Vb 为 0V。此外,RT Spark 1 或 STM32F407XX 没有输出负电压的能力。

2. 最大输出电压是多少?

答:DAC对方波的最大输出电压为3.30V。如上图31所示,Vb为3.25V,这并非我们的电压上限。由于我们的图表存在偏移,因此必须用Va减去Vb,从而得到ΔV为3.30V。该最大输出电压也处于STM32F407XX可安全输出的电压范围内。

3. 输出信号的上升时间是多少?

答:方波的上升时间约为496.0微秒,换算成纳秒时大约为496000纳秒。如上图32所示,可看到ΔT读数为496.0微秒。蓝色垂直线是放置在信号上升沿和下降沿之间的时间光标线,用于测量方波的上升时间。该数值也是近似的,因为示波器读数每次都会有所变化。

4. 输出信号的下降时间是多少?

答:方波的下降时间约为504.0μs,换算成纳秒时大约为504000ns。如上图33所示,可看到ΔT读数为504.0μs。蓝色垂直线是放置在信号上升沿和下降沿之间的时间光标线,用于测量方波的下降时间。该数值也仅为近似值,因为示波器读数每次都会有所变化。

5. 输出信号的周期是多少?

答:输出信号的周期在转换后恰好为1000.0微秒,即1毫秒。该值通过将上题第3问的答案中测得的高电平时间(496.0微秒)与上题第4问的答案中测得的低电平时间(504.0微秒)相加得出。1毫秒的周期确认STM32F407XX MCU正生成精确的1千赫频率,这与我们的软件设计完全一致。

Ramp Wave

1. 为什么斜坡波的上升沿不平滑?DAC具有8位分辨率,但产生的波形却呈现出锯齿状。

答:尽管DAC以8位分辨率运行,可输出256个不同的电压级别,但由于微控制器无法输出连续的斜线,因此波形会呈现锯齿状。它只能输出平坦的离散台阶。

在我们的项目代码中,我们定义了一个仅包含100个数据点的数组(LUT_SIZE),用于绘制整个波形。由于定时器6以100 kHz的频率计时,DAC会从数组中取出一个数值,设置相应的物理电压,并保持该电压完全恒定,持续精确的10微秒,然后转到下一个数值。此外,为了在100步内达到255,数组会跳过某些数值(如0、2、5、7、10……)。示波器上我们看到的锯齿状图形,正是DAC在时间上持续保持这些被跳过的离散电压电平的视觉表现。

2. 如何在硬件中平滑上升边缘?

答案:我们可以通过在DAC_OUT1引脚PA4上添加一个模拟RC低通滤波器来平滑硬件上的锯齿边缘。通过将一个简单的电阻与信号串联,并将电容连接到地,电容就像一个小型、响应迅速的电池。电压不再瞬间急剧上升呈90度台阶状跳跃,而是缓慢地吸收和释放能量。这种物理的充放电循环能够平均化这些突变,将锯齿状的阶梯转化为平滑连续的斜坡。

3. 如何在软件中平滑上升的边缘?

答案:我们可以通过提高采样率和位分辨率来在软件中平滑波形。

增加数据点数(采样率):将100个数据点的数组改为1000个数据点的数组,并将定时器6的时钟频率提升至1 MHz。这使得每个步长的水平宽度变得极其微小。

增加位深度(分辨率):STM32F407XX DAC硬件原生支持最高12位分辨率。通过将软件配置从DAC_ALIGN_8B_R更改为DAC_ALIGN_12B_R,MCU将3.3V划分为4,096个垂直分段,而非仅256个。这使得每个分段的垂直高度几乎无法被肉眼察觉。

正弦波

1. 尝试代码以确定可生成的最大频率正弦波。

答:假设我们继续使用100点阵列,生成的最高纯净正弦波频率约为10 kHz至20 kHz。

通过降低TIM6自动重载寄存器(ARR)以加快定时器速度,所获得的最大纯净正弦波频率约为10 kHz。超过此限制后,波形会变形为锯齿状三角波,并出现振幅衰减。这一物理极限源于STM32F407XX DAC的硬件最大转换速率仅为每秒1至2百万个采样点(MSPS)。若在每个周期内生成的数据点数超过100个,则会超出DAC的物理稳定时间。

项目结论

本实验室项目成功展示了如何利用裸金属架构合成连续模拟信号。通过使用STM32F407XX的硬件定时器(TIM6)、直接内存访问(DMA)以及数模转换器(DAC),精确地生成了方波、斜坡波和正弦波。此外,借助示波器对这些波形进行分析,揭示了数字到模拟转换中的实际限制,例如由于离散采样率引起的阶梯效应,以及DAC最大1 MSPS转换速率所决定的物理频率极限。

该项目展示了数字软件阵列与现实世界模拟硬件限制之间的差距,并成功弥合了这一鸿沟。

本文编译自hackster.io

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
换一批
延伸阅读

我喜欢第一版的外壳设计,也欣赏第二版的便携性。这款新版本外观与第一版相似。内部配备了一个UPS模块,可使用18650 3.7V电池供电,也可通过USB-C电源供电。即使在外部供电时,设备关闭状态下仍能为电池充电。

关键字: 函数发生器 Arduino Nano AD9833

在电子技术领域,RC桥式振荡电路因结构简单、成本低廉、波形质量较好,广泛应用于信号发生器、音频设备、自动控制等低频信号生成场景,其输出正弦波的幅值稳定性直接决定了电子设备的工作精度和可靠性。然而在实际应用中,受放大电路非...

关键字: RC桥式 振荡电路 正弦波

有的函数发生器还具有调制的功能,可以进行调幅、调频、调相、脉宽调制和VCO控制。在《振荡器》的教程中,我们深入了解了振荡器的本质与功能。

关键字: 函数发生器

正弦波振荡器会以预设的频率无限期地产生输出波形;也就是说,它会持续不断地运行。雷达等设备中的许多电子电路要求振荡器在特定时间内开启,并在之后的时间保持关闭状态,直到需要时再开启。此类电路被称为脉冲振荡器或振铃振荡器。它们...

关键字: 脉冲振荡器 谐振电路 正弦波

是德科技京东自营旗舰店在本月9日重磅开业,开业期间(9日至11日每天10:00)推出"限时秒杀"活动,多款高端测试仪器以超值优惠价格回馈广大科研工作者和工程师。本次活动精选三款明星产品:EDU36311A三路输出台式电源...

关键字: 示波器 台式电源 函数发生器

在电子技术领域,RC 桥式振荡电路作为一种常用的正弦波振荡电路,被广泛应用于信号发生器、音频设备等众多电子设备中。其输出稳定的正弦波信号,对设备的正常运行起着关键作用。然而,实际应用中,RC 桥式振荡电路的稳幅效果常常受...

关键字: RC 桥式 振荡电路 正弦波

Spwm的产生可以分为软件方法和硬件方法,硬件方法通过硬件产生一路三角波一路正弦波,经过一个比较器比较正弦波幅值与三角波幅值的关系即可得到spwm波。

关键字: 步进电机 正弦波

函数发生器是一种多波形的信号源。它可以产生正弦波、方波、三角波、锯齿波,甚至任意波形

关键字: 正弦波 方波

频率电压转换器将频率或脉冲转换成成比例的电输出,如电压或电流。它是发生重复事件的机电测量的重要工具。因此,当我们在频率电压转换器电路中提供一个频率时,它将提供一个成比例的直流输出。在这里,我们使用KA331集成电路来构建...

关键字: KA331 集成电路 频率电压转换器 函数发生器

函数发生器或波形发生器是电子学的一个组成部分,用于产生各种波形,如正弦波、方波、锯齿波等。我们已经设计了正弦波产生电路、方波产生电路和锯齿波产生电路。现在,在本教程中,我们将向您展示如何使用运算放大器和一些基本组件设计三...

关键字: 运算放大器 函数发生器 波形发生器 LM358
关闭