STM32F407ZG开发板学习(10)
数字/模拟转换器 DAC
简介
STM32F4 的 DAC 模块是 12 位电压输出数模转换器。DAC 可以按 8 位或 12 位模式进行配置,并且可与 DMA 控制器配合使用。在 12 位模式下,数据可以采用左对齐或右对齐。DAC 有两个输出 通道,每个通道各有一个转换器。在 DAC 双通道模式下,每个通道可以单独进行转换;当 两个通道组合在一起同步执行更新操作时,也可以同时进行转换。可通过一个输入参考电压引脚 VREF+ (与 ADC 共享)来提高分辨率。
主要特性
- 两个 DAC 转换器:各对应一个输出通道
- 12 位模式下数据采用左对齐或右对齐
- 同步更新功能
- 生成噪声波
- 生成三角波
- DAC 双通道单独或同时转换
- 每个通道都具有 DMA 功能
- DMA 下溢错误检测
- 通过外部触发信号进行转换
- 输入参考电压 VREF+
原理框图
图中,TSEL 是触发源选择,DHR 是数据保持寄存器,DOR 是数据输出寄存器,DOR 是不允许写的,我们只能通过写 DHR 的方式来改变输出的值,DMAEN 是 DMA 使能,TEN 是 DAC 通道触发使能(选择 DHR 数据转移到 DOR 所需的时间),MAMP 和 WAVEN 是滤波/三角波相关。整个架构比较简单,通过控制寄存器 CR 控制两个 DAC 的数据转换,控制逻辑负责将DHR保持的数据做所需的处理输出到DOR,最后DOR的数据通过数模转换器输出为所需模拟信号。
寄存器
控制寄存器 CR
高16位控制 DAC2 ,低16位控制 DAC1。
滤波和 DMA 之后再了解,先关注各使能位和触发源选择,即低8位。
软件触发寄存器 SWTRIGR
比较直接,就是控制两个 DAC 是否允许软件触发。
数据保持寄存器 DHR
此寄存器在选择不同模式和对齐方式下,数据存入的位置也不一致,具体如图。为了满足硬件转移数据,每个模式对应一个寄存器,其中单通道还分 DAC1 和 DAC2 。因此,STM32中 DHR 寄存器总共应该有9个之多。
数据输出寄存器 DOR
含两个32位寄存器,分别保存 DAC1 和 DAC2 的数据输出。都只有低12位有效且只读,高位必须保持复位。
状态寄存器 SR
实验
STM32 自带 DAC 实验
配置 DAC1 输出模拟信号,并通过 ADC1 的通道5接收转换,用串口显示。
配置步骤
选用 PA4 和 PA5 短接。
- 使能 GPIOA 和 DAC 的时钟。
- 创建 GPIO_InitTypeDef 初始化 PA4 的 DAC 输出。
- 创建 DAC_InitTypeDef 初始化 DAC 。
- 使能 DAC 转换通道。即 Cmd 函数。
上四个步骤完成即可通过 DAC_SetChannel1Data 和 DAC_GetChannel1Data 来分别设置 DHR 和读出 DAC 的最后一次转换数值。
代码
dac.c
void dac1_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
//GPIO_InitStructure.GPIO_OType = ;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
//GPIO_InitStructure.GPIO_Speed = ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0; //此项选择滤波或生成三角波时才有效
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; //关闭输出缓冲
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None; //不触发
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; //不开启通道噪声,不生成三角波
DAC_Init(DAC_Channel_1, &DAC_InitStructure);
DAC_Cmd(DAC_Channel_1, ENABLE);
DAC_SetChannel1Data(DAC_Align_12b_R, 0); //12位右对齐
}
//vol为设置电压,单位 mV ,取值 0-3300
void dac1_set_vol(uint16_t vol)
{
double temp = vol;
temp /= 1000;
temp = temp*(4096/3.3);
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)temp);
}
main.c
int main(void)
{
uint16_t vol = 0;
uint16_t dac, adc;
uint8_t key;
double v;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组2
delay_init(168); //延时初始化
usart_init(); //串口初始化波特率为115200
LED_Init(); //初始化与LED连接的硬件接口
KEY_Init();
adc_init();
dac1_init();
dac1_set_vol(vol);
while(1)
{
key = KEY_Scan(0);
if(key == WKUP_PRES)
{
if(vol < 3101)vol += 200;
dac1_set_vol(vol);
}
else if(key == KEY1_PRES)
{
if(vol > 200)vol -= 200;
else vol = 0;
dac1_set_vol(vol);
}
if(key == WKUP_PRES || key == KEY1_PRES)
{
printf("\n\r");
dac = DAC_GetDataOutputValue(DAC_Channel_1);
printf("DAC原始数据:%u\r\n", dac);
printf("\n\r");
printf("DAC电压值:%u\r\n", vol);
printf("\n\r");
adc = adc_get_average(ADC_Channel_5, 10);
v = adc;
v = v / 4096 * 3.3;
printf("ADC电压值:%f\r\n", v);
printf("\n\r");
LED0 = !LED0;
}
delay_ms(10);
}
}
实验结果
如图,每按键一次加200mV或减200mV。