STM32F407ZG 数模转换器DAC

数字/模拟转换器 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

CR
高16位控制 DAC2 ,低16位控制 DAC1。
滤波和 DMA 之后再了解,先关注各使能位和触发源选择,即低8位。
CR
CR

软件触发寄存器 SWTRIGR

比较直接,就是控制两个 DAC 是否允许软件触发。
SWTRIGR

数据保持寄存器 DHR

此寄存器在选择不同模式和对齐方式下,数据存入的位置也不一致,具体如图。为了满足硬件转移数据,每个模式对应一个寄存器,其中单通道还分 DAC1 和 DAC2 。因此,STM32中 DHR 寄存器总共应该有9个之多。
DHR单通道
DHR双通道

数据输出寄存器 DOR

含两个32位寄存器,分别保存 DAC1 和 DAC2 的数据输出。都只有低12位有效且只读,高位必须保持复位。

状态寄存器 SR

SR

实验

STM32 自带 DAC 实验

配置 DAC1 输出模拟信号,并通过 ADC1 的通道5接收转换,用串口显示。

配置步骤

原理图
选用 PA4 和 PA5 短接。

  1. 使能 GPIOA 和 DAC 的时钟。
  2. 创建 GPIO_InitTypeDef 初始化 PA4 的 DAC 输出。
  3. 创建 DAC_InitTypeDef 初始化 DAC 。
  4. 使能 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。
结果

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值