tag 标签: 内部dac

相关博文
  • 热度 16
    2013-3-12 21:43
    1433 次阅读|
    3 个评论
    第二十四章 DAC 实验         上两章,我们介绍了STM32的ADC使用,本章我们将向大家介绍STM32的DAC功能。在本章中,我们将利用按键(或USMART)控制STM32内部DAC模块的通道1来输出电压,通过ADC1的通道1采集DAC的输出电压,在LCD模块上面显示ADC获取到的电压值以及DAC的设定输出电压值等信息。本章将分为如下几个部分: 24.1 STM32 DAC简介 24.2 硬件设计 24.3 软件设计 24.4 下载验证 24.1 STM32 DAC 简介         大容量的STM32F103具有内部DAC,战舰STM32选择的是STM32F103ZET6属于大容量产品,所以是带有DAC模块的。 STM32的DAC模块(数字/模拟转换模块)是12位数字输入,电压输出型的DAC。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压VREF+以获得更精确的转换结果。 STM32的DAC模块主要特点有: ① 2个DAC转换器:每个转换器对应1个输出通道 ② 8位或者12位单调输出 ③ 12位模式下数据左对齐或者右对齐 ④ 同步更新功能 ⑤ 噪声波形生成 ⑥ 三角波形生成 ⑦ 双DAC通道同时或者分别转换 ⑧ 每个通道都有DMA功能 单个DAC通道的框图如图24.1.1所示:   图24.1.1 DAC通道模块框图 图中VDDA和VSSA为DAC模块模拟部分的供电,而Vref+则是DAC模块的参考电压。DAC_OUTx就是DAC的输出通道了(对应PA4或者PA5引脚)。 从图24.1.1可以看出,DAC输出是受DORx寄存器直接控制的,但是我们不能直接往DORx寄存器写入数据,而是通过DHRx间接的传给DORx寄存器,实现对DAC输出的控制。前面我们提到,STM32的DAC支持8/12位模式,8位模式的时候是固定的右对齐的,而12位模式又可以设置左对齐/右对齐。单DAC通道x,总共有3种情况: ①     8位数据右对齐:用户将数据写入DAC_DHR8Rx 位(实际是存入DHRx 位)。 ②     12位数据左对齐:用户将数据写入DAC_DHR12Lx 位(实际是存入DHRx 位)。 ③     12位数据右对齐:用户将数据写入DAC_DHR12Rx 位(实际是存入DHRx 位)。 我们本章使用的就是单DAC通道1,采用12位右对齐格式,所以采用第③种情况。 如果没有选中硬件触发(寄存器DAC_CR1的TENx位置’0’),存入寄存器DAC_DHRx的数据会在一个APB1时钟周期后自动传至寄存器DAC_DORx。如果选中硬件触发(寄存器DAC_CR1的TENx位置’1’),数据传输在触发发生以后3个APB1时钟周期后完成。 一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间 之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。我们可以从STM32F103ZET6的数据手册查到 的典型值为3us,最大是4us。所以DAC的转换速度最快是250K左右。 本章我们将不使用硬件触发(TEN=0),其转换的时间框图如图24.1.2所示:   图24.1.2 TEN=0时DAC模块转换时间框图 当DAC的参考电压为Vref+的时候,DAC的输出电压是线性的从0~Vref+,12位模式下DAC输出电压与Vref+以及DORx的计算公式如下: DACx输出电压=Vref*(DORx/4095) 接下来,我们介绍一下要实现DAC的通道1输出,需要用到的一些寄存器。首先是DAC控制寄存器DAC_CR,该寄存器的各位描述如图24.1.3所示:   图24.1.3 寄存器DAC_CR各位描述        DAC_CR的低16位用于控制通道1,而高16位用于控制通道2,我们这里仅列出比较重要的最低8位的详细描述,如图24.1.4所示: 图24.1.4 寄存器DAC_CR低八位详细描述        首先,我们来看DAC通道1使能位(EN1),该位用来控制DAC通道1使能的,本章我们就是用的DAC通道1,所以该位设置为1。        再看关闭DAC通道1输出缓存控制位(BOFF1),这里STM32的DAC输出缓存做的有些不好,如果使能的话,虽然输出能力强一点,但是输出没法到0,这是个很严重的问题。所以本章我们不使用输出缓存。即设置该位为1。        DAC通道1触发使能位(TEN1),该位用来控制是否使用触发,里我们不使用触发,所以设置该位为0。        DAC通道1触发选择位(TSEL1 ),这里我们没用到外部触发,所以设置这几个位为0就行了。        DAC通道1噪声/三角波生成使能位(WAVE1 ),这里我们同样没用到波形发生器,故也设置为0即可。        DAC通道1屏蔽/复制选择器(MAMP ),这些位仅在使用了波形发生器的时候有用,本章没有用到波形发生器,故设置为0就可以了。        最后是DAC通道1 DMA使能位(DMAEN1),本章我们没有用到DMA功能,故还是设置为0。        通道2的情况和通道1一模一样,这里就不不细说了。在DAC_CR设置好之后,DAC就可以正常工作了,我们仅需要再设置DAC的数据保持寄存器的值,就可以在DAC输出通道得到你想要的电压了(对应IO口设置为模拟输入)。本章,我们用的是DAC通道1的12位右对齐数据保持寄存器:DAC_DHR12R1,该寄存器各位描述如图24.1.5所示:   图24.1.5 寄存器DAC_DHR12R1各位描述        该寄存器用来设置DAC输出,通过写入12位数据到该寄存器,就可以在DAC输出通道1(PA4)得到我们所要的结果。        通过以上介绍,我们了解了STM32实现DAC输出的相关设置,本章我们将使用DAC模块的通道1来输出模拟电压,其详细设置步骤如下: 1 )开启PA 口时钟,设置PA4 为模拟输入。 STM32F103ZET6的DAC通道1是接在PA4上的,所以,我们先要使能PORTA的时钟,然后设置PA4为模拟输入(虽然是输入,但是STM32内部会连接在DAC模拟输出上)。 2 )使能DAC1 时钟。 同其他外设一样,要想使用,必须先开启相应的时钟。STM32的DAC模块时钟是由APB1提供的,所以我们先要在APB1ENR寄存器里面设置DAC模块的时钟使能。 3 )设置DAC 的工作模式。 该部分设置全部通过DAC_CR设置实现,包括:DAC通道1使能、DAC通道1输出缓存关闭、不使用触发、不使用波形发生器等设置。    4 )设置DAC 的输出值。 通过前面3个步骤的设置,DAC就可以开始工作了,我们使用12位右对齐数据格式,所以我们通过设置DHR12R1,就可以在DAC输出引脚(PA4)得到不同的电压值了。 最后,再提醒一下大家,本例程,我们使用的是3.3V的参考电压,即Vref+连接VDDA。 通过以上几个步骤的设置,我们就能正常的使用STM32的DAC通道1来输出不同的模拟电压了。 24.2 硬件设计 本章用到的硬件资源有: 1)  指示灯DS0 2)  WK_UP和KEY1按键 3)  串口 4)  TFTLCD模块 5)  ADC 6)  DAC 本章,我们使用DAC通道1输出模拟电压,然后通过ADC1的通道1对该输出电压进行读取,并显示在LCD模块上面,DAC的输出电压,我们通过按键(或USMART)进行设置。 我们需要用到ADC采集DAC的输出电压,所以需要在硬件上把他们短接起来。ADC和DAC的连接原理图如图24.2.1所示:   图24.2.1 ADC、DAC与STM32连接原理图        P14是多功能端口,我们只需要通过跳线帽短接P14的ADC和DAC,就可以开始做本章实验了。如图24.2.2所示:   图 24.2.2 硬件连接示意图 24.3 软件设计 找到上一章的工程,首先在HARDWARE文件夹下新建一个DAC的文件夹。然后打开USER文件夹下的工程,新建一个dac.c的文件和dac.h的头文件,保存在DAC文件夹下,并将DAC文件夹加入头文件包含路径。 打开dac.c,输入如下代码: #include "dac.h" //DAC 通道 1 输出初始化 void Dac1_Init(void) {        RCC-APB2ENR|=12;    // 使能 PORTA 时钟                    RCC-APB1ENR|=129;   // 使能 DAC 时钟                  GPIOA-CRL=0XFFF0FFFF;        GPIOA-CRL|=0X00000000;//PA4 模拟输入               DAC-CR|=10;  // 使能 DAC1        DAC-CR|=11;  //DAC1 输出缓存不使能 BOFF1=1        DAC-CR|=02;  // 不使用触发功能 TEN1=0        DAC-CR|=03;  //DAC TIM6 TRGO, 不过要 TEN1=1 才行        DAC-CR|=06;  // 不使用波形发生        DAC-CR|=08;  // 屏蔽、幅值设置        DAC-CR|=012;       //DAC1 DMA 不使能            DAC-DHR12R1=0; } // 设置通道 1 输出电压 //vol:0~3300, 代表 0~3.3V void Dac1_Set_Vol(u16 vol) {        float temp=vol;        temp/=1000;        temp=temp*4096/3.3;        DAC-DHR12R1=temp; } 此部分代码就2个函数,Dac1_Init函数用于初始化DAC通道1。这里基本上是按我们上面的步骤来初始化的,经过这个初始化之后,我们就可以正常使用DAC通道1了。第二个函数Dac1_Set_Vol,用于设置DAC通道1的输出电压,通过USMART调用该函数,就可以随意设置DAC通道1的输出电压了。 保存dac.c代码,并将该代码加入HARDWARE组下。接下来在dac.h文件里面输入如下代码: #ifndef __DAC_H #define __DAC_H   #include "sys.h"          void Dac1_Init(void);           //DAC 通道 1 初始化           void Dac1_Set_Vol(u16 vol); // 设置通道 1 输出电压 #endif 该部分代码很简单,这里我们就不多说了。接下来我们在test.c里面,修改main函数如下: int main(void) {             u16 adcx;        float temp;       u8 t=0;           u16 dacval=0;        u8 key;       Stm32_Clock_Init(9);    // 系统时钟设置        uart_init(72,9600);      // 串口初始化为 9600        delay_init(72);                  // 延时初始化        LED_Init();                 // 初始化与 LED 连接的硬件接口       LCD_Init();                  // 初始化 LCD        usmart_dev.init(72);      // 初始化 USMART                KEY_Init();                  // 按键初始化                      Adc_Init();                   //ADC 初始化        Dac1_Init();                //DAC 通道 1 初始化               POINT_COLOR=RED;// 设置字体为红色        LCD_ShowString(60,50,200,16,16,"WarShip STM32");           LCD_ShowString(60,70,200,16,16,"DAC TEST");             LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK");        LCD_ShowString(60,110,200,16,16,"2012/9/8");              LCD_ShowString(60,130,200,16,16,"WKUP:+  KEY1:-");             // 显示提示信息                                                                                          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");                   DAC-DHR12R1=dacval;// 初始值为 0                                while(1)        {                 ......//省略部分代码                        delay_ms(10);          } } 此部分代码,我们先对需要用到的模块进行初始化,然后显示一些提示信息,本章我们通过WK_UP和KEY1(也就是上下键)来实现对DAC输出的幅值控制。按下WK_UP增加,按KEY1减小。同时在LCD上面显示DHR12R1寄存器的值、DAC设计输出电压以及ADC采集到的DAC输出电压。 本章,我们还可以利用USMART来设置DAC的输出电压值,故需要将Dac1_Set_Vol函数加入USMART控制,方法前面已经有详细的介绍了,大家这里自行添加,或者直接查看我们光盘的源码。 从main函数代码可以看出,按键设置输出电压的时候,每次都是以0.161V递增或递减的,而通过USMART调用Dac1_Set_Vol函数,则可以实现任意电平输出控制(当然得在DAC可控范围内)。 24.4 下载验证 在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32开发板上,可以看到LCD显示如图24.4.1所示: 图 24.4.1 DAC实验测试图 同时伴随DS0的不停闪烁,提示程序在运行。此时,我们通过按WK_UP按键,可以看到输出电压增大,按KEY1则变小。 大家可以试试在USMART调用Dac1_Set_Vol函数,来设置DAC通道1的输出电压,如图24.4.2所示: 图 24.4.2 通过 usmart 设置 DAC 通道 1 的电压输出