stm32 - DAC基本输出方式
DAC简介
数模转换器(DAC)是极为常用的电子器件,可以将数字量转换为以参考量为基准的模拟量,以满足应用需求。
电压输出模式
在stm32
中,D/A
转换器包含以下三种输出方式:
- 输出电压
- 噪声生成
- 三角波生成
本文将着重介绍最基本的电压输出方式。
主要特征
DAC的主要特征有:
- 2个DAC转换器:1个输出通道对应1个转换器
- 8位或者12位单调输出
- 12位模式下数据左对齐或者右对齐
- 同步更新功能
- 噪声波形生成
- 三角波形生成
- 双DAC通道同时或者分别转换
- 每个通道都有DMA功能
- 外部触发转换
- 输入参考电压V_REF+
数据对齐方式
DAC 输出通道的数据对齐方式包含以下三种:
- 8位右对齐
- 12位左对齐
- 12位右对齐
此外,在单 DAC 通道模式下,数据寄存器的存储方式如下:
在双 DAC 通道模式下,数据寄存器的存储方式则为:
我通常会选择12位右对齐方式,并在单通道模式设置数据时与0x0fff
进行"位与"。
DAC转换
用户无法直接对DAC的数据寄存器 DAC_DORx 写入数据,只能通过修改数据保持寄存器 DAC_DHRx 装入数据。
- 未选择"硬件触发"时,保持寄存器 DAC_DHRx 的值将在1个APB1周期后自动传入数据寄存器 DAC_DORx;
- 已选择"硬件触发"时,保持寄存器 DAC_DHRx 的值将在触发发生后3个APB1后传入数据寄存器 DAC_DORx。
- 当数据存入 DAC_DORx 后再经过时间 t_settings(与负载和电源电压有关),输出变为有效。
DAC触发方式
#define DAC_Trigger_None ((uint32_t)0x00000000)
/*!< Conversion is automatic once the DAC1_DHRxxxx register
has been loaded, and not by external trigger */
#define DAC_Trigger_T6_TRGO ((uint32_t)0x00000004)
/*!< TIM6 TRGO selected as external conversion trigger for DAC channel */
#define DAC_Trigger_T8_TRGO ((uint32_t)0x0000000C)
/*!< TIM8 TRGO selected as external conversion trigger for DAC channel
only in High-density devices*/
#define DAC_Trigger_T3_TRGO ((uint32_t)0x0000000C)
/*!< TIM8 TRGO selected as external conversion trigger for DAC channel
only in Connectivity line, Medium-density and Low-density Value Line devices */
#define DAC_Trigger_T7_TRGO ((uint32_t)0x00000014)
/*!< TIM7 TRGO selected as external conversion trigger for DAC channel */
#define DAC_Trigger_T5_TRGO ((uint32_t)0x0000001C)
/*!< TIM5 TRGO selected as external conversion trigger for DAC channel */
#define DAC_Trigger_T15_TRGO ((uint32_t)0x0000001C)
/*!< TIM15 TRGO selected as external conversion trigger for DAC channel
only in Medium-density and Low-density Value Line devices*/
#define DAC_Trigger_T2_TRGO ((uint32_t)0x00000024)
/*!< TIM2 TRGO selected as external conversion trigger for DAC channel */
#define DAC_Trigger_T4_TRGO ((uint32_t)0x0000002C)
/*!< TIM4 TRGO selected as external conversion trigger for DAC channel */
#define DAC_Trigger_Ext_IT9 ((uint32_t)0x00000034)
/*!< EXTI Line9 event selected as external conversion trigger for DAC channel */
#define DAC_Trigger_Software ((uint32_t)0x0000003C)
/*!< Conversion started by software trigger for DAC channel */
触发方式 大致可分为四类:
- DAC_Trigger_None : 无触发;
- DAC_Trigger_Tx_TRGO : 来自片上定时器的TRGO输出
- DAC_Trigger_Ext_IT9 : 来自外部中断线9的上升沿
- DAC_Trigger_Software : 来自软件控制位 SWTRIG
当 DAC 接口检测到来自定时器 TRGO输出 或 EXTI9 的上升沿时,最近存入 DAC_DHRx 中的数据将被传入 DAC_DORx 中。经3个APB1周期后更新 DAC_DORx 的值。对于 "软件触发",需要在程序中对 SWTRIG 置位完成触发,该触发位将被硬件自动清零。
DAC输出电压
DAC输出 = V_reference × DOR /4095;
式中,V_reference 为参考电压,DOR 为 DAC 输出数据寄存器的值(0255/04095)。
DAC 基本输出方式
DAC 参数设置
在stm32f103
中包含2个通道的12位D/A
转换器,PA4
与PA5
作为两个通道输出接口,在使用时需要配置为模拟输入AIN
。当使能 DAC 的输出通道后,相应的 GPIO 管脚将自动与 DAC 的模拟输出接口(DAC_OUTx)相连。
void dacConfig(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitStructure;
/* 开启GPIOA时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
/* 配置DAC输出通道 */
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 开启DAC时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE);
DAC_InitStructure.DAC_Trigger = DAC_Trigger_None; // 无触发
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; // 无波形生成
DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; // 禁用输出缓存
/* 配置DAC参数 */
DAC_Init(DAC_Channel_1,&DAC_InitStructure);
/* enable dac1 */
DAC_Cmd(DAC_Channel_1,ENABLE);
}
设置 DAC 输出电压
经测试,我所用最小系统板的DA参考电压并非3.3v
,而是接近于3.24v
,我们可以通过宏定义配置好参考电压。
#define REFERENCE_VOLTAGE 3.24f // DAC 参考电压
根据公式 data = 4095*(v/v_ref)
可以求得电压v对应的12位数。
void setVoltage(double voltage)
{
uint16_t temp;
if(voltage < 0.0 || voltage > REFERENCE_VOLTAGE)
return;
temp = (uint16_t)(4095*voltage/REFERENCE_VOLTAGE) & 0x0fff;
DAC_SetChannel1Data(DAC_Align_12b_R,temp); // 电压输出:12位右对齐
}
产生正弦波信号
使用宏定义PI
以及采样频率,并添加头文件math.h
。
#include <math.h>
#define PI 3.14159f
#define FSAMPLE 100 // 采样频率 (Hz)
使用sin
函数和一个static
变量即可生成正弦信号。
void createSinWave(double baseAmp, double amp, double frequency, double fSample)
{
static uint32_t time = 0;
double voltage = 0.0;
voltage = amp*sin(2*PI*frequency*time/fSample) + baseAmp;
time++;
setVoltage(voltage);
}
修改main
函数,每隔一个采样周期修改一次DA输出电压,完成正弦信号的输出。
int main(void)
{
dacConfig();
while(1)
{
createSinWave(2,0.5,1,FSAMPLE); // 产生 2±0.5v , 1Hz 的正弦信号
delayMs(1000.0/FSAMPLE);
}
}
查看波形
使用示波器或NI采集卡即可查看生成的正弦信号。
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 litreily的博客!