STM32-关于DAC的笔记

数模转换器,又称D/A转换器,简称DAC,它是把数字量转变成模拟的器件。D/A转换器基本上由4个部分组成,即权电阻网络、运算放大器、基准电源和模拟开关。模数转换器中一般都要用到数模转换器,模数转换器即A/D转换器,简称ADC,它是把连续的模拟信号转变为离散的数字信号的器件。

-----------------------------------------------------------------------------------------------

接下来介绍DAC的一些分辨率:

1、分辨率:表示模拟电压的最小增量,常用二进制位数表示,比如8、12位;

2、建立时间:表示将一个数字量转换为稳定模拟信号所需的时间;

3、精度:转换器实际特性曲线和理想特性曲线之间的最大误差源:比例系统误差、失调误差、非线性误差,其诱发原因有元件参数误差、基准电压不稳定、运放零飘等。

以STM32F1为例,其DAC输出类型为电压输出型,分辨率为8/12位,DAC时钟频率为36MHz(APB1),建立时间为3us。供电电压如下:Vssa:0V,Vdda:2.4V~3.6V;参考电压Vref-为0V,Vref+为3.3V,DAC输出电压 Vref-<=Vout<=Vref+ 。输出通道DAC_OUT1(PA4),DAC_OUT2(PA5),为了避免寄生电流消耗,PA4和PA5配置为模拟功能,每个通道都有单独的转换器,可同时或单独转换,每个通道都有DMA。

对于8位模式,只能右对齐;对于12位模式,可以左对齐和右对齐,都能实验双DAC通道转换用。

以12位模式下,DAC输出电压计算方式为Vout = (DORx / 2^12 ) * Vref+,DORx为寄存器值,Vref+ = 3.3V。对应得,在8位模式下,DAC输出电压计算方式为Vout = (DORx / 2^8 ) * Vref+。

-----------------------------------------------------------------------------------------------

接下来介绍代码配置方法:

先介绍HAL函数介绍:

1、HAL_DAC_Init():配置DAC工作状态;

2、HAL_DAC_MspInit():存放NVIC,CLOCK,GPIO初始化代码

3、HAL_DAC_ConfigChannel():配置DAC相应通道的相关参数

4、HAL_DAC_Start():启动D/A转换;

5、HAL_DAC_SetValue();设置输出数字量;

6、HAL_DAC_GatValue():读取通道输出数字量。

接下来介绍常用的结构体句柄DAC_HandleTypeDef g_dac_handle:

1.g_dac_handle.Instance:DAC寄存器基地址;

2.g_dac_handle.State:DAC工作状态;

3.g_dac_handle.Lock:DAC锁存对象;

4.g_dac_handle.*DMA_Handle1:通道1的DMA处理句柄指针;

5.g_dac_handle.*DMA_Handle2:通道2的DMA处理句柄指针。

而对于通道参数结构体DAC_ChannelConfTypeDef g_dac_config:

1.g_dac_config.DAC_Trigger:DAC触发源的选择;

2.g_dac_config.DAC_OutputBuffer 启用或禁用DAC通道输出缓存。

-----------------------------------------------------------------------------------------------

实验要求:通过DAC1通道1(PA4)输出预设电压,然后由ADC1通道1(PA1)采集,最后显示ADC的数字转换量及换算后的电压值。然后关闭通道1触发(TEN1位置0),关闭输出缓冲(BOFF1位置1),使用12位右对齐模式,将数字量写入DAC_DHR12R1寄存器。

接下来编写函数代码:

首先编写函数文件dac.c:

#include "./BSP/DAC/dac.h"

DAC_HandleTypeDef g_dac_handle;

void dac_init(void){

    DAC_ChannelConfTypeDef dac_ch_conf;

    g_dac_handle.Instance = DAC1; //寄存器基地址
    HAL_DAC_Init(&g_dac_handle);

    dac_ch_conf.Trigger = DAC_TRIGGER_NONE; //触发源选择,选择自动触发
    dac_ch_conf.OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
    HAL_DAC_ConfigChannel(&g_dac_handle, &dac_ch_conf, DAC_CHANNEL_1);

    HAL_DAC_Start(&g_dac_handle, DAC_CHANNEL_1);
}

void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac){

    if(hdac->Instance == DAC1){
        GPIO_InitTypeDef gpio_init_struct;
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_DAC_CLK_ENABLE();

        gpio_init_struct.Pin = GPIO_PIN_4;
        gpio_init_strcut.Mode = GPIO_MODE_ANALOG;
        HAL_GPIO_Init(GPIOA, &gpio_init_struct);
    }
}

void dac_set_voltage(uint16_t vol){

    double temp = vol;
    temp /= 1000;
    temp = temp * 4096 / 3.3;

    if(temp > 4095){
        temp = 4095;
    }

    HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, temp);
}

接下来编写函数文件头文件dac.h:

#ifndef __DAC_H
#define __DAC_H

void dac_init(void);
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac);
void dac_set_voltage(uint16_t vol);

#endif

接下来编写主函数文件main.c:

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/DAC/dac.h"
#include "./BSP/ADC/adc3.h"

extern DAC_HandleTypeDef g_dac_handle;

int main(void)
{
    uint16_t adcx;
    float temp;
    uint8_t t = 0;
    uint16_t dacval = 0;
    uint8_t key;

    HAL_Init();                                 /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9);         /* 设置时钟, 72Mhz */
    delay_init(72);                             /* 延时初始化 */
    usart_init(115200);                         /* 串口初始化为115200 */
    usmart_dev.init(72);                        /* 初始化USMART */
    led_init();                                 /* 初始化LED */
    lcd_init();                                 /* 初始化LCD */
    key_init();                                 /* 初始化按键 */
    adc3_init();                                /* 初始化ADC3 */
    dac_init(1);                                /* 初始化DAC1_OUT1通道 */

    lcd_show_string(30,  50, 200, 16, 16, "STM32F103", RED);
    lcd_show_string(30,  70, 200, 16, 16, "DAC TEST", RED);
    lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "WK_UP:+  KEY1:-", RED);
    
    lcd_show_string(30, 130, 200, 16, 16, "DAC VAL:", BLUE);
    lcd_show_string(30, 150, 200, 16, 16, "DAC VOL:0.000V", BLUE);
    lcd_show_string(30, 170, 200, 16, 16, "ADC VOL:0.000V", BLUE);

    while (1)
    {
        t++;
        key = key_scan(0);          /* 按键扫描 */

        if (key == WKUP_PRES)
        {
            if (dacval < 4000)dacval += 200;

            HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dacval);/* 输出增大200 */
        }
        else if (key == KEY1_PRES)
        {
            if (dacval > 200)dacval -= 200;
            else dacval = 0;

            HAL_DAC_SetValue(&g_dac_handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dacval); /* 输出减少200 */
        }

        if (t == 10 || key == KEY1_PRES || key == WKUP_PRES)        /* WKUP/KEY1按下了,或者定时时间到了 */
        {
            adcx = HAL_DAC_GetValue(&g_dac_handle, DAC_CHANNEL_1);  /* 读取前面设置DAC1_OUT1的值 */
            lcd_show_xnum(94, 130, adcx, 4, 16, 0, BLUE);           /* 显示DAC寄存器值 */
            
            temp = (float)adcx * (3.3 / 4096);                      /* 得到DAC电压值 */
            adcx = temp;
            lcd_show_xnum(94, 150, temp, 1, 16, 0, BLUE);           /* 显示电压值整数部分 */
            
            temp -= adcx;
            temp *= 1000;
            lcd_show_xnum(110, 150, temp, 3, 16, 0X80, BLUE);       /* 显示电压值的小数部分 */
            
            adcx = adc3_get_result_average(ADC3_CHY, 20);           /* 得到ADC3通道1的转换结果 */
            temp = (float)adcx * (3.3 / 4096);                      /* 得到ADC电压值(adc是16bit的) */
            adcx = temp;
            lcd_show_xnum(94, 170, temp, 1, 16, 0, BLUE);           /* 显示电压值整数部分 */
                
            temp -= adcx;
            temp *= 1000;
            lcd_show_xnum(110, 170, temp, 3, 16, 0X80, BLUE);       /* 显示电压值的小数部分 */
            
            LED0_TOGGLE();  /* LED0闪烁 */
            t = 0;
        }

        delay_ms(10);
    }
}

到这里我们的实验代码便写完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值