STM32 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输出型的 DAC。
DAC 可以配置为 8 位或 12 位模式,也可以与 DMA 控制器配合使用
DAC 工作在 12 位模式时,数据可以设置成左对齐或右对齐。
DAC 模块有 2 个输出通道,每个通道都有单独的转换器。在双DAC 模式下,2 个通道可以独立地进行转换,也可以同时进行转换并同步地更新 2 个通道的输出。
DAC 可以通过引脚输入参考电压 VREF+以获得更精确的转换结果
注意:STM_DAC 和 GBC_KEY 共用 PA4,所以,如果您的开发板 ATK MODULE 位置插了其他模块,那么可能影响 DAC 的输出结果,建议在做 DAC 实验的时候,ATK MODULE 位置,不要插任何其他模块。
VDDA 和 VSSA 为 DAC 模块模拟部分的供电,而 Vref+则是 DAC 模块的参考电压
DAC_OUTx 就是 DAC 的输出通道了(对应 PA4 或者 PA5 引脚)
图中可以看出,DAC输出是受DORx寄存器直接控制的,但是我们是通过 DHRx 间接的传给 DORx 寄存器,实现对 DAC 输出的控制。
我们说过,STM32 的 DAC 支持 8/12 位模式,8 位模式的时候是固定的右对齐的,而 12 位模式又可以设置左对齐/右对齐。单 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_CR1 的 TENx 位置’0’),存入寄存器 DAC_DHRx的数据会在一个 APB1 时钟周期后自动传至寄存器 DAC_DORx。
如果选中硬件触发(寄存器DAC_CR1 的 TENx 位置’1’),数据传输在触发发生以后 3 个 APB1 时钟周期后完成。
一旦数据从 DAC_DHRx 寄存器装入 DAC_DORx 寄存器,在经过时间Tsetting之后,输出即有效,典型值为 3us,最大是 4us。
这段时间的长短依电源电压和模拟输出负载的不同会有所变化。
当 DAC 的参考电压为 Vref+的时候,DAC 的输出电压是线性的从 0~Vref+,12 位模式下 DAC输出电压与 Vref+以及 DORx 的计算公式如下:
DACx 输出电压=Vref*(DORx/4095)
目录
DAC控制寄存器 DAC_CR
DAC 的数据保持寄存器
DAC_CR 的低 16 位用于控制通道 1,而高 16 位用于控制通道 2,我们这里仅列出比较重要的最低 8 位的详细描述
DAC 通道 1 使能位(EN1),该位用来控制 DAC 通道 1 使能的关闭 DAC 通道 1 输出缓存控制位(BOFF1),这里 STM32 的 DAC 输出缓存做的有些不好,如果使能的话,虽然输出能力强一点,但是输出没法到 0,这是个很严重的问题。
DAC 通道 1 触发使能位(TEN1),该位用来控制是否使用触发
DAC 通道 1 触发选择位(TSEL1[2:0])
DAC 通道 1 噪声/三角波生成使能位(WAVE1[1:0])
DAC 通道 1 屏蔽/幅值选择器(MAMP[3:0]),这些位仅在使用了波形发生器的时候有用
DAC 通道 1 DMA 使能位(DMAEN1)
DAC 通道 1 的 12 位右对齐数据保持寄存器:DAC_DHR12R1
该寄存器用来设置 DAC 输出,通过写入 12 位数据到该寄存器,就可以在 DAC 输出通道 1(PA4)得到我们所要的结果。
目录
开启 PA 口时钟,设置 PA4为模拟输入
使能 GPIOA 时钟
使能 DAC1 时钟
初始化 DAC, 设置 DAC 的工作模式
使能 DAC 转换通道
设置 DAC 的输出值
STM32F103ZET6 的 DAC 通道 1 在 PA4 上,所以,我们先要使能 PORTA 的时钟,然后设置 PA4 为模拟输入。
DAC 本身是输出,但是为什么端口要设置为模拟输入模式呢?
因为一但使能 DACx 通道之后,相应的 GPIO 引脚(PA4 或者 PA5)会自动与 DAC 的模拟输出相连,设置为输入,是为了避免额外的干扰。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); //使能PORTA时钟
设置 PA1 为模拟输入只需要设置初始化参数即可:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
同其他外设一样,要想使用,必须先开启相应的时钟。
STM32 的 DAC 模块时钟是由 APB1提供的,所以我们调用函数 RCC_APB1PeriphClockCmd()设置 DAC 模块的时钟使能。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能 DAC 通道时钟
该部分设置全部通过 DAC_CR 设置实现,包括:DAC 通道 1 使能、DAC 通道 1 输出缓存关闭、不使用触发、不使用波形发生器等设置。这里 DMA 初始化是通过函数 DAC_Init 完成的:
void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct)
来看看参数设置结构体类型 DAC_InitTypeDef 的定义:
typedef struct
{
uint32_t DAC_Trigger;
uint32_t DAC_WaveGeneration;
uint32_t DAC_LFSRUnmask_TriangleAmplitude;
uint32_t DAC_OutputBuffer;
}DAC_InitTypeDef;
第一个参数 DAC_Trigger 用来设置是否使用触发功能,不用触发功能,所以值为 DAC_Trigger_None。
第二个参数 DAC_WaveGeneratio 用来设置是否使用波形发生,这里我们前面同样讲解过不使用。所以值为 DAC_WaveGeneration_None。
第三个参数 DAC_LFSRUnmask_TriangleAmplitude 用来设置屏蔽/幅值选择器,这个变量只在使用波形发生器的时候才有用,这里我们设置为 0 即可,值为 DAC_LFSRUnmask_Bit0。
第四个参数 DAC_OutputBuffer 是用来设置输出缓存控制位,前面讲解过,我们不使用输出缓存,所以值为 DAC_OutputBuffer_Disable。
实例代码:
DAC_InitTypeDef DAC_InitType;
DAC_InitType.DAC_Trigger=DAC_Trigger_None; //不使用触发功能 TEN1=0
DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;
DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ; //DAC1 输出缓存关闭
DAC_Init(DAC_Channel_1,&DAC_InitType); //初始化 DAC 通道 1
初始化 DAC 之后,理所当然要使能 DAC 转换通道,库函数方法是:
DAC_Cmd(DAC_Channel_1, ENABLE); //使能 DAC1
通过前面 的设置,DAC 就可以开始工作了
我们使用 12 位右对齐数据格式,所以我们通过设置 DHR12R1,就可以在 DAC 输出引脚(PA4)得到不同的电压值了。库函数的函数是:
DAC_SetChannel1Data(DAC_Align_12b_R, 0);
第一个参数设置对齐方式,可以为 12 位右对齐 DAC_Align_12b_R,12 位左对齐DAC_Align_12b_L 以及 8 位右对齐 DAC_Align_8b_R 方式。
第二个参数就是 DAC 的输入值了,这个很好理解,初始化设置为 0。
这里,还可以读出 DAC 的数值,函数是:
DAC_GetDataOutputValue(DAC_Channel_1);