logo资料库

STM32 DAC DMA 绝对好用.pdf

第1页 / 共13页
第2页 / 共13页
第3页 / 共13页
第4页 / 共13页
第5页 / 共13页
第6页 / 共13页
第7页 / 共13页
第8页 / 共13页
资料共13页,剩余部分请下载后查看
零死角玩转 STM32F103—霸道 第39章 DAC—输出正弦波 本章参考资料:《STM32F10X-中文参考手册》DAC 章节。 学习本章时,配合《STM32F10X-中文参考手册》DAC 章节一起阅读,效果会更佳, 特别是涉及到寄存器说明的部分。 39.1 DAC 简介 DAC 为数字/模拟转换模块,故名思议,它的作用就是把输入的数字编码,转换成对 应的模拟电压输出,它的功能与 ADC 相反。在常见的数字信号系统中,大部分传感器信 号被化成电压信号,而 ADC 把电压模拟信号转换成易于计算机存储、处理的数字编码, 由计算机处理完成后,再由 DAC 输出电压模拟信号,该电压模拟信号常常用来驱动某些 执行器件,使人类易于感知。如音频信号的采集及还原就是这样一个过程。 STM32 具有片上 DAC 外设,它的分辨率可配置为 8 位或 12 位的数字输入信号,具有 两个 DAC 输出通道,这两个通道互不影响,每个通道都可以使用 DMA 功能,都具有出错 检测能力,可外部触发。 39.2 DAC 功能框图剖析 STM32 的 DAC 模块框图见图 39-1。 图 39-1 DAC 功能框图 第 565 页 共 887 STM32-DAC正玄波详解STM32-DAC正玄波详解STM32-DAC正玄波详解
零死角玩转 STM32F103—霸道 整个 DAC 模块围绕框图下方的“数字至模拟转换器 x”展开,它的左边分别是参考 电源的引脚: 、 及 ,其中 STM32 的 DAC 规定了它的参考电压 输入范围 为 2.4——3.3V。“数字至模拟转换器 x”的输入为 DAC 的数据寄存器“DORx”的数字编 码,经过它转换得的模拟信号由图中右侧的“DAC_OUTx”输出。而数据寄存器“DORx” 又受“控制逻辑”支配,它可以控制数据寄存器加入一些伪噪声信号或配置产生三角波信 号。图中的左上角为 DAC 的触发源,DAC 根据触发源的信号来进行 DAC 转换,其作用就 相当于 DAC 转换器的开关,它可以配置的触发源为外部中断源触发、定时器触发或软件 控制触发。如本章实验中需要控制正弦波的频率,就需要定时器定时触发 DAC 进行数据 转换。 1. 参考电压 与 ADC 外设类似,DAC 也使用 VREF+引脚作为参考电压,在设计原理图的时候一般把 VSSA 接地,把 VREF+和 VDDA 接 3.3V,可得到 DAC 的输出电压范围为:0~3.3V。 如果想让输出的电压范围变宽,可以在外部加一个电压调理电路,把 0~3.3V 的 DAC 输出抬升到特定的范围即可。 2. 数模转换及输出通道 框图中的―数字至模拟转换器 x‖是核心部件,整个 DAC 外设都围绕它而展开。它以左 边的 VREF+作为参考电源,以 DAC 的数据寄存器“DORx”的数字编码作为输入,经过它 转换得的模拟信号由右侧的“DAC_OUTx”通道输出。其中各个部件中的―x‖是指设备的 标号,在 STM32 中具有 2 个这样的 DAC 部件,每个 DAC 有 1 个对应的输出通道连接到特 定的引脚,即:PA4-通道 1,PA5-通道 2,为避免干扰,使用 DAC 功能时,DAC 通道引 脚需要被配置成模拟输入功能(AIN)。 3. 触发源及 DHRx 寄存器 在使用 DAC 时,不能直接对上述 DORx 寄存器写入数据,任何输出到 DAC 通道 x 的 数据都必须写入到 DHRx 寄存器中(其中包含 DHR8Rx、DHR12Lx 等,根据数据对齐方向 和分辨率的情况写入到对应的寄存器中)。 数据被写入到 DHRx 寄存器后,DAC 会根据触发配置进行处理,若使用硬件触发,则 DHRx 中的数据会在 3 个 APB1 时钟周期后传输至 DORx,DORx 随之输出相应的模拟电压 到输出通道;若 DAC 设置为外部事件触发,可以使用定时器(TIMx_TRGO)、EXTI_9 信号或软件触发(SWTRIGx)这几种方式控制数据 DAC 转换的时机,例如使用定时器触 发,配合不同时刻的 DHRx 数据,可实现 DAC 输出正弦波的功能。 39.3 DAC 初始化结构体详解 在 ST 的标准库中,把控制 DAC 相关的各种配置封装到了结构体 DAC_InitTypeDef 中, 它主要包含了 DAC_CR 控制寄存器的各寄存器位的配置,见代码清单 39-1。 代码清单 39-1 DAC_InitTypeDef 结构体 第 566 页 共 887 STM32-DAC正玄波详解STM32-DAC正玄波详解STM32-DAC正玄波详解
零死角玩转 STM32F103—霸道 1 typedef struct { 2 /*DAC 触发方式 */ 3 uint32_t DAC_Trigger; 4 5 /*是否自动输出噪声或三角波 */ 6 uint32_t DAC_WaveGeneration; 7 8 /*选择噪声生成器的低通滤波或三角波的幅值 */ 9 uint32_t DAC_LFSRUnmask_TriangleAmplitude; 10 11 /*选择是否使能输出缓冲器 */ 12 uint32_t DAC_OutputBuffer; 13 14 } DAC_InitTypeDef; 各个结构体成员的介绍如下,解说中各模式后括号内的英文为该模式在标准库中使用 宏: (1) DAC_Trigger 本成员用于配置 DAC 的触发模式,当 DAC 产生相应的触发事件时,才会把 DHRx 寄 存器的值转移到 DORx 寄存器中进行转换。本结构体成员可以选择的触发模式如下: 硬件触发模式(DAC_Trigger_None),DHRx 寄存器内的数据会在 3 个 APB1 时钟周 期 内 自 动 转 换 至 DORx 进 行 转 换 ; 定 时 器 触 发 模 式 (DAC_Trigger_T2/4/5/6/7_TRGO),使用定时器 2、4、5、6、7 控制 DHRx 寄存器 的数据按时间转移到 DORx 中进行转换,利用这种方式可以输出特定的波形;EXTI_9 触发方式(DAC_Trigger_Ext_IT9),当产生 EXTI_9 事件时(如 GPIO 中断事件), 触 发 转 换 ; 软 件 触 发 模 式 ( DAC_Trigger_Software ) , 在 本 模 式 下 , 向 DAC_SWTRIGR 寄存器写入配置即可触发信号进行转换。 (2) DAC_WaveGeneration 本 成 员 用 于 设 置 是 否 使 用 DAC 输 出 伪 噪 声 或 三 角 波 (DAC_WaveGeneration_None/Noise/Triangle),使用伪噪声和三角波输出时 ,DAC 都会把 LFSR 寄存器的值叠加到 DHRx 数值上,产生伪噪声和三角波,若希望产生自 定义的输出时,直接配置为 DAC_WaveGeneration_None 即可。 (3) DAC_LFSRUnmask_TriangleAmplitude 本成员通过控制 DAC_CR 的 MAMP2 位设置 LFSR 寄存器位的数据,即当使用伪噪声 或三角波输出时要叠加到 DHRx 的值,非噪声或三角波输出模式下,本配置无效。使 用伪噪声输出时 LFSR=0xAAA,MAMP2 寄存器位可以屏蔽 LFSR 的某些位,这时把 本结构体成员赋值为 DAC_LFSRUnmask_Bit0~DAC_LFSRUnmask_Bit11_0 等宏即可; 使 用 三 角 波 输 出 时 , 本 结 构 体 设 置 三 角 波 的 最 大 幅 值 , 可 选 择 为 DAC_TriangleAmplitude_1~ DAC_TriangleAmplitude_4096 等宏,见图 39-2,DAC 在 DHRx 值的基础上升,幅值达到 MAMPx 设置的最大幅度时下降,形成三角波的输出。 第 567 页 共 887 STM32-DAC正玄波详解STM32-DAC正玄波详解STM32-DAC正玄波详解
零死角玩转 STM32F103—霸道 图 39-2 DAC 输出三角波 (4) DAC_OutputBuffer 本 结 构 体 成 员 用 于 控 制 是 否 使 能 DAC 的 输 出 缓 冲 (DAC_OutputBuffer_Enable/Disable),使能了 DAC 的输出缓冲后可以减小输出阻抗, 适合直接驱动一些外部负载。 39.4 DAC 输出正弦波实验 利用 STM32 的 DAC 配合 TIM 定时器,可以输出随时间变化的电压,本章的实验以输 出正弦波为例,演示如何控制输出电压波形。 39.4.1 硬件设计 STM32 的 DAC 外设有固定的输出通道,分别为 PA4 和 PA5,不过,霸道开发板已经 在板载 SPI-FLASH 芯片中使用了这两个引脚,所以用作 DAC 通道输出电压时会受到干扰, 影响实验,见图 31-5。 图 39-3 SPI-FLASH 占用了 DAC 使用的输出通道 PA4 引脚在上述 SPI-FLASH 的电路中已通过上拉电阻接到 3.3V,PA5 引脚则连接到 FLASH 芯片的 CLK 引脚中,这些都会干扰 DAC 实验输出的电压信号,导致得不到正确 的波形。 在实验时,需要把开发板中 SPI-FLASH 附近的上拉电阻 R6 拆掉,拆掉 R6 后,本实 验中的 PA4、PA5 的波形输出正常,且不会影响后续 SPI-FLASH 的使用(只要 DAC 和 SPI-FLASH 不在同一个实验中使用即可)。 第 568 页 共 887 STM32-DAC正玄波详解STM32-DAC正玄波详解STM32-DAC正玄波详解
零死角玩转 STM32F103—霸道 在设计 DAC 专门的实际应用时,DAC 的输出通道应独占,不与其它设备共用。本开 发板的设计是考虑到各种资源分配,才不得不占用 DAC 通道的。 拆掉相应的元件后,实验时直接使用示波器测量 PA4 和 PA5 引脚的输出即可。 39.4.2 软件设计 为了使工程更加有条理,我们把 DAC 控制相关的代码独立分开存储,方便以后移植。 新建“bsp_dac.c”及“bsp_dac.h”文件,这些文件也可根据您的喜好命名,它们不属于 STM32 标准库的内容,是由我们自己根据应用需要编写的。 1. 编程要点 1) 计算获取正弦波数据表; 2) 根据正弦波数据表的周期内点数和周期计算定时器触发间隔; 3) 初始化 DAC 输出通道,初始化 DAC 工作模式; 4) 配置触发 DAC 用的定时器; 5) 配置 DMA 自动转运正弦波数据表。 配置完成后,即可在 PA4、PA5 引脚中检测到信号输出。 2. 代码分析 生成正弦波数据表 要输出正弦波,实质是要控制 DAC 以 v=sin(t)的正弦函数关系输出电压,其中 v 为电 压输出,t 为时间。 而由于模拟信号连续而数字信号是离散的,所以使用 DAC 产生正弦波时,只能按一 定时间间隔输出正弦曲线上的点,在该时间段内输出相同的电压值,若缩短时间间隔,提 高单个周期内的输出点数,可以得到逼近连续正弦波的图形,见图 39-4,若在外部电路加 上适当的电容滤波,可得到更完美的图形。 图 39-4 DAC 按点输出正弦波数据(左:32 个点,右:128 个点) 第 569 页 共 887 STM32-DAC正玄波详解STM32-DAC正玄波详解STM32-DAC正玄波详解
零死角玩转 STM32F103—霸道 由于正弦曲线是周期函数,所以只需要得到单个周期内的数据后按周期重复即可,而 单个周期内取样输出的点数又是有限的,所以为了得到呈 v=sin(t)函数关系电压值的数据通 常不会实时计算获取,而是预先计算好函数单个周期内的电压数据表,并且转化成以 DAC 寄存器表示的值。 如 sin 函数值的范围为[-1: +1],而 STM32 的 DAC 输出电压范围为[0~3.3]V,按 12 位 DAC 分辨率表示的方法,可写入寄存器的最大值为 212 = 4096,即范围为[0:4096]。所以, 实际输出时,会进行如下处理: 1) 抬升 sin 函数的输出为正值:v = sin(t)+1 ,此时,v 的输出范围为[0:2]; 2) 扩展输出至 DAC 的全电压范围: v = 3.3*(sin(t)+1)/2 ,此时,v 的输出范围为[0:3.3], 正是 DAC 的电压输出范围,扩展至全电压范围可以充分利用 DAC 的分辨率; 3) 把电压值以 DAC 寄存器的形式表示:Reg_val = 212/3.3 * v = 211*(sin(t)+1),此时,存 储到 DAC 寄存器的值范围为[0:4096]; 4) 实践证明,在 sin(t)的单个周期内,取 32 个点进行电压输出已经能较好地还原正弦波 形,所以在 t∈[0:2π]区间内等间距根据上述 Reg_val 公式运算得到 32 个寄存器值, 即可得到正弦波表; 5) 控制 DAC 输出时,每隔一段相同的时间从上述正弦波表中取出一个新数据进行输出, 即可输出正弦波。改变间隔时间的单位长度,可以改变正弦波曲线的周期。 为方便起见,我们使用了 Python 和 Matlab 脚本制作正弦波表,脚本的代码存储在本 工程的目录下,感兴趣可以打开文件查看,以下列出 Python 脚本代码,见代码清单 39-2。 代码清单 39-2 制作正弦波数据表的 python 脚本(工程目录下的 sinWave.py 文件) 1 #! python3 2 #coding=utf-8 3 4 """ 5 Python 版本:3.x 6 外部库:matplotlib1.5.3、numpy1.11.2 7 8 运行方式: 9 在命令行中输入:python sinWave.py 10 11 运行结果: 12 命令行中会打印计算得的各点数据, 13 在当前目录下会生成 py_dac_sinWav.c 文件,包含上述数据, 14 并且会弹出描绘曲线的对话框。 15 """ 16 17 import matplotlib.pyplot as plt 18 import numpy as np 19 import math 20 21 #修改本变量可以更改点数,如 16、32、64 等 22 POINT_NUM = 32 23 24 pi = math.pi 25 26 #一个周期 POINT_NUM 个点 27 n = np.linspace(0,2*pi,POINT_NUM) 28 29 #计算 POINT_NUM 个点的正弦值 30 a = map(math.sin,n) 第 570 页 共 887 STM32-DAC正玄波详解STM32-DAC正玄波详解STM32-DAC正玄波详解
零死角玩转 STM32F103—霸道 31 32 r =[] 33 for i in a: 34 #调整幅值至在 0~1 区间 35 i+=1 36 37 #按 3.3V 电压调整幅值 38 i*= 3.3/2 39 40 #求取 dac 数值,12 位 dac LSB = 3.3V/2**12 41 ri = round(i*2**12/3.3) 42 43 #检查参数 44 if ri >= 4095: 45 ri = 4095 46 47 #得到 dac 数值序列 48 r.append( ri ) 49 50 51 print(list(map(int,r))) 52 53 #写入序列到文件 54 with open("py_dac_sinWav.c",'w',encoding= 'gb2312') as f: 55 print(list(map(int,r)),file= f) 56 57 #绘图 58 plt.plot(n,r,"-o") 59 plt.show() 60 Python 脚本的实现原理就是前面介绍的正弦波数据表的制作过程,运行后,该脚本把 得到的正弦波表数据输出到目录下的 py_dac_sinWav.c 文件中,见代码清单 39-3,并且根 据取样点描绘出示意图,见图 39-5。Matlab 脚本原理相同,此处不再列出,实际上使用 C 语言也能制作正弦波表,只是画图不方便而已。 代码清单 39-3 生成的正弦波数据表 [2048, 2460, 2856, 3218, 3532, 3786, 3969, 4072, 4093, 4031, 3887, 3668, 3382, 3042, 2661, 2255, 1841, 1435, 1054, 714, 428, 209, 65, 3, 24, 127, 310, 564, 878, 1240, 1636, 2048] 图 39-5 python 脚本根据正弦波表描绘的曲线图 第 571 页 共 887 STM32-DAC正玄波详解STM32-DAC正玄波详解STM32-DAC正玄波详解
零死角玩转 STM32F103—霸道 DAC 宏定义 制作好正弦波数据表后,开始使用 MDK 编写 STM32 的 DAC 工程,首先设置好相关 的宏,见代码清单 39-4。 代码清单 39-4 DAC 宏定义(bsp_dac.h 文件) 1 //DAC DHR12RD 寄存器,12 位、右对齐、双通道 2 #define DAC_DHR12RD_ADDRESS (DAC_BASE+0x20) 此处定义的宏 DAC_DHR12RD_ ADDRESS 是寄存器 DHR12RD 的地址,该寄存器是 12 位右对齐的双通道寄存器,见图 39-6。在本实验中将会使用 DMA 把正弦波数据表的点 数据赋值到该寄存器中,往该寄存器赋值后的数据会在 DAC 被触发的时候搬运到 2 个 DAC 转换器,然后在这 2 个通道中输出以 12 位右对齐表示的这两个通道的电压。DAC 中 还有其它寄存器,它们的功能类似,可以在《STM32 中文参考手册》中了解到。 与 DAC 控制相关的引脚固定是 PA4 和 PA5,就不使用宏定义了,在源代码中会直接 图 39-6 DHR12RD 寄存器说明 使用引脚号操作。 DAC GPIO 和模式配置 代码清单 39-5 DAC GPIO 和模式配置 1 /** 2 * @brief 使能 DAC 的时钟,初始化 GPIO 3 * @param 无 4 * @retval 无 5 */ 6 static void DAC_Config(void) 7 { 8 GPIO_InitTypeDef GPIO_InitStructure; 9 DAC_InitTypeDef DAC_InitStructure; 10 11 /* 使能 GPIOA 时钟 */ 12 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 13 14 /* 使能 DAC 时钟 */ 第 572 页 共 887 STM32-DAC正玄波详解STM32-DAC正玄波详解STM32-DAC正玄波详解
分享到:
收藏