实验目的
通过本实验学习STM32的DAC数模转换器的使用,利用DAC输出电压,再用ADC采集,通过串口打印出来,数据手册请参看第12章。
实验简介
DAC数模转换器的作用就是将数字输入转换成模拟信号输出,比如音频播放就是通过DAC 将数字信号转换成模拟信号实现的。
STM32的DAC模块是12位数字输入,电压输出的数字/模拟转换器。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压VREF+
以获得更精准的转换结果。
STM32的DAC模块主要特点有
- 2个DAC转换器:每个转换器对应1个输出通道。
- 8位或12位单调输出
- 12位模式下数据左对齐或右对齐
- 同步更新功能
- 噪声波形形成
- 三角波形形成
- 双DAC通道同时或者分别转换
电路设计
用跳帽就将DAC输出引脚PA4连接到ADC1的采集引脚PA6,将DAC生成的电压通过ADC再采集回来,通过串口打印出来。
代码
main.c
#include "MyIncludes.h"
char buff[100];
uint16_t DAC_Vol = 1500;
uint16_t Vol;
u16 sys_cnt = 0;
void systick_isr(void)
{
if(sys_cnt < 1000)
{
sys_cnt++;
}
else
{
sys_cnt = 0;
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_4|GPIO_PIN_5);
}
}
int main()
{
System_Init();
LED_Init();
SysTick_Init(systick_isr);
Key_Init();
USART1_Init(115200,NULL,NULL);
STM32_ADC_Init(ADC1,ADC_CHANNEL_6,NULL);
Stm32DAC_Init();
DAC_SetVoltage(DAC_Vol);
delay_ms(100);
sprintf(buff,"Expected Voltage: %d.%d%dV, ",DAC_Vol/1000,DAC_Vol%1000/100,DAC_Vol%100/10);
printf(buff);
Vol = Vol_Sample();
sprintf(buff,"ADC VOL: %d.%d%dV\r\n",Vol/1000,Vol%1000/100,Vol%100/10);
printf(buff);
while(1)
{
Key_Read();
if(Key_Info.Num_Last != Key_Info.Num)
{
Key_Info.Num_Last = Key_Info.Num;
if(Key_Info.Num != 0)
{
switch(Key_Info.Num)
{
case KEY_ONE:
if( DAC_Vol <3200 )
DAC_Vol += 100;
break;
case KEY_TWO:
if(DAC_Vol > 100)
DAC_Vol -=100;
break;
default:break;
}
DAC_SetVoltage(DAC_Vol);
sprintf(buff,"Expected Voltage: %d.%d%dV, ",DAC_Vol/1000,DAC_Vol%1000/100,DAC_Vol%100/10);
printf(buff);
Vol = Vol_Sample();
sprintf(buff,"ADC VOL: %d.%d%dV\r\n",Vol/1000,Vol%1000/100,Vol%100/10);
printf(buff);
}
}
}
}
dac.h
#ifndef __DAC_H_
#define __DAC_H_
#include "stm32f1xx.h"
#include "stm32_types.h"
#include "stm32f1xx_hal.h"
//#define DAC_USE_DMA
//DAC使用DMA,打开此定义
#define DACx_CHANNEL_PIN GPIO_PIN_4
//DAC输出引脚
#define DACx_CHANNEL DAC_CHANNEL_1
//DAC转换通道
//DAC2
//#define DACx_CHANNEL_PIN GPIO_PIN_5
//DAC输出引脚
//#define DACx_CHANNEL DAH_CHANNEL_2
//DAC转换通道PA5
#define DACx_DMA_INSTANCE DMA2_Channe13
#define DACx_DMA_IRQn DMA_Channe13_IRQn
#define DACx_DMA_IRQHandler DMA2_Channel13_IRQHandler
void Stm32DAC_Init(void);
//DA转化器初始化
void DAC_SetVal(uint32_t Data);
//设置DAC值
void DAC_SetVoltage(uint32_t vol);
//DAC转换生成电压(0-3.3V)
//vol:0~3300,电压放大1000倍
void DAC_TriangleInit(void);
//三角波生成初始化
void DAC_NoiseWaveConfig(void);
//噪声波生成
void DAC_EscalatorConfig(uint32_t *data,uint32_t len);
//
void DAC_DMA_Init(void);
void DAC_DMA_Start(uint32_t* pData,uint32_t Length);
void DAC_DMA_Stop(void);
void DAC_TriangleInit(void);
void DAC_NoiseWaveInit(void);
#endif
dac.c
#include "dac.h"
DAC_HandleTypeDef DacHandle;
//DAC句柄结构变量声明
static DAC_ChannelConfTypeDef sConfig;
//DAC配置常规通道结构变量声明
void Stm32DAC_Init(void)
//DA转化器初始化
{
GPIO_InitTypeDef GPIO_InitStruct;
//GIPIO初始化结构变量声明
__HAL_RCC_GPIOA_CLK_ENABLE();
//使能DAC输出端口时钟
__DAC_CLK_ENABLE();
//使能DAC时钟
//PA4配置为DAC输出
GPIO_InitStruct.Pin = DACx_CHANNEL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
//模拟模式
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//DAC转换器配置
DacHandle.Instance = DAC;
HAL_DAC_Init(&DacHandle);
//DAC通道配置
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
//不使用通道触发器
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
//DAC输出缓冲器禁止
HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL);
//配置选定DAC通道
HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0x00);
//12位右对齐,初始值为0
HAL_DAC_Start(&DacHandle, DACx_CHANNEL);
//启动DAC
}
//启动DAC值
void DAC_SetVal(uint32_t Data)
{
HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, Data);
}
//DAC转换生成电压(0~3.3V)
//vol:0~3300,电压放大1000倍
void DAC_SetVoltage(uint32_t vol)
{
uint32_t val;
val = vol * 4096 / 3300;
DAC_SetVal(val);
}
//三角波生成
void DAC_TriangleConfig(void)
{
//DAC转换器配置
DacHandle.Instance = DAC;
HAL_DAC_Init(&DacHandle);
//DAC通道配置
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
//定时器6触发
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
//DAC输出缓冲器使能
HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL);
//配置选定DAC通道
HAL_DACEx_TriangleWaveGenerate(&DacHandle, DACx_CHANNEL, DAC_TRIANGLEAMPLITUDE_1023);
//配置三角波生成,最大转换值1023
HAL_DAC_Start(&DacHandle, DACx_CHANNEL);
//启动DAC
HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0x100);
//12位右对齐,初始值为0x100
}
void DAC_NoiseWaveConfig(void)
//噪声波生成
{
//DAC转换器配置
DacHandle.Instance = DAC;
HAL_DAC_Init(&DacHandle);
//DAC通道配置
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
//定时器6触发
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
//DAC输出缓冲器使能
HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL);
//DAC通道配置
HAL_DACEx_NoiseWaveGenerate(&DacHandle, DACx_CHANNEL, DAC_TRIANGLEAMPLITUDE_1023);
//配置噪声波生成,最大转换值1023
HAL_DAC_Start(&DacHandle, DACx_CHANNEL);
//启动DAC
HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL, DAC_ALIGN_12B_R, 0x100);
//12位右对齐,初始值为0x100
}
void DAC_EscalatorConfig(uint32_t *data, uint32_t len)
//自定义波形生成,需要开启DMA
{
//DAC转换器配置
DacHandle.Instance = DAC;
HAL_DAC_Init(&DacHandle);
//DAC通道配置
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
//定时器6触发
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
//DAC输出缓冲器使能
HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL);
//DAC通道配置
HAL_DAC_Start_DMA(&DacHandle, DACx_CHANNEL, (uint32_t *)data, len, DAC_ALIGN_8B_R);
//启动DMA
}
void TIM6_Config(uint32_t Period)
//定时器6配置,用于触发DAC转换
{
static TIM_HandleTypeDef htim;
//TIM句柄结构变量声明
TIM_MasterConfigTypeDef sMasterConfig;
//主配置结构变量声明
uint32_t uwPrescalerValue = 0;
uwPrescalerValue = (uint32_t) ((SystemCoreClock) / 1000000) - 1;
//1us计数的分频系统
__HAL_RCC_TIM6_CLK_ENABLE();
//开启定时钟
htim.Instance = TIM6;
//配置定时器6
htim.Init.Period = Period;
//自动重装值
htim.Init.Prescaler = uwPrescalerValue;
//设置计数频率为0.1ms计一次数
htim.Init.ClockDivision = 0;
//时钟不分频,来自RCC
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
//递增计数
htim.Init.RepetitionCounter = 0;
//指定重复计数值
HAL_TIM_Base_Init(&htim);
//初始化定时器参数
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
//从模式禁止
HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig);
//在主模式下配置TIME。
//启动定时器
HAL_TIM_Base_Start(&htim);
}
void DAC_ConvertFreqConfig(uint32_t Freq)
//DAC转换频率设置,利用定时器触发
//DAC转换频率,即多久转换一次,但位HZ
{
TIM6_Config(1000000/Freq - 1);
}
//在HAL_DAC_Init中调用
void HAL_DAC_MspInit(DAC_HandleTypeDef *hdac)
{
GPIO_InitTypeDef GPIO_InitStruct;
//GPIO句柄结构变量声明
static DMA_HandleTypeDef hdma_dac1;
//DMA基础结构变量声明
__HAL_RCC_GPIOA_CLK_ENABLE();
//使能DAC输出端口时钟
__DAC_CLK_ENABLE();
//使能DAC时钟
//PA4配置为DAC输出
GPIO_InitStruct.Pin = DACx_CHANNEL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
#ifdef DAC_USE_DMA
//配置DMA1
//使能DMA时钟
__HAL_RCC_DMA1_CLK_ENABLE();
hdma_dac1.Instance = DACx_DMA_INSTANCE;
hdma_dac1.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_dac1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dac1.Init.MemInc = DMA_MINC_ENABLE;
hdma_dac1.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
//DAC播放音频可以字节传输,也可以半字传输
hdma_dac1.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
// hdma_dac1.Init.PeriphDataAlignment = DMA_MDATAALIGN_HALFWORD;
// hdma_dac1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
// hdma_dac1.Init.Mode = DMA_CIRCULAR;
hdma_dac1.Init.Mode = DMA_NORMAL;
hdma_dac1.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_dac1);
//初始化DMA句柄为DAC
__HAL_LINKDMA(hdac, DMA_Handle1, hdma_dac1);
//配置NVIC
HAL_NVIC_SetPriority(DACx_DMA_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(DACx_DMA_IRQn);
#endif
}
void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef* hdac)
//DAC通道1 DMA数据流一半转换完成回调,在DAC_DMAHalfConvCpltCh1中调用
{
}
void HAL_DAC_ErrorCallbackCh1(DAC_HandleTypeDef *hdac)
//DAC通道1 DMA转换错误回调,在DAC_DMAErrorCh1中调用
{
}
void DAC_DMA_Init(void)
{
//DAC转换器配置
DacHandle.Instance = DAC;
HAL_DAC_Init(&DacHandle);
//DAC通道配置
//语音播放需要修改定时器6的触发频率和音频文件
sConfig.DAC_Trigger = DAC_TRIGGER_T6_TRGO;
//定时器6触发
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
//DAC输出缓冲器
HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL);
//DAC通道配置
}
//DMA中断
void DACx_DMA_IRQHandler(void)
{
HAL_DMA_IRQHandler(DacHandle.DMA_Handle1);
}
void DAC_DMA_Start(uint32_t* pData, uint32_t Length)
//DAC DMA功能启动,播放音频要注意,采用8位对齐或12位左对齐
{
HAL_DAC_Start_DMA(&DacHandle,DACx_CHANNEL, pData, Length, DAC_ALIGN_8B_R);
}
void DAC_DMA_Stop(void)
//DAC DMA功能禁止
{
HAL_DAC_Stop_DMA(&DacHandle,DACx_CHANNEL);
//终止DMA传输,DAC
}
void DAC_TriangleInit(void)
//三角波生成初始化
{
DAC_ConvertFreqConfig(1000);
//数据转换频率1KHz
DAC_TriangleConfig();
}
void DAC_NoiseWaveInit(void)
//噪声波生成初始化
{
DAC_ConvertFreqConfig(1000);
//数据转换频率1KHz
DAC_NoiseWaveConfig();
}