GD32F103的DAC1采用定时器1触发,DMA传输,将数据转换为电压输出到PA5引脚。
GD32F103的DAC为12位DA转换器,可以将12位的数据转换为电压,从外部引脚上输出;
DAC_OUT0映射到PA4,DAC_OUT1映射到PA5;
DACx引脚上的模拟输出电压:
DACoutput =DAC_DO * Vref+/4096
DAC触发:
DTSELx[2:0]=000,触发源为TIMER5_TRGO,属于内部片上信号;
DTSELx[2:0]=001,互联型产品的触发源为TIMER2_TRGO;非互联型产品的触发源为TIMER7_TRGO,属于内部片上信号;
DTSELx[2:0]=010,触发源为TIMER6_TRGO,属于内部片上信号;
DTSELx[2:0]=011,触发源为TIMER4_TRGO,属于内部片上信号;
DTSELx[2:0]=100,触发源为TIMER1_TRGO,属于内部片上信号;
DTSELx[2:0]=101,触发源为TIMER3_TRGO,属于内部片上信号;
DTSELx[2:0]=110,触发源为EXTI9,属于外部信号触发;
DTSELx[2:0]=111,触发源为SWTRIG,属于软件触发;
DAC数据格式
根据选择的配置模式,数据按照下文所述写入指定的寄存器:
8位数据右对齐:用户须将数据写入寄存器DACx_R8DH [7:0]位
12位数据左对齐:用户须将数据写入寄存器DACx_L12DH[15:4]位
12位数据右对齐:用户须将数据写入寄存器DACx_R12DH[11:0]位
DAC0的DAC_CH0映射到DMA1通道2;
DAC1的DAC_CH1映射到DMA1通道3;
#include "DAC1.h"
#include "stdio.h" //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
/*
GD32F103的DAC为12位DA转换器,可以将12位的数据转换为电压,从外部引脚上输出;
DAC_OUT0映射到PA4,DAC_OUT1映射到PA5;
DACx引脚上的模拟输出电压:
DACoutput =DAC_DO * Vref+/4096
DAC触发:
DTSELx[2:0]=000,触发源为TIMER5_TRGO,属于内部片上信号;
DTSELx[2:0]=001,互联型产品的触发源为TIMER2_TRGO;非互联型产品的触发源为TIMER7_TRGO,属于内部片上信号;
DTSELx[2:0]=010,触发源为TIMER6_TRGO,属于内部片上信号;
DTSELx[2:0]=011,触发源为TIMER4_TRGO,属于内部片上信号;
DTSELx[2:0]=100,触发源为TIMER1_TRGO,属于内部片上信号;
DTSELx[2:0]=101,触发源为TIMER3_TRGO,属于内部片上信号;
DTSELx[2:0]=110,触发源为EXTI9,属于外部信号触发;
DTSELx[2:0]=111,触发源为SWTRIG,属于软件触发;
DAC数据格式
根据选择的配置模式,数据按照下文所述写入指定的寄存器:
8位数据右对齐:用户须将数据写入寄存器DACx_R8DH [7:0]位
12位数据左对齐:用户须将数据写入寄存器DACx_L12DH[15:4]位
12位数据右对齐:用户须将数据写入寄存器DACx_R12DH[11:0]位
DAC0的DAC_CH0映射到DMA1通道2;
DAC1的DAC_CH1映射到DMA1通道3;
*/
#define DAC1_Buff_Size 32
uint16_t DAC1_Buff[DAC1_Buff_Size]=\
{2048,128,256,384,512,640,768,896,\
1024,1152,1280,1408,1536,1664,1792,1920,\
2048,2176,2304,2432,2560,2688,2816,2944,\
3072,3200,3328,3456,3584,3712,3840,3968};
void DAC1_Receive_DMA1_DMA_CH3_config(void);
void DAC1_Init(void);
void Timer1_Initializtion(uint16_t arr,uint16_t psc);
void DAC1_Receive_DMA1_DMA_CH3_config(void)
{
dma_parameter_struct dma_init_struct;
rcu_periph_clock_enable(RCU_DMA1);//使能DMA1时钟
dma_deinit(DMA1,DMA_CH3);//复位DAM1的通道3
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;//DMA传送方向:从内存到外设
dma_init_struct.memory_addr = (uint32_t)(&DAC1_Buff[0]); //源数据首地址为:DAC1_Buff[]
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//源数据块地址递增
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;//源数据块的数据宽度为16位
dma_init_struct.number = DAC1_Buff_Size;//源数据块的数据长度
dma_init_struct.periph_addr = ((uint32_t)(&DAC1_R12DH));//目的数据首地址为:DAC数据寄存器
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//目的数据块地址不递增
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;//目的据块的数据宽度为8位
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;//超高的优先级
dma_init(DMA1,DMA_CH3,&dma_init_struct);//使用dma_init_struct数据结构初始化DMA1通道3
dma_circulation_enable(DMA1,DMA_CH3);//使能"DMA1通道3循环工作模式"
// dma_circulation_disable(DMA1,DMA_CH3);//不使能"DMA1通道3循环工作模式"
dma_memory_to_memory_disable(DMA1,DMA_CH3);//不使能"DMA1通道3内存到内存传输模式"
dma_channel_enable(DMA1,DMA_CH3);
dac_dma_enable(DAC1);
//使能DMA和DAC之间的传输,enable DAC DMA function
//这个必须要
}
void DAC1_Init(void)
{
rcu_periph_clock_enable(RCU_GPIOA);//使能GPIOA时钟
rcu_periph_clock_enable(RCU_DAC); //使能DAC时钟
gpio_init(GPIOA,GPIO_MODE_AIN,GPIO_OSPEED_50MHZ,GPIO_PIN_5);
//将GPIOA5设置为模拟输出口,最大输出速度为50MHz
dac_deinit();//复位DAC
dac_trigger_source_config(DAC1,DAC_TRIGGER_T1_TRGO);
//设置触发源:定时器1触发
dac_trigger_enable(DAC1);//打开DAC1触发功能
// dac_trigger_disable(DAC1);//关闭DAC1触发功能
dac_wave_mode_config(DAC1,DAC_WAVE_DISABLE);//DAC_WAVE_DISABLE表示不使用波形发生器
dac_output_buffer_disable(DAC1);
//不允许"直接将DAC1数据寄存器的值转换为电压输出"
//需要通过触发源触发,才可以输出电压值
// dac_output_buffer_enable(DAC1);
//不用通过触发源触发,直接将DAC1数据寄存器的值转换为电压输出
dac_enable(DAC1);//使能DAC1
DAC1_Receive_DMA1_DMA_CH3_config();
Timer1_Initializtion(50000,6480);//当arr=50000,psc=6480时,则为3000ms,误差为10us;
// Timer1_Initializtion(19,0);//当arr=50000,psc=6480时,则为3000ms,误差为10us;
}
//函数功能:通用定时器1更新事件作为DAC1的触发源
//arr:自动重装值。
//psc:时钟预分频数
//Timer1_Initializtion(50000,6480);//当arr=50000,psc=6480时,则为3000ms,误差为10us;
//Timer1_Initializtion(50000,1080);//当arr=50000,psc=1080时,则为500ms,误差为10us;
void Timer1_Initializtion(uint16_t arr,uint16_t psc)
{
timer_parameter_struct TimerParameterStruct;
rcu_periph_clock_enable(RCU_TIMER1);
nvic_irq_enable(TIMER1_IRQn, 2U, 0U); //设置TIMER1_IRQn的中断优先级,抢占优先级为2,子优先级为0
timer_deinit(TIMER1);//复位TIMER1
TimerParameterStruct.period = arr-1;//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TimerParameterStruct.prescaler = psc-1;//设置用来作为TIMx时钟频率除数的预分频值(APB2时钟分频值)
TimerParameterStruct.clockdivision = TIMER_CKDIV_DIV1;//设置时钟分母值为1
//计算公式:arr*psc/108000000/1,当arr=250,psc=108时,则为0.25ms,误差为1us;
TimerParameterStruct.counterdirection = TIMER_COUNTER_UP;//设置计数方向为"向上计数"
TimerParameterStruct.alignedmode = TIMER_COUNTER_EDGE;//设置为无中央对齐计数模式(边沿对齐模式)
timer_init(TIMER1, &TimerParameterStruct);
timer_master_output_trigger_source_select(TIMER1,TIMER_TRI_OUT_SRC_UPDATE);
//输出的更新事件作为触发器输出,update event as trigger output
timer_update_event_enable(TIMER1);//定时器更新事件使能
timer_counter_value_config(TIMER1,0);//设置TIMERx的计数器初始值为0
//timer_counter_read(timer_periph);//读取TIMERx的计数器值
timer_auto_reload_shadow_enable(TIMER1);//使能TIMERx自动重装载
timer_flag_clear(TIMER1,TIMER_FLAG_UP); //清除"TIMERx更新标志位"
timer_interrupt_flag_clear(TIMER1,TIMER_INT_FLAG_UP); //清除"TIMERx更新中断标志位"
timer_interrupt_enable(TIMER1,TIMER_INT_UP); //使能"TIMERx更新"产生中断
timer_internal_clock_config(TIMER1);//设置"内部时钟"作为定时器时钟
//timer_slave_mode_select(timer_periph,TIMER_SLAVE_MODE_DISABLE);
//设置"关闭从模式",如果TIMER计数器使能,则预分频器直接由内部时钟驱动
timer_enable(TIMER1);//TIMERx计数器使能,开始工作
}
//函数功能:TIMER1更新中断服务程序
void TIMER1_IRQHandler(void)
{
uint16_t d;
if( timer_interrupt_flag_get(TIMER1,TIMER_INT_FLAG_UP) )// 读取更新中断标志位
{
d=dac_output_value_get(DAC1);//读取DAC1的值
printf("\r\nd=%f v",3.3*( (float)d/4096 ));
timer_flag_clear(TIMER1,TIMER_FLAG_UP);//清除"TIMER1更新标志位"
}
timer_interrupt_flag_clear(TIMER1,TIMER_INT_FLAG_UP); //清除"更新中断标志位"
}