STM32CubeMX教程18 DAC - DMA输出自定义波形
1、准备材料
STM32CubeMX软件(Version 6.10.0)
keil µVision5 IDE(MDK-Arm)
一台示波器
逻辑分析仪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系列教程文章汇总贴
热门相关:重生隐婚:Hi,高冷权少! 唐土万里 顺明 顺明 抗日之全能兵王