1、准备材料

开发板(正点原子stm32f407探索者开发板V2.4

STM32CubeMX软件(Version 6.10.0

野火DAP仿真器

keil µVision5 IDE(MDK-Arm

ST-LINK/V2驱动

一台示波器

逻辑分析仪nanoDLA

2、实验目标

使用STM32CubeMX软件配置STM32F407开发板的DAC OUT1实现输出0-3.3V 周期为12.8ms的正弦波形

3、实验流程

3.0、前提知识

由于STM32F407的两个DAC输出通道只能自动生成三角波和噪声波,因此如果想要输出其他的波形可以自己手动定义一个周期内DAC要输出的值,并选择定时器的更新事件作为DAC输出的触发源按顺序输出

这样按照波形采样值的顺序,在每一个触发源到来的时候,手动指定DAC将要输出的值,理论上就可以输出任何我们想要输出的波形,比如正弦波,本实验将以正弦波为例,讲解如何通过DAC的DMA输出正弦波型

当DAC参考电源引脚VREF+接VDDA(3.3V)时,可设置的DAC输出寄存器值范围为0~4095,而DAC的输出范围为0-3.3V,要输出的正弦波sin(x)波形幅值范围为-1~1,因此可以对该波形做一些平移伸缩,将其幅值范围缩放到DAC设置范围0~4095内,变换后的正弦波公式为:y=2047*(sin(x)+1)

在该正弦波形的一个周期0-2pi内平均取128个采样点,然后按照时间先后顺序定义在数组中,每当0.1ms触发源到来的时候,我们就递归的从数组中取出一个值将其设置为DAC的输出值,直到128个采样点全部设置完毕,然后再反复从第一个重新设置,这样就可以大致实现正弦波型

因为需要频繁的从内存取出数据然后写入DAC外设,因此这里比较合适的做法是使用DMA的方式进行,通过上述设置的DAC输出的正弦波形的周期应该为0.1ms*128=12.8ms,正弦波的幅值范围应该为0-3.3V

3.1、CubeMX相关配置

3.1.0、工程基本配置

打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号),选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示

开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示

详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立

3.1.1、时钟树配置

系统时钟使用8MHz外部高速时钟HSE,HCLK、PCLK1和PCLK2均设置为STM32F407能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置

在Pinout & Configuration页面左边功能分类栏目Analog中单击其中DAC

在Mode中勾选OUT1 Configuration

选择TIM6的外部触发事件作为DAC OU1输出的触发源,不选择波形生成模式,因为本实验要生成自定义波形

具体配置如下图所示

单击Configuration中的DMA Settings选项卡对DAC的DMA请求进行设置

单击ADD按键增加DMA请求,这里可选的只有一个DAC1

选择想要使用的DMA Stream,并设置优先级,将DMA请求模式设置为循环模式,外设地址不增加,内存地址递增,数据宽度选择字Word

上述配置如下图所示

3.1.3、外设中断配置

在Pinout & Configuration页面左边System Core/NVIC中勾选DMA1 Stream5 全局中断,然后选择合适的中断优先级即可

3.2、生成代码

3.2.0、配置Project Manager页面

单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示

详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节

3.2.1、外设初始化调用流程

在生成的工程代码主函数中新增了MX_DMA_Init()函数,该函数对DAC使用的DMA1时钟使能,由于启用了该DMA的中断,因此还对中断优先级及使能进行了配置,如下图所示

DAC的初始化调用流程与“STM32CubeMX教程16 DAC - 输出3.3V内任意电压”实验一致,只是因为本实验配置了DMA,因此在HAL_DAC_MspInit()函数中增加了对使用的DAC1 DMA请求的相关配置代码,如下图所示

3.2.2、外设中断调用流程

DMA全局中断事件回调函数为一个函数指针,当使用HAL_DAC_Start_DMA()函数启动DAC传输时,会将DMA全局中断事件回调函数指针指向具体的函数,这里指向了DAC_DMAConvCpltCh1()函数

在DAC_DMAConvCpltCh1()函数中最终调用了DAC OU1 DMA传输完成中断回调函数HAL_DAC_ConvCpltCallbackCh1(),该函数为虚函数,需要用户重新实现

启用DMA的外设中断调用流程可参考“STM32CubeMX教程12 DMA 直接内存读取”实验3.2.2、外设中断调用流程小节,上述具体过程如下图所述

3.2.3、添加其他必要代码

采集正弦波y=2047*(sin(x)+1)的一个周期2pi内n个采样点,并将其定义在一个uint32_t 数组中,笔者这里定义了128个采样点

为什么非要正弦波函数为y=2047*(sin(x)+1)?

因为DAC的输出范围为0~4095,而sin(x)的输出范围为-1~1,因此需要采集的正弦波采样点最好缩放到0-4095范围,这样输出的波形更好显示

源代码如下所示 (注释1)

/*正弦波数据,12bit,1个周期128个点, 0-4095之间变化*/
const uint32_t userWave[] =
{
2047, 2147, 2248, 2347, 2446, 2544, 2641, 2737,
2830, 2922, 3012, 3099, 3184, 3266, 3346, 3422,
3494, 3564, 3629, 3691, 3749, 3803, 3852, 3897,
3938, 3974, 4006, 4033, 4055, 4072, 4084, 4092,
4094, 4092, 4084, 4072, 4055, 4033, 4006, 3974,
3938, 3897, 3852, 3803, 3749, 3691, 3629, 3564,
3494, 3422, 3346, 3266, 3184, 3099, 3012, 2922,
2830, 2737, 2641, 2544, 2446, 2347, 2248, 2147,
2047, 1947, 1846, 1747, 1648, 1550, 1453, 1357,
1264, 1172, 1082, 995 , 910 , 828 , 748 , 672 ,
600 , 530 , 465 , 403 , 345 , 291 , 242 , 197 ,
156 , 120 , 88 , 61 , 39 , 22 , 10 , 2 ,
0 , 2 , 10 , 22 , 39 , 61 , 88 , 120 ,
156 , 197 , 242 , 291 , 345 , 403 , 465, 530 ,
600 , 672 , 748 , 828 , 910 , 995 , 1082, 1172,
1264, 1357, 1453, 1550, 1648, 1747, 1846, 1947
};

在dac.c中重新实现DAC OU1 DMA传输完成中断回调函数HAL_DAC_ConvCpltCallbackCh1(),源代码如下

/*DAC OUT1 DMA传输完成中断回调函数*/
void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac)
{
/*翻转RED_LED引脚状态*/
HAL_GPIO_TogglePin(RED_LED_GPIO_Port,RED_LED_Pin);
}

在main.c文件主函数main中以DMA方式启动DAC输出,源代码如下

HAL_DAC_Start_DMA(&hdac,DAC_CHANNEL_1,userWave,128,DAC_ALIGN_12B_R);
HAL_TIM_Base_Start(&htim6);

4、常用函数

/*以DMA启动DAC输出*/
HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel, const uint32_t *pData, uint32_t Length,uint32_t Alignment) /*停止以DMA启动的DAC输出*/
HAL_StatusTypeDef HAL_DAC_Stop_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel) /*DAC OUT1 DMA传输完成时间中断回调函数*/
void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac)

5、烧录验证

烧录程序,单片机上电后,将示波器的探头挂钩与DAC OUT1引脚PA4相连接,接地环与开发板上的GND引脚连接,将示波器每格电压幅值调节为1.00V,将每格子采集时间调节为10ms,然后开启示波器对DAC OU1输出的波形采集

因为定时器溢出时间为0.1ms,而DMA传输的数据为正弦波一个周期内的128个样本点,因此生成的正弦波周期为128*0.1ms=12.8ms,这与示波器采集到的正弦波波形周期一致,如下图所示为示波器采集到的正弦波形

在DAC OUT1 DMA传输完成时间中断回调函数中翻转了RED_LED(PF9)引脚的状态,经过上述分析知道,传输完成一次所需事件应该为输出正弦波形的周期,也即12.8ms,因此使用逻辑分析仪器采集PF9引脚的状态,发现PF9引脚确实12.8ms翻转一次状态,逻辑分析仪采集的波形如下图所示

6、注释详解

注释1:正弦波数组定义来源 DAC输出正弦波帖子

更多内容请浏览 STM32CubeMX+STM32F4系列教程文章汇总贴

STM32CubeMX教程18 DAC - DMA输出自定义波形的更多相关文章

  1. 【STM32H7教程】第60章 STM32H7的DAC应用之定时器触发实现DMA方式双通道波形

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第60章       STM32H7的DAC应用之定时器触发实 ...

  2. STM32 使用DMA+DAC+TIMER 输出正弦波

    之前已经简单论述过,根据我个人菜鸟的了解与认识,对之前的知识进行整理回顾: DMA:我的理解就是一个通道,或者是一座桥梁.在静态内存到静态内存,或者外设到静态内存间的一个通讯的通道.建立这个通道的好处 ...

  3. python Django教程 之 模型(数据库)、自定义Field、数据表更改、QuerySet API

    python  Django教程  之 模型(数据库).自定义Field.数据表更改.QuerySet API 一.Django 模型(数据库) Django 模型是与数据库相关的,与数据库相关的代码 ...

  4. Directx11教程(18) D3D11管线(7)

    原文:Directx11教程(18) D3D11管线(7) 光栅化阶段(RS)之后,将进入PS/OM阶段. 参考外文资料:http://fgiesen.wordpress.com/2011/07/01 ...

  5. Senparc.Weixin.MP SDK 微信公众平台开发教程(九):自定义菜单接口说明

    上一篇<Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明>介绍了如何通过通用接口获取AccessToken,有了AccessToken,我们就可以来操作 ...

  6. asp.net mvc输出自定义404等错误页面,非302跳转。

    朋友问到一个问题,如何输出自定义错误页面,不使用302跳转.当前页面地址不能改变. 还要执行一些代码等,生成一些错误信息,方便用户提交反馈. 500错误,mvc框架已经有现成解决方法: filters ...

  7. STM32F4_TIM输出PWM波形(可调频率、占空比)

    Ⅰ.概述 上一篇文章关于STM32基本的计数原理明白之后,该文章是在其基础上进行拓展,讲述关于STM32比较输出的功能,以输出PWM波形为实例来讲述. 提供实例工程中比较实用的函数:只需要调用该函数, ...

  8. asp.net mvc输出自定义404等错误页面,非302跳转

      朋友问到一个问题,如何输出自定义错误页面,不使用302跳转.当前页面地址不能改变. 还要执行一些代码等,生成一些错误信息,方便用户提交反馈. 500错误,mvc框架已经有现成解决方法: filte ...

  9. STM32 F4 DAC DMA Waveform Generator

    STM32 F4 DAC DMA Waveform Generator Goal: generating an arbitrary periodic waveform using a DAC with ...

  10. [译]Vulkan教程(18)命令buffers

    [译]Vulkan教程(18)命令buffers Command buffers 命令buffer Commands in Vulkan, like drawing operations and me ...

随机推荐

  1. 使用 Guava Retry 优雅的实现重试机制

    王有志,一个分享硬核Java技术的互金摸鱼侠 加入Java人的提桶跑路群:共同富裕的Java人 大家好,我是王有志.今天我会通过一个真实的项目改造案例和大家聊一聊如何优雅的实现 Java 中常用的的重 ...

  2. 【总结】MySQL使用优化

    一.表设计 1.避免使用null  占用额外空间.索引无效.检索麻烦 2.能用int 不用varchaer,能用varchaer 不用text 3.int 最好给默认值 0 .varchar empt ...

  3. 怎么在Android项目中导入ffmpeg库?

    1.前言 在这里我以导入静态库(.a)为例进行分析,动态库(.so)是类似的.在导入前,各位要先编译好ffmpeg库,需要注意的是在编译的时候要开启交叉编译,目标平台为Android,其他平台的库(w ...

  4. Cocos-JS HTTP网络请求

    网络结构 网络结构是网络构建方式,目前流行的有客户端服务器结构(C/S结构)和点对点(P2P)结构网络. 客户端服务器结构(C/S结构) 这种结构又被称为Clicent/Server结构,它是一种主从 ...

  5. 解决Tensorflow2.0出现:AttributeError: module 'tensorflow' has no attribute 'get_default_graph'的问题

    问题描述 在使用tensorflow2.0时,遇到了这个问题: AttributeError: module 'tensorflow' has no attribute 'get_default_gr ...

  6. JNA入门(一)

    JNA入门,代码在github写得明明白白:https://github.com/java-native-access/jna/blob/master/www/GettingStarted.md 一. ...

  7. js文字转语音播放SpeechSynthesisUtterance

    文字转语音 SpeechSynthesisUtterance是HTML5中新增的API,用于将指定文字合成为对应的语音 function sayTTS(content) { const synth = ...

  8. KubeEdge@MEC:Kubernetes容器生态与5G的结合

    摘要:边缘计算技术快速发展,5G MEC边云协同成为最新的发展趋势. 前言 边缘计算技术快速发展,5G MEC进入商业部署快车道,边云协同成为MEC的普遍诉求,KubeEdge社区洞悉这一趋势,按照C ...

  9. 大数据集群跨多版本升级、业务0中断,只因背后有TA

    摘要:2021年4月21日,中国太平洋保险集团联合华为云完成了全球首例大数据集群跨多版本的大数据集群滚动升级. 本文分享自华为云社区<华为云FusionInsight助力太保跨多版本升级业务0中 ...

  10. 教你实现一个朴实的Canvas时钟效果

    摘要:今天教大家写一个canvas的时钟案例,效果可能看起来比较简单,没有那些花里胡哨的. 本文分享自华为云社区<如何实现一个朴实无华的Canvas时钟效果>,作者: 北极光之夜.. 一. ...