第十五章 DAC (上篇)
目录
1 DAC简介
数字/模拟转换模块(DAC)是 12 位数字输入,电压输出的数字/模拟转换器。DAC 可以配置为 8 位或 12 位模式,也可以与 DMA 控制器配合使用。DAC 工作在 12 位模式时,数据可以设置成左对齐或右对。DAC 模块有 2 个输出通道,每个通道都有单独的转换器。在双 DAC 模式下,2 个通道可以独立地进行转换,也可以同时进行转换并同步地更新 2 个通道的输出。DAC 可以通过引脚输入参考电压 VREF+以获得更精确的转换结果。
2 DAC主要特征
- 2 个 DAC 转换器:每个转换器对应 1 个输出通道
- 8 位或者 12 位单调输出
- 12 位模式下数据左对齐或者右对齐
- 同步更新功能
- 噪声波形生成
- 三角波形生成
- 双 DAC 通道同时或者分别转换
- 每个通道都有 DMA 功能
- 外部触发转换
- 输入参考电压 VREF+
DAC通道模块框图如下:
DAC 通道模块框图
名称 | 型号类型 | 注释 |
VREF+ | 输入,正模拟参考电压 | DAC使用的高端/正极参考电压,2.4V≤VREF+≤VDDA(3.3V) |
VDDA | 输入,模拟电源 | 模拟电源 |
VSSA | 输入,模拟电源地 | 模拟电源的地线 |
DAC_OUTx | 模拟输出信号 | DAC通道x的模拟输出 |
注意: 一旦使能 DACx 通道,相应的 GPIO 引脚(PA4 或者 PA5)就会自动与 DAC 的模拟输出相连(DAC_OUTx)。为了避免寄生的干扰和额外的功耗,引脚 PA4 或者 PA5 在之前应当设置成模拟输入(AIN)。
3 DAC功能描述
3.1 使能DAC通道
将 DAC_CR 寄存器的 ENx 位置'1'即可打开对 DAC 通道 x 的供电。经过一段启动时间 tWAKEUP,DAC 通道 x 即被使能。注意: ENx 位只会使能 DAC 通道 x 的模拟部分,即便该位被置'0',DAC 通道 x 的数字部分仍然工作
3.2 使能DAC输出缓存
DAC 集成了 2 个输出缓存,可以用来减少输出阻抗,无需外部运放即可直接驱动外部负载。每个DAC 通道输出缓存可以通过设置 DAC_CR 寄存器的 BOFFx 位来使能或者关闭。
3.3 DAC数据格式
根据选择的配置模式,数据按照下文所述写入指定的寄存器:
- 单 DAC 通道 x,有 3 种情况:
- 8 位数据右对齐:用户须将数据写入寄存器 DAC_DHR8Rx[7:0]位(实际是存入寄存器DHRx[11:4]位)
- 12位数据左对齐:用户须将数据写入寄DAC_DHR12Lx[15:4]位(实际是存入寄存器DHRx[11:0]位)
- 12 位数据右对齐:用户须将数据写入寄存器 DAC_DHR12Rx[11:0]位(实际是存入寄存器DHRx[11:0]位)
根据对 DAC_DHRyyyx 寄存器的操作,经过相应的移位后,写入的数据被转存到 DHRx 寄存器中(DHRx 是内部的数据保存寄存器 x)。随后,DHRx 寄存器的内容或被自动地传送到 DORx 寄存器,或通过软件触发或外部事件触发被传送到 DORx 寄存器。
单 DAC 通道模式的数据寄存器
- 双 DAC 通道,有 3 种情况:
- 8 位数据右对齐:用户须将 DAC 通道 1 数据写入寄存器 DAC_DHR8RD[7:0]位(实际是存入寄存器 DHR1[11:4]位),将 DAC 通道 2 数据写入寄存器DAC_DHR8RD[15:8]位(实际是存入寄存器 DHR2[11:4]位)
- 12 位数据左对齐:用户须将 DAC 通道 1 数据写入寄存器 DAC_DHR12LD[15:4]位(实际是存入寄存器 DHR1[11:0]位),将 DAC 通道 2 数据写入寄存器 DAC_DHR12LD[31:20]位(实际是存入寄存器 DHR2[11:0]位)
- 12 位数据右对齐:用户须将 DAC 通道 1 数据写入寄存器 DAC_DHR12RD[11:0]位(实际是存入寄存器 DHR1[11:0]位),将 DAC 通道 2 数据写入寄存器 DAC_DHR12RD[27:16]位(实际是存入寄存器 DHR2[11:0]位)
根据对 DAC_DHRyyyD 寄存器的操作,经过相应的移位后,写入的数据被转存到 DHR1 和 DHR2 寄存器中(DHR1 和 DHR2 是内部的数据保存寄存器 x)。随后,DHR1 和 DHR2 的内容或被自动地传送到 DORx 寄存器,或通过软件触发或外部事件触发被传送到 DORx 寄存器。
双 DAC 通道模式的数据寄存器
3.4 DAC转换
不能直接对寄存器 DAC_DORx 写入数据,任何输出到 DAC 通道 x 的数据都必须写入 DAC_DHRx 寄存器(数据实际写入DAC_DHR8Rx、DAC_DHR12Lx、DAC_DHR12Rx、DAC_DHR8RD、DAC_DHR12LD、或者 DAC_DHR12RD 寄存器)。
如果没有选中硬件触发(寄存器 DAC_CR1 的 TENx 位置'0'),存入寄存器 DAC_DHRx 的数据会在一个 APB1 时钟周期后自动传至寄存器 DAC_DORx。如果选中硬件触发(寄存器 DAC_CR1 的 TENx 位置'1'),数据传输在触发发生以后 3 个 APB1 时钟周期后完成。一旦数据从 DAC_DHRx 寄存器装入 DAC_DORx 寄存器,在经过时间 tSETTLING 之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。
TEN=0 触发失能时转换的时间框图
3.5 DAC输出电压
数字输入经过 DAC 被线性地转换为模拟电压输出,其范围为 0 到 VREF+。
任一 DAC 通道引脚上的输出电压满足下面的关系:
- DAC 输出=VREFx(DOR/4095)。
3.6 选择DAC触发
如果 TENx 位被置 1,DAC 转换可以由某外部事件触发(定时器计数器、外部中断线)。配置控制TSELx[2:0]可以选择 8 个触发事件之一触发 DAC 转换。
触发源 | 类型 | TSELx[2:0] |
定时器 6TRGO 事件 | 来自片上定时器的内部信号 | 000 |
定时器 8TRGO 事件 | 001 | |
定时器 7TRGO 事件 | 010 | |
定时器 5TRGO 事件 | 011 | |
定时器 2TRGO 事件 | 100 |
每次 DAC 接口侦测到来自选中的定时器 TRGO 输出,或者外部中断线 9 的上升沿,最近存放在寄存器 DAC_DHRx 中的数据会被传送到寄存器 DAC_DORx 中。在 3 个 APB1 时钟周期后,寄存器DAC_DORx 更新为新值。
如果选择软件触发,一旦 SWTRIG 位置'1',转换即开始。在数据从 DAC_DHRx 寄存器传送到DAC_DORx 寄存器后,SWTRIG 位由硬件自动清'0'。
注意: 1.不能在 ENx 为'1'时改变 TSELx[2:0]位。2.如果选择软件触发,数据从寄存器 DAC_DHRx 传送到寄存器 DAC_DORx 只需要一个 APB1 时钟周期。
3.7 DMA请求
任一 DAC 通道都具有 DMA 功能。2 个 DMA 通道可分别用于 2 个 DAC 通道的 DMA 请求。如果DMAENx 位置'1',一旦有外部触发(而不是软件触发)发生,则产生一个 DMA 请求,然后DAC_DHRx 寄存器的数据被传送到 DAC_DORx 寄存器。
在双 DAC 模式下,如果 2 个通道的 DMAENx 位都为'1',则会产生 2 个 DMA 请求。如果实际只需要一个 DMA 传输,则应只选择其中一个 DMAENx 位置'1'。这样,程序可以在只使用一个 DMA 请求,一个DMA 通道的情况下,处理工作在双 DAC 模式的 2 个 DAC 通道。DAC 的 DMA 请求不会累计,因此如果第 2 个外部触发发生在响应第 1 个外部触发之前,则不能处理第 2 个 DMA 请求,也不会报告错误。
3.8 噪声生成
可以利用线性反馈移位寄存器(Linear Feedback Shift Register LFSR)产生幅度变化的伪噪声。设置WAVE[1:0]位为'01'选择DAC噪声生成功能。寄存器LFSR的预装入值为0xAAA。按照特定算法,在每次触发事件后 3 个 APB1 时钟周期之后更新该寄存器的值。
DACLFSR 寄存器算法
设置 DAC_CR 寄存器的 MAMPx[3:0]位可以屏蔽部分或者全部 LFSR 的数据,这样的得到的 LSFR 值与 DAC_DHRx 的数值相加,去掉溢出位之后即被写入 DAC_DORx 寄存器。
如果寄存器 LFSR 值为 0x000,则会注入'1'(防锁定机制)。将 WAVEx[1:0]位置'0'可以复位 LFSR 波形的生成算法。
带 LFSR 波形生成的 DAC 转换(使能软件触发)
3.9 三角波生成
可以在 DC 或者缓慢变化的信号上加上一个小幅度的三角波。设置 WAVEx[1:0]位为'10'选择 DAC 的三角波生成功能。设置 DAC_CR 寄存器的 MAMPx[3:0]位来选择三角波的幅度。内部的三角波计数器每次触发事件之后 3 个 APB1 时钟周期后累加 1。计数器的值与 DAC_DHRx 寄存器的数值相加并丢弃溢出位后写入 DAC_DORx 寄存器。在传入 DAC_DORx 寄存器的数值小于 MAMP[3:0]位定义的最大幅度时,三角波计数器逐步累加。一旦达到设置的最大幅度,则计数器开始递减,达到 0 后再开始累加,周而复始。
将 WAVEx[1:0]位置'0'可以复位三角波的生成。
DAC 三角波生成
带三角生成的 DAC 转换(使能软件触发)
注意: 1.为了产生三角波,必须使能 DAC 触发,即设 DAC_CR 寄存器的 TENx 位为'1'。
MAMP[3:0]位必须在使能 DAC 之前设置,否则其值不能修改。
4 双DAC通道转换
在需要 2 个 DAC 同时工作的情况下,为了更有效地利用总线带宽,DAC 集成了 3 个供双 DAC 模式使用的寄存器:DHR8RD、DHR12RD 和 DHR12LD,只需要访问一个寄存器即可完成同时驱动 2 个DAC 通道的操作。
对于双 DAC 通道转换和这些专用寄存器,共有 11 种转换模式可用。这些转换模式在只使用一个DAC 通道的情况下,仍然可通过独立的 DHRx 寄存器操作。
4.1 不使用波形发生器的独立触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1';
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为不同值,分别配置 2 个 DAC 通道的不同触发源;
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。
当发生 DAC 通道 1 触发事件时,(延迟 3 个 APB1 时钟周期后)寄存器 DHR1 的值传入寄存器DAC_DOR1。
当发生 DAC 通道 2 触发事件时,(延迟 3 个 APB1 时钟周期后)寄存器 DHR2 的值传入寄存器DAC_DOR2。
4.2 使用相同LFSR的独立触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1';
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为不同值,分别配置 2 个 DAC 通道的不同触发源;
- 设置 2 个 DAC 通道的 WAVEx[1:0]位为”01”,并设置 MAMPx[3:0]为相同的 LFSR 屏蔽值;
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。
当发生 DAC 通道 1 触发事件时,具有相同屏蔽的 LFSR1 计数器值与 DHR1 寄存器数值相加,(延迟3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR1,然后更新 LFSR1 计数器。当发生 DAC 通道 2 触发事件时,具有相同屏蔽的 LFSR2 计数器值与 DHR2 寄存器数值相加,(延迟3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR2,然后更新 LFSR2 计数器。
4.3 使用不同LFSR的独立触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1';
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为不同值,分别配置 2 个 DAC 通道的不同触发源;
- 设置 2 个 DAC 通道的 WAVEx[1:0]位为”01”,并设 MAMPx[3:0]为不同的 LFSR 屏蔽值;
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或者 DHR8RD)。
当发生 DAC 通道 1 触发事件时,按照 MAMP1[3:0]所设屏蔽的 LFSR1 计数器值与 DHR1 寄存器数值相加,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR1,然后更新 LFSR1 计数器。当发生 DAC 通道 2 触发事件时,按照 MAMP2[3:0]所设屏蔽的 LFSR2 计数器值与 DHR2 寄存器数值相加,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR2,然后更新 LFSR2 计数器。
4.4 产生相同三角波的独立触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1';
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为不同值,分别配置 2 个 DAC 通道的不同触发源;
- 设置 2 个 DAC 通道的 WAVEx[1:0]位为”1x”,并设 MAMPx[3:0]为相同的三角波幅值;
将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。
当发生 DAC 通道 1 触发事件时,相同的三角波幅值加上 DHR1 寄存器的值,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR1,然后更新 DAC 通道 1 三角波计数器。
当发生 DAC 通道 2 触发事件时,相同的三角波幅值加上 DHR2 寄存器的值,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR2,然后更新 DAC 通道 2 三角波计数器。
4.5 产生不同三角波的独立触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1';
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为不同值,分别配置 2 个 DAC 通道的不同触发源;
- 设置 2 个 DAC 通道的 WAVEx[1:0]位为'1x',并设 MAMPx[3:0]为不同的三角波幅值。
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。
当发生 DAC 通道 1 触发事件时,MAMP1[3:0]所设的三角波幅值加上 DHR1 寄存器数值,(延迟 3 个APB1 时钟周期后)结果传入寄存器 DAC_DOR1,然后更新 DAC 通道 1 三角波计数器。
当发生 DAC 通道 2 触发事件时,MAMP2[3:0]所设的三角波幅值加上 DHR2 寄存器数值,(延迟 3 个APB1 时钟周期后)结果传入寄存器 DAC_DOR2,然后更新 DAC 通道 2 三角波计数器。
4.6 同时软件启动
按照下列过程设置 DAC 工作在此转换模式:
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。在此配置下,一个 APB1 时钟周期后,DHR1 和 DHR2 寄存器的数值即被分别传入 DAC_DOR1 和DAC_DOR2 寄存器。
4.7 不使用波形发生器的同时触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1';
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为相同值,分别配置 2 个 DAC 通道使用相同触发源;
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。
当发生触发事件时,(延迟 3 个 APB1 时钟周期后)DHR1 和 DHR2 寄存器的数值分别传入 DAC_DOR1和 DAC_DOR2 寄存器。
4.8 使用相同LFSR的同时触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1';
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为相同值,分别配置 2 个 DAC 通道使用相同触发源;
- 设置 2 个 DAC 通道的 WAVEx[1:0]位为”01”,并设 MAMPx[3:0]为相同的 LFSR 屏蔽值;
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD);
当发生触发事件时,MAMP1[3:0]所设屏蔽的 LFSR1 计数器值与 DHR1 寄存器的数值相加,(延迟 3个 APB1 时钟周期后)结果传入 DAC_DOR1 寄存器,然后更新 LFSR1 计数器。同样,MAMP1[3:0]所设屏蔽的 LFSR2 计数器值与 DHR2 寄存器的数值相加,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR2,然后更新 LFSR2 计数器。
4.9 使用不同LFSR的同时触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1';
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为相同值,分别配置 2 个 DAC 通道使用相同触发源;
- 设置 2 个 DAC 通道的 WAVEx[1:0]位为'01',并设 MAMPx[3:0]为不同的 LFSR 屏蔽值;
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。
当发生触发事件时,具有相同屏蔽的 LFSR1 计数器值与 DHR1 寄存器数值相加,(延迟 3 个 APB1时钟周期后)结果传入寄存器 DAC_DOR1,然后更新 LFSR1 计数器。同时,具有相同屏蔽的 LFSR2 计数器值与 DHR2 寄存器数值相加,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR2,然后更新 LFSR2 计数器。
4.10 使用相同三角波发生器的同时触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1':
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为相同值,分别配置 2 个 DAC 通道使用相同触发源。
- 设置 2 个 DAC 通道的 WAVEx[1:0]位为'1x',并设 MAMPx[3:0]为相同的三角波幅值。将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。
当发生触发事件时,相同的三角波幅值与 DHR1 寄存器数值相加,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR1,然后更新 LFSR1 计数器。同时,相同的三角波幅值与 DHR2 寄存器数值相加,(延迟 3 个 APB1 时钟周期后)结果传入寄存器DAC_DOR2,然后更新 LFSR2 计数器。
4.11 使用不同三角波发生器的同时触发
按照下列顺序设置 DAC 工作在此转换模式:
- 分别设置 2 个 DAC 通道的触发使能位 TEN1 和 TEN2 为'1':
- 通过设置 TSEL1[2:0]和 TSEL2[2:0]位为相同值,分别配置 2 个 DAC 通道使用相同触发源。
- 设置 2 个 DAC 通道的 WAVEx[1:0]位为'1x',并设 MAMPx[3:0]为不同的三角波幅值。
- 将双 DAC 通道转换数据装入所需的 DHR 寄存器(DHR12RD、DHR12LD 或 DHR8RD)。
当发生触发事件时,MAMP1[3:0]所设的三角波幅值与 DHR1 寄存器数值相加,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR1,然后更新 LFSR1 计数器。同时,MAMP2[3:0]所设的三角波幅值与 DHR2 寄存器数值相加,(延迟 3 个 APB1 时钟周期后)结果传入寄存器 DAC_DOR2,然后更新 LFSR2 计数器。
5 例程设计
5.1 DAC_OutAudio例程
1.UART 模块:配置 USART1,波特率为 115200,将printf输出重定向到该串口,用于输出系统时钟信息与测试提示。
// UART初始化函数
void UART_Configuration(uint32_t bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 使能USART1和GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置TX引脚(PA9)为复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置RX引脚(PA10)为浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置串口参数:115200bps,8位数据,1位停止位
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
// 重定向printf函数到USART1
int SER_PutChar(int ch)
{
while (!USART_GetFlagStatus(USART_TEST, USART_FLAG_TC)); // 等待发送完成
USART_SendData(USART_TEST, (uint8_t)ch);
return ch;
}
int fputc(int c, FILE *f)
{
if (c == '\n') SER_PutChar('\r'); // 自动添加回车符
return SER_PutChar(c);
}
2.GPIO 模块:使能 GPIOA 时钟,把引脚 4 和 5 配置成模拟输入模式,为 DAC 输出做准备。
3.DAC 模块:使能 DAC 时钟,对 DAC 通道 1 和通道 2 进行初始化,设置初始输出值,将触发源设为定时器 2 的触发输出,同时使能 DMA 请求。
4.定时器模块:使能定时器 2 时钟,配置其参数以产生 8kHz 的更新事件,将更新事件选为触发输出。
5.DMA 模块:使能 DMA2 时钟,配置通道 4 和通道 3,将Sine12bit数组的数据循环传输到 DAC2 和 DAC1 的数据寄存器。
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
// 使能DMA2时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
// 配置DMA2通道4(DAC2)
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC2_DHR12RD_ADDRESS; // DAC2数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Sine12bit; // 数据源:正弦波数组
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 内存到外设
DMA_InitStructure.DMA_BufferSize = DATA_LEN; // 传输长度
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16位数据
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_Init(DMA2_Channel4, &DMA_InitStructure);
DMA_Cmd(DMA2_Channel4, ENABLE);
// 配置DMA2通道3(DAC1,参数与通道4相同)
DMA_InitStructure.DMA_PeripheralBaseAddr = DAC1_DHR12RD_ADDRESS;
DMA_Init(DMA2_Channel3, &DMA_InitStructure);
DMA_Cmd(DMA2_Channel3, ENABLE);
}
- 数据转换模块:把 8 位数据转换为 12 位数据,存于Sine12bit数组。
6 下载验证
6.2 DAC_OutAudio例程
初始输出
在 DAC 配置过程中,代码会先将 DAC 通道 1 和通道 2 的输出设置为一个初始值(代码中设置为 3102)。因此,在程序启动的瞬间,DAC 的两个通道会输出对应于该初始值的电压信号。
在完成所有配置后,DMA 会将Sine12bit数组中的数据循环传输到 DAC 的数据寄存器,同时定时器 TIM2 会以 8kHz 的频率产生触发信号,触发 DAC 进行数模转换。因此,DAC 的两个通道会持续输出软件生成的正弦波信号。
- 频率:由于定时器 TIM2 的周期设置为 8999,预分频器设置为 0,所以定时器的更新频率为 8kHz,这意味着 DAC 输出的正弦波信号的频率也为 8kHz。
- 幅度:正弦波的幅度取决于Sine12bit数组中的数据,该数组中的数据是通过uint8_uint16函数将data数组中的 8 位数据转换为 12 位数据得到的。