打印
[应用相关]

stm32DAC

[复制链接]
802|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhuotuzi|  楼主 | 2016-12-14 17:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
STM32 的 DAC 模块(数字/模拟转换模块)是 12 位数字输入,电压输出型的 DAC。 DAC可以配置为 8 位或 12 位模式,也可以与 DMA 控制器配合使用。 DAC 工作在 12 位模式时,数据可以设置成左对齐或右对齐。 DAC 模块有 2 个输出通道,每个通道都有单独的转换器。在双 DAC 模式下, 2 个通道可以独立地进行转换,也可以同时进行转换并同步地更新 2 个通道的输出。
本节实验,我们将利用按键(或 USMART) 控制 STM32 内部 DAC1来输出电压,通过 ADC1的通道1 采集 DAC的输出电压,在 LCD 模块上面显示 ADC 获取到的电压值以及 DAC 的设定输出电压值等信息。


沙发
zhuotuzi|  楼主 | 2016-12-14 17:37 | 只看该作者
STM32 的 DAC 模块主要特点有:
① 2 个 DAC 转换器:每个转换器对应 1 个输出通道
② 8 位或者 12 位单调输出
③ 12 位模式下数据左对齐或者右对齐
④ 同步更新功能
⑤ 噪声波形生成
⑥ 三角波形生成
⑦ 双 DAC 通道同时或者分别转换
⑧ 每个通道都有 DMA 功能

当 DAC 的参考电压为 Vref+的时候(对 STM32F103RC 来说就是 3.3V), DAC 的输出电压是线性的从 0~Vref+, 12 位模式下 DAC 输出电压与 Vref+以及 DORx 的计算公式如下:
                  DACx 输出电压=Vref*( DORx/4095)

我的ADC和DAC的理解是:

ADC可以采集电压把电压转换为数字,DAC可以把数字转换为电压的形式并输出


使用特权

评论回复
板凳
zhuotuzi|  楼主 | 2016-12-14 17:40 | 只看该作者

配置步骤:

1)开启 PA 口时钟,设置 PA4 为模拟输入。


STM32F103RCT6 的 DAC 通道 1 在 PA4 上,所以,我们先要使能 PORTA 的时钟,然后设置 PA4 为模拟输入。 DAC 本身是输出,但是为什么端口要设置为模拟输入模式呢?因为一但使能 DACx 通道之后,相应的 GPIO 引脚( PA4 或者 PA5)会自动与 DAC 的模拟输出相连,设置为输入,是为了避免额外的干扰。
2)使能 DAC1 时钟。
3) 初始化 DAC,设置 DAC 的工作模式。
4) 使能 DAC 转换通道
5) 设置 DAC 的输出值
-----------------------------------------------------------------------------
typedef struct {
                    u32 DAC_Trigger;  //触发选择   

                    u32 DAC_WaveGeneration;    //波形发生   
                    u32 DAC_LFSRUnmask_TriangleAmplitude; //幅值选择
                    u32 DAC_OutputBuffer;  //输出缓存控制
                 }DAC_InitTypeDef;

-----------------------------------------------------------------------------------
dac.c
#include "dac.h"
void Dac1_Init(void)
{
        GPIO_InitTypeDef GPIO_ist;
        DAC_InitTypeDef DAC_ist;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );//使能 PA 时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能 DAC 时钟
        GPIO_ist.GPIO_Pin=GPIO_Pin_4;
        GPIO_ist.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
        GPIO_ist.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_ist);
        GPIO_SetBits(GPIOA,GPIO_Pin_4);//PA.4 输出高
       
        DAC_ist.DAC_Trigger=DAC_Trigger_None; //不使用触发功能
        DAC_ist.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
        DAC_ist.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;
        DAC_ist.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;//关DAC1输出缓存
        DAC_Init(DAC_Channel_1,&DAC_ist);  //初始化 DAC 通道 1
       
        DAC_Cmd(DAC_Channel_1,ENABLE);//使能 DAC1
        DAC_SetChannel1Data(DAC_Align_12b_R,0);//12位右对齐,设置DAC初始值
}

//设置通道 1 输出电压
//vol:0~3300,代表 0~3.3V
void Dac1_Set_Vol(u16 vol)
{
        float temp=vol;
        temp/=1000;
        temp=temp*4096/3.3;
        DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐设置DAC值
}
u16 Dac1_Get_Vol(void)
{
        return DAC_GetDataOutputValue(DAC_Channel_1);
}
[size=13.3333330154419px]dac.h

#ifndef _DAC_H
#define _DAC_H
#include "sys.h"
void Dac1_Init(void);
u16 Dac1_Get_Vol(void);
void Dac1_Set_Vol(u16 vol);
#endif





使用特权

评论回复
地板
zhuotuzi|  楼主 | 2016-12-14 17:40 | 只看该作者
主函数。。通过按键来调节DAC输出电压的强度,WKUP增强,KEY0减弱(也可以通过USMART组件设置)
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "adc.h"
#include "dac.h"
#include "key.h"
void init()
{
        delay_init();                     //延时函数初始化          
        uart_init(9600);                 //串口初始化为9600
        LED_Init();                                  //初始化与LED连接的硬件接口
        LCD_Init();
        KEY_Init();
        Adc_Init();
        Dac1_Init();
       
        POINT_COLOR=RED;//设置字体为红色
        LCD_ShowString(60,40,200,24,24,"DAC Test ^-^");
        LCD_ShowString(60,70,200,16,16,"Bigggg difficulty");
        LCD_ShowString(60,90,200,16,16,"2015/1/25");
        LCD_ShowString(60,110,200,16,16,"By--Mr yh");
        LCD_ShowString(60,130,200,16,16,"WK_UP:+ KEY0:-");
        //显示提示信息
        POINT_COLOR=BLUE;//设置字体为蓝色
        LCD_ShowString(60,150,200,16,16,"DAC VAL:");
        LCD_ShowString(60,170,200,16,16,"DAC VOL:0.000V");
        LCD_ShowString(60,190,200,16,16,"ADC VOL:0.000V");
        Dac1_Set_Vol(330);
}
int main(void)
{
       
        u16  adcnum=0;
        u16 dacnum=0;
        float tem;
        u8 key,t=0;
        init();
        while(1)
        {
                t++;
                key=KEY_Scan(0);
                if(key==WK_UP_PRES)
                {
                        if(dacnum<4000)dacnum+=200;
                        DAC_SetChannel1Data(DAC_Align_12b_R,dacnum);
                }
                else if(key==KEY0_PRES)
                {
                        if(dacnum>200)dacnum-=200;
                        else dacnum=0;
                        DAC_SetChannel1Data(DAC_Align_12b_R,dacnum);
                }
               
                if(t==10||key==WK_UP_PRES||key==KEY0_PRES)
                {
                        adcnum=Dac1_Get_Vol();dacnum=adcnum;
                        LCD_ShowxNum(124,150,adcnum,4,16,0);//显示DAC寄存器值
                        tem=(float)adcnum*(3.3/4096); //得到DAC电压值
                        adcnum=tem;
                        LCD_ShowxNum(124,170,tem,1,16,0);//显示电压值整数部分
                        tem-=adcnum;tem*=1000;
                        LCD_ShowxNum(140,170,tem,3,16,0X80);//显示电压值的小数部分
                        adcnum=Get_Adc_Average(ADC_Channel_1,10);
                        tem=(float)adcnum*(3.3/4096);
                        adcnum=tem;
                        LCD_ShowxNum(124,190,tem,1,16,0);
                        tem-=adcnum;tem*=1000;
                        LCD_ShowxNum(140,190,tem,3,16,0X80);
                        t=0;
                        LED0=!LED0;
                }
                delay_ms(10);
        }
}


使用特权

评论回复
5
zhuotuzi|  楼主 | 2016-12-14 17:41 | 只看该作者

最后在通过杜邦线将PA1和PA4连起来就好了。。至于为什么要连这两个口 看图

ADC1 和DAC1 分别挂在了 PA1和PA4上,所以我们想要通过ADC1采集DAC1输出的电压,就要将这两点连起来


使用特权

评论回复
6
zhuotuzi|  楼主 | 2016-12-14 17:42 | 只看该作者
(STM32)使用DAC输出WAVE音频波形
本想使用PWM输出音频的,但无论怎么样调试,PWM的音频的频率总不对。后来,改用DAC了。
配置:
芯片:STM32F103VET
DAC:DAC通道2(8位右对齐)、定时器TIM7中断更改DAC值
WAVE数据:以const形式放于芯片上(8kHz采样、8bit、单声道)

弯路:
(1)使用TIM7控制DAC输出,用TRIG方式,通过DMA2通道传送数据到DAC写寄存器 => 没有任何波形输出
(2)以为不需要使用与 DAC通道 一致的定时器作驱动,故使用了 TIM3 。使TIM3工作于8K的工作频率,并允许IT_UPDATE,在TIM3定时器中断中更改DAC的值,不使用DMA2通道 => 有波形信号输出,但频率太高,1秒的音频在约50ms内输出完毕
(3)不使用TIM3,使用与DAC通道2相应的TIM7。将TIM7配置为8K工作频率,允许IT_UPDATE,在TIM7定时器中断中更改DAC的值 ,可正常驱动DAC。估计弯路(2)是由于TIM7的工作频率没有配置,导致DAC频率不正常所致,但未证实
(4)使用步骤(3)的定时器,改用DMA传送数据 => DAC无**常输出音频

例程:
void DACInit(void)
{
        DAC_InitTypeDef   DAC_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
         
        // 1. 配置TIM7
        TIM_DeInit(TIM7);
        /* Time base configuration */
        TIM_TimeBaseStructure.TIM_Period = GetARRValue(8000);        // 重置周期
        TIM_TimeBaseStructure.TIM_Prescaler = 0;                // 分频
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;        // 时钟分割
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;        // 计数模式
        TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
        // 使能TIM7更新中断
        TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);
         
        // 2. 配置DAC
        DAC_DeInit();
        /* DAC channel1 Configuration */
        DAC_InitStructure.DAC_Trigger = DAC_Trigger_None;        //
        DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
        DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bits8_0;
        DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
        // DA通道2初始化
        DAC_Init(DAC_Channel_2, &DAC_InitStructure);
        /* Enable DAC Channel1: Once the DAC channel1 is enabled, PA.04 is
         automatically connected to the DAC converter. */
        DAC_Cmd(DAC_Channel_2, ENABLE);
         
        // 3. 启动TIM7
        TIM_Cmd(TIM7, ENABLE);
}


void TIM7_IRQHandler(void)
{
        INT16U tmpCap;
         
        if (TIM_GetITStatus(TIM7, TIM_IT_Update) != RESET)
        {
                if( wavecount < wave0Length )
                {
                        tmpCap = wave0[wavecount];
                        wavecount++;
                        /* Set DAC Channel1 DHR register */
                        DAC_SetChannel2Data(DAC_Align_8b_R,tmpCap);                        
                }
                else
                {
                        // 完成传输,关闭中断
                        wavecount = 0;
                        TIM_ITConfig(TIM7, TIM_IT_Update, DISABLE);
                        TIM_Cmd(TIM7, DISABLE);
                         // 需要关闭DAC,不然在没有声音的时候会有杂音
                        DAC_Cmd(DAC_Channel_2, DISABLE);
                }
        }

        /* Clear TIM6 update interrupt */
        TIM_ClearITPendingBit(TIM7, TIM_IT_Update);
}
  
// 根据采样率获得定时器自动
// 摘自waveplayer.c
INT16U GetARRValue(INT16U sample)
{
        INT16U arrValue;
        /* 更新OCA值以符合.WAV文件采样率 */
        switch (sample)
        {
        case SAMPLE_RATE_8000 :
            arrValue = (uint16_t)(/8000);
            break; /* 8KHz = 2x36MHz / 9000 */
        case SAMPLE_RATE_11025:
            arrValue = (uint16_t)(/11025);
            break; /* 11.025KHz = 2x36MHz / 6531 */
        case SAMPLE_RATE_16000:
             arrValue = (uint16_t)(/16000);
            break; /* 16KHz = 2x36MHz / 4500 */
        case SAMPLE_RATE_22050:
            arrValue = (uint16_t)(/22050);
            break; /* 22.05KHz = 2x36MHz / 2365 */
        case SAMPLE_RATE_44100:
            arrValue = (uint16_t)(/44100);
            break; /* 44.1KHz = 2x36MHz / 1633 */
        case SAMPLE_RATE_48000:
            arrValue = (uint16_t)(/48000);
            break; /* 48KHz = 2x36MHz / 1500 */
        default:
            arrValue = 0;
            break;
        }
        return arrValue;
}


使用特权

评论回复
7
Soraka| | 2016-12-14 21:33 | 只看该作者
DAC 模块有 2 个输出通道,每个通道都有单独的转换器

使用特权

评论回复
8
zhuotuzi|  楼主 | 2016-12-19 10:15 | 只看该作者
这个配置已经很不错了,好多芯片的DAC只有一路,甚至没有。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

197

主题

3263

帖子

7

粉丝